diff --git a/mps_youtube/config.py b/mps_youtube/config.py index 0c963c9b..22c8ab51 100644 --- a/mps_youtube/config.py +++ b/mps_youtube/config.py @@ -347,7 +347,8 @@ class _Config: ConfigItem("show_qrcode", False), ConfigItem("history", True), ConfigItem("input_history", True), - ConfigItem("vlc_dummy_interface", False) + ConfigItem("vlc_dummy_interface", False), + ConfigItem("show_subtitles", True), ] def __getitem__(self, key): diff --git a/mps_youtube/pafy.py b/mps_youtube/pafy.py index 8d543889..ac56458f 100644 --- a/mps_youtube/pafy.py +++ b/mps_youtube/pafy.py @@ -1,15 +1,19 @@ import json -import os +import os, glob import random import re from urllib.parse import parse_qs, urlparse import requests import yt_dlp -from youtubesearchpython import * +from youtubesearchpython import VideosSearch, ChannelsSearch, PlaylistsSearch, Suggestions, Playlist, playlist_from_channel_id, Comments, Video, Channel, ChannelSearch class MyLogger: + + def __init__(self, print_info=False): + self.print_info = print_info + def debug(self, msg): # For compatibility with youtube-dl, both debug and info are passed into debug # You can distinguish them by the prefix '[debug] ' @@ -19,7 +23,8 @@ def debug(self, msg): self.info(msg) def info(self, msg): - pass + if self.print_info: + print(msg) def warning(self, msg): pass @@ -184,4 +189,48 @@ def all_playlists_from_channel(channel_id): while channel.has_more_playlists(): channel.next() playlists.extend(channel.result["playlists"]) - return playlists \ No newline at end of file + return playlists + +def get_subtitles(ytid, output_dir): + ''' + Downloads and saves the .vtt subtitle of give youtube video id under path {output_dir}/subtitles + Subtitles are selected as follows: + 1. Select first user provided subtitle. If none then + 2. Select auto generated 'en' subtitles + ''' + + if output_dir.endswith('/'): + output_dir = output_dir[:-1] + outtmpl = f'{output_dir}/subtitles/{ytid}' + # check if subtitles already exist + existing_subtitles = glob.glob(os.path.join(outtmpl+'*.vtt')) + if existing_subtitles: + return existing_subtitles[0] + + url = f'https://www.youtube.com/watch?v={ytid}' + ydl_opts = { + 'skip_download': True, + 'writesubtitles': True, + 'writeautomaticsub': True, + 'subtitlesformat': 'vtt', + 'outtmpl': outtmpl, + 'logger': MyLogger(print_info=False), + } + # Create a YoutubeDL instance with the options + with yt_dlp.YoutubeDL(ydl_opts) as ydl: + info_dict = ydl.extract_info(url, download=False) + subtitles = info_dict.get('subtitles', {}) + available_formats = list(subtitles.keys()) + if available_formats: + lang = available_formats[0] # pick first subtitle from user-uploaded subtitles + else: + lang = 'en' # otherwise use english auto-generated subtitles + ydl.params['subtitleslangs'] = [lang] + # Add the new options to the existing ydl_opts dictionary + ydl.add_default_info_extractors() + # Create a new yt-dlp object with the updated ydl_opts dictionary + ydl = yt_dlp.YoutubeDL(ydl_opts) + # Download the subtitle + ydl.download([url]) + path = f'{outtmpl}.{lang}.vtt' + return path if os.path.isfile(path) else None \ No newline at end of file diff --git a/mps_youtube/player.py b/mps_youtube/player.py index e00b3dd8..f2e27482 100644 --- a/mps_youtube/player.py +++ b/mps_youtube/player.py @@ -13,6 +13,7 @@ from . import c, config, content, g, history, screen, streams, util from .commands import lastfm from .util import not_utf8_environment +from . import pafy mswin = os.name == "nt" @@ -70,6 +71,8 @@ def play(self, songlist, shuffle=False, repeat=False, override=False): lastfm.set_now_playing(g.artist, g.scrobble_queue[self.song_no]) try: + if config.SHOW_VIDEO and config.SHOW_SUBTITLES: + self.subtitle_path = pafy.get_subtitles(self.song.ytid, config.DDIR.get) self.video, self.stream, self.override = stream_details( self.song, override=self.override, diff --git a/mps_youtube/players/vlc.py b/mps_youtube/players/vlc.py index 48cdb4f4..20e97d42 100644 --- a/mps_youtube/players/vlc.py +++ b/mps_youtube/players/vlc.py @@ -21,6 +21,9 @@ def _generate_real_playerargs(self): if not config.SHOW_VIDEO.get: args.extend(("--no-video",)) + if self.subtitle_path: + args.extend(('--sub-file', self.subtitle_path)) + util.list_update("--play-and-exit", args) return [self.player] + args + [self.stream['url']]