Added yt-dlp as new default
This commit is contained in:
parent
06073297ef
commit
afebe528cb
2 changed files with 48 additions and 5 deletions
|
@ -22,6 +22,7 @@ mutagen = "^1.46.0"
|
||||||
aiocmd = "^0.1.5"
|
aiocmd = "^0.1.5"
|
||||||
pyqrcode = "^1.2.1"
|
pyqrcode = "^1.2.1"
|
||||||
pillow = "^9.3.0"
|
pillow = "^9.3.0"
|
||||||
|
yt-dlp = "^2022.11.11"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core"]
|
requires = ["poetry-core"]
|
||||||
|
@ -40,6 +41,7 @@ module = [
|
||||||
"pyqrcode",
|
"pyqrcode",
|
||||||
"socketio",
|
"socketio",
|
||||||
"pillow",
|
"pillow",
|
||||||
"PIL"
|
"PIL",
|
||||||
|
"yt_dlp",
|
||||||
]
|
]
|
||||||
ignore_missing_imports = true
|
ignore_missing_imports = true
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
"""
|
"""
|
||||||
Construct the YouTube source.
|
Construct the YouTube source.
|
||||||
|
|
||||||
|
If available, downloading will be performed via yt-dlp, if not, pytube will be used.
|
||||||
|
|
||||||
Adds it to the ``available_sources`` with the name ``youtube``.
|
Adds it to the ``available_sources`` with the name ``youtube``.
|
||||||
"""
|
"""
|
||||||
import asyncio
|
import asyncio
|
||||||
|
@ -17,6 +19,13 @@ from pytube import Stream
|
||||||
from pytube import StreamQuery
|
from pytube import StreamQuery
|
||||||
from pytube import YouTube
|
from pytube import YouTube
|
||||||
|
|
||||||
|
try:
|
||||||
|
from yt_dlp import YoutubeDL
|
||||||
|
|
||||||
|
USE_YT_DLP = True
|
||||||
|
except ImportError:
|
||||||
|
USE_YT_DLP = False
|
||||||
|
|
||||||
from ..entry import Entry
|
from ..entry import Entry
|
||||||
from ..result import Result
|
from ..result import Result
|
||||||
from .source import available_sources
|
from .source import available_sources
|
||||||
|
@ -36,7 +45,7 @@ class YoutubeSource(Source):
|
||||||
downloaded/streamed. Default is 720.
|
downloaded/streamed. Default is 720.
|
||||||
- ``start_streaming``: If set to ``True``, the client starts streaming
|
- ``start_streaming``: If set to ``True``, the client starts streaming
|
||||||
the video, if buffering was not completed. Needs ``youtube-dl`` or
|
the video, if buffering was not completed. Needs ``youtube-dl`` or
|
||||||
``yt-dlp``.
|
``yt-dlp``. Default is False.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, config: dict[str, Any]):
|
def __init__(self, config: dict[str, Any]):
|
||||||
|
@ -51,6 +60,18 @@ class YoutubeSource(Source):
|
||||||
self.start_streaming: bool = (
|
self.start_streaming: bool = (
|
||||||
config["start_streaming"] if "start_streaming" in config else False
|
config["start_streaming"] if "start_streaming" in config else False
|
||||||
)
|
)
|
||||||
|
self.formatstring = (
|
||||||
|
f"bestvideo[height<={self.max_res}]+"
|
||||||
|
f"bestaudio/best[height<={self.max_res}]"
|
||||||
|
)
|
||||||
|
if USE_YT_DLP:
|
||||||
|
self._yt_dlp = YoutubeDL(
|
||||||
|
params={
|
||||||
|
"paths": {"home": self.tmp_dir},
|
||||||
|
"format": self.formatstring,
|
||||||
|
"quiet": True,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
async def get_config(self) -> dict[str, Any] | list[dict[str, Any]]:
|
async def get_config(self) -> dict[str, Any] | list[dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
|
@ -75,14 +96,12 @@ class YoutubeSource(Source):
|
||||||
:rtype: None
|
:rtype: None
|
||||||
"""
|
"""
|
||||||
if self.start_streaming and not self.downloaded_files[entry.ident].complete:
|
if self.start_streaming and not self.downloaded_files[entry.ident].complete:
|
||||||
print("streaming")
|
|
||||||
self.player = await self.play_mpv(
|
self.player = await self.play_mpv(
|
||||||
entry.ident,
|
entry.ident,
|
||||||
None,
|
None,
|
||||||
"--script-opts=ytdl_hook-ytdl_path=yt-dlp,"
|
"--script-opts=ytdl_hook-ytdl_path=yt-dlp,"
|
||||||
"ytdl_hook-exclude='%.pls$'",
|
"ytdl_hook-exclude='%.pls$'",
|
||||||
f"--ytdl-format=bestvideo[height<={self.max_res}]"
|
f"--ytdl-format={self.formatstring}",
|
||||||
f"+bestaudio/best[height<={self.max_res}]",
|
|
||||||
"--fullscreen",
|
"--fullscreen",
|
||||||
)
|
)
|
||||||
await self.player.wait()
|
await self.player.wait()
|
||||||
|
@ -236,6 +255,23 @@ class YoutubeSource(Source):
|
||||||
pass
|
pass
|
||||||
return list_of_videos
|
return list_of_videos
|
||||||
|
|
||||||
|
async def _buffer_with_yt_dlp(self, entry: Entry) -> Tuple[str, Optional[str]]:
|
||||||
|
"""
|
||||||
|
Download the video using yt-dlp.
|
||||||
|
|
||||||
|
Yt-dlp automatically merges the audio and video, so only the video
|
||||||
|
location exists, the return value for the audio part will always be
|
||||||
|
``None``.
|
||||||
|
|
||||||
|
:param entry: The entry to download.
|
||||||
|
:type entry: Entry
|
||||||
|
:return: The location of the video file and ```None```
|
||||||
|
:rtype: Tuple[str, Optional[str]]
|
||||||
|
"""
|
||||||
|
info = await asyncio.to_thread(self._yt_dlp.extract_info, entry.ident)
|
||||||
|
combined_path = info["requested_downloads"][0]["filepath"]
|
||||||
|
return combined_path, None
|
||||||
|
|
||||||
async def do_buffer(self, entry: Entry) -> Tuple[str, Optional[str]]:
|
async def do_buffer(self, entry: Entry) -> Tuple[str, Optional[str]]:
|
||||||
"""
|
"""
|
||||||
Download the video.
|
Download the video.
|
||||||
|
@ -245,6 +281,8 @@ class YoutubeSource(Source):
|
||||||
the video and audio seperatly. If that is the case, both will be
|
the video and audio seperatly. If that is the case, both will be
|
||||||
downloaded.
|
downloaded.
|
||||||
|
|
||||||
|
If yt-dlp is installed it will be used, otherwise pytube will be used.
|
||||||
|
|
||||||
|
|
||||||
:param entry: The entry to download.
|
:param entry: The entry to download.
|
||||||
:type entry: Entry
|
:type entry: Entry
|
||||||
|
@ -252,6 +290,9 @@ class YoutubeSource(Source):
|
||||||
location of the audio file.
|
location of the audio file.
|
||||||
:rtype: Tuple[str, Optional[str]]
|
:rtype: Tuple[str, Optional[str]]
|
||||||
"""
|
"""
|
||||||
|
if USE_YT_DLP:
|
||||||
|
return await self._buffer_with_yt_dlp(entry)
|
||||||
|
|
||||||
yt_song: YouTube = YouTube(entry.ident)
|
yt_song: YouTube = YouTube(entry.ident)
|
||||||
|
|
||||||
streams: StreamQuery = await asyncio.to_thread(lambda: yt_song.streams)
|
streams: StreamQuery = await asyncio.to_thread(lambda: yt_song.streams)
|
||||||
|
|
Loading…
Add table
Reference in a new issue