From 44d4ae2a966c2f89daf3893fcfb2fa3e9ba6f6b1 Mon Sep 17 00:00:00 2001 From: Fabio Manganiello Date: Sat, 4 Nov 2023 11:57:09 +0100 Subject: [PATCH] [`media`] Made the `youtube-dl` executable configurable. `youtube-dl` is mostly dead and there are several forks available, thus we need to give the user the ability to pick which `youtube-dl` executable fork they want to use. Among these, `yt-dlp` is probably the most maintained today and it's also included in many default repos, so it's been added as an extra requirement for all the media plugins. Closes: #268 --- platypush/plugins/media/__init__.py | 49 +++++++++++-------- platypush/plugins/media/mplayer/manifest.yaml | 4 ++ platypush/plugins/media/mpv/manifest.yaml | 5 ++ .../plugins/media/omxplayer/manifest.yaml | 2 + platypush/plugins/media/vlc/manifest.yaml | 5 ++ platypush/plugins/youtube/manifest.yaml | 24 ++------- setup.py | 2 +- 7 files changed, 50 insertions(+), 41 deletions(-) diff --git a/platypush/plugins/media/__init__.py b/platypush/plugins/media/__init__.py index 794cbaf89..b9ca020bc 100644 --- a/platypush/plugins/media/__init__.py +++ b/platypush/plugins/media/__init__.py @@ -14,6 +14,7 @@ import requests from platypush.config import Config from platypush.context import get_plugin, get_backend from platypush.plugins import Plugin, action +from platypush.utils import get_default_downloads_dir class PlayerState(enum.Enum): @@ -147,7 +148,9 @@ class MediaPlugin(Plugin, ABC): env: Optional[Dict[str, str]] = None, volume: Optional[Union[float, int]] = None, torrent_plugin: str = 'torrent', - youtube_format: str = 'best', + # youtube_format: Optional[str] = 'bv*[height<=?1080][ext=mp4]+bestaudio/best', + youtube_format: Optional[str] = 'best[height<=?1080][ext=mp4]', + youtube_dl: str = 'yt-dlp', **kwargs, ): """ @@ -169,10 +172,17 @@ class MediaPlugin(Plugin, ABC): - ``webtorrent`` - torrent support over webtorrent (unstable) :param youtube_format: Select the preferred video/audio format for - YouTube videos (default: ``best``). See the `youtube-dl - documentation + YouTube videos. See the `youtube-dl documentation `_ for more - info on supported formats. + info on supported formats. Default: + ``bv*[height<=?1080][ext=mp4]+bestaudio/best`` - select the best + mp4 video with a resolution <= 1080p, and the best audio format. + + :param youtube_dl: Path to the ``youtube-dl`` executable, used to + extract information from YouTube videos and other media platforms. + Default: ``yt-dlp``. The default has changed from ``youtube-dl`` to + the ``yt-dlp`` fork because the former is badly maintained and its + latest release was pushed in 2021. """ super().__init__(**kwargs) @@ -216,16 +226,12 @@ class MediaPlugin(Plugin, ABC): os.path.expanduser( download_dir or player_config.get('download_dir') - or os.path.join( - (os.path.expanduser('~') or self._env.get('HOME') or '/'), - 'Downloads', - ) + or get_default_downloads_dir() ) ) - if not os.path.isdir(self.download_dir): - os.makedirs(self.download_dir, exist_ok=True) - + os.makedirs(self.download_dir, exist_ok=True) + self._ytdl = youtube_dl self.media_dirs.add(self.download_dir) self.volume = volume self._videos_queue = [] @@ -468,7 +474,7 @@ class MediaPlugin(Plugin, ABC): self.logger.exception(e) results = [ - {'type': media_type, **result} + {**result, 'type': media_type} for media_type in self._supported_media_types for result in results.get(media_type, []) if media_type in results @@ -580,17 +586,20 @@ class MediaPlugin(Plugin, ABC): def get_youtube_video_url(self, url, youtube_format: Optional[str] = None): ytdl_cmd = [ - 'youtube-dl', - '-f', - youtube_format or self.youtube_format, + self._ytdl, + *( + ['-f', youtube_format or self.youtube_format] + if youtube_format or self.youtube_format + else [] + ), '-g', url, ] self.logger.info('Executing command %s', ' '.join(ytdl_cmd)) - with subprocess.Popen(ytdl_cmd, stdout=subprocess.PIPE) as youtube_dl: - url = youtube_dl.communicate()[0].decode().strip() - youtube_dl.wait() + with subprocess.Popen(ytdl_cmd, stdout=subprocess.PIPE) as ytdl: + url = ytdl.communicate()[0].decode().strip() + ytdl.wait() return url @@ -628,9 +637,7 @@ class MediaPlugin(Plugin, ABC): if m: url = f'https://www.youtube.com/watch?v={m.group(1)}' - with subprocess.Popen( - ['youtube-dl', '-j', url], stdout=subprocess.PIPE - ) as proc: + with subprocess.Popen([self._ytdl, '-j', url], stdout=subprocess.PIPE) as proc: if proc.stdout is None: return None diff --git a/platypush/plugins/media/mplayer/manifest.yaml b/platypush/plugins/media/mplayer/manifest.yaml index b700ece2c..55da33096 100644 --- a/platypush/plugins/media/mplayer/manifest.yaml +++ b/platypush/plugins/media/mplayer/manifest.yaml @@ -3,11 +3,15 @@ manifest: install: apk: - mplayer + - yt-dlp apt: - mplayer + - yt-dlp dnf: - mplayer + - yt-dlp pacman: - mplayer + - yt-dlp package: platypush.plugins.media.mplayer type: plugin diff --git a/platypush/plugins/media/mpv/manifest.yaml b/platypush/plugins/media/mpv/manifest.yaml index 4fa6b91aa..ae586245e 100644 --- a/platypush/plugins/media/mpv/manifest.yaml +++ b/platypush/plugins/media/mpv/manifest.yaml @@ -4,15 +4,20 @@ manifest: apk: - mpv - py3-mpv + - yt-dlp apt: - mpv - python3-mpv + - yt-dlp dnf: - mpv + - yt-dlp pacman: - mpv - python-mpv + - yt-dlp pip: - python-mpv + - yt-dlp package: platypush.plugins.media.mpv type: plugin diff --git a/platypush/plugins/media/omxplayer/manifest.yaml b/platypush/plugins/media/omxplayer/manifest.yaml index e77f8ac9d..305d38b68 100644 --- a/platypush/plugins/media/omxplayer/manifest.yaml +++ b/platypush/plugins/media/omxplayer/manifest.yaml @@ -3,7 +3,9 @@ manifest: install: pip: - omxplayer-wrapper + - yt-dlp apt: - omxplayer + - yt-dlp package: platypush.plugins.media.omxplayer type: plugin diff --git a/platypush/plugins/media/vlc/manifest.yaml b/platypush/plugins/media/vlc/manifest.yaml index 5db883df6..4d53385ec 100644 --- a/platypush/plugins/media/vlc/manifest.yaml +++ b/platypush/plugins/media/vlc/manifest.yaml @@ -4,15 +4,20 @@ manifest: apk: - vlc - py3-vlc + - yt-dlp apt: - vlc - python3-vlc + - yt-dlp dnf: - vlc - python3-vlc + - yt-dlp pacman: - vlc + - yt-dlp pip: - python-vlc + - yt-dlp package: platypush.plugins.media.vlc type: plugin diff --git a/platypush/plugins/youtube/manifest.yaml b/platypush/plugins/youtube/manifest.yaml index f994eed6d..913e615ad 100644 --- a/platypush/plugins/youtube/manifest.yaml +++ b/platypush/plugins/youtube/manifest.yaml @@ -2,28 +2,14 @@ manifest: events: {} install: apk: - - py3-google-api-python-client - - py3-google-auth - - py3-oauth2client - - py3-httplib2 + - yt-dlp apt: - - python3-google-auth - - python3-oauth2client - - python3-httplib2 + - yt-dlp dnf: - - python-google-api-client - - python-google-auth - - python-oauth2client - - python-httplib2 + - yt-dlp pacman: - - python-google-api-python-client - - python-google-auth - - python-oauth2client - - python-httplib2 + - yt-dlp pip: - - google-api-python-client - - google-auth - - oauth2client - - httplib2 + - yt-dlp package: platypush.plugins.youtube type: plugin diff --git a/setup.py b/setup.py index 129ee380d..f4d0e68c5 100755 --- a/setup.py +++ b/setup.py @@ -118,7 +118,7 @@ setup( # Support for OMXPlayer plugin 'omxplayer': ['omxplayer-wrapper'], # Support for YouTube - 'youtube': ['youtube-dl'], + 'youtube': ['yt-dlp'], # Support for torrents download 'torrent': ['python-libtorrent'], # Generic support for cameras