Merge pull request #949 from tpikonen/ytdl-streaming

Allow episodes with youtube-dl compatible URLs
This commit is contained in:
Eric Le Lay 2021-05-16 17:44:48 +02:00 committed by GitHub
commit 56e8f4755f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 34 additions and 5 deletions

View File

@ -285,6 +285,10 @@ class gPodderYoutubeDL(download.CustomDownloader):
self._ydl_opts['verbose'] = True
else:
self._ydl_opts['quiet'] = True
# Don't create downloaders for URLs supported by these youtube-dl extractors
self.ie_blacklist = ["Generic"]
# Cache URL regexes from youtube-dl matches here, seed with youtube regex
self.regex_cache = [re.compile(r'https://www.youtube.com/watch\?v=.+')]
# #686 on windows without a console, sys.stdout is None, causing exceptions
# when adding podcasts.
# See https://docs.python.org/3/library/sys.html#sys.__stderr__ Note
@ -411,16 +415,30 @@ class gPodderYoutubeDL(download.CustomDownloader):
return self.refresh(url, channel.url, max_episodes)
return None
def is_supported_url(self, url):
if self.regex_cache[0].match(url) is not None:
return True
for r in self.regex_cache[1:]:
if r.match(url) is not None:
self.regex_cache.remove(r)
self.regex_cache.insert(0, r)
return True
with youtube_dl.YoutubeDL(self._ydl_opts) as ydl:
for ie in ydl._ies:
if ie.suitable(url) and ie.ie_key() not in self.ie_blacklist:
self.regex_cache.insert(0, ie._VALID_URL_RE)
return True
return False
def custom_downloader(self, unused_config, episode):
"""
called from registry.custom_downloader.resolve
"""
if not self.force and not self.my_config.manage_downloads:
return None
if re.match(r'''https://www.youtube.com/watch\?v=.+''', episode.url):
if self.is_supported_url(episode.url):
return YoutubeCustomDownload(self, episode.url, episode)
elif re.match(r'''https://www.youtube.com/watch\?v=.+''', episode.link):
return YoutubeCustomDownload(self, episode.link, episode)
return None

View File

@ -290,18 +290,26 @@ class PodcastEpisode(PodcastModelObject):
audio_available = any(enclosure['mime_type'].startswith('audio/') for enclosure in entry['enclosures'])
video_available = any(enclosure['mime_type'].startswith('video/') for enclosure in entry['enclosures'])
link_has_media = False
if not (audio_available or video_available):
_url = episode.url
episode.url = util.normalize_feed_url(entry['link'])
# Check if any extensions (e.g. youtube-dl) support the link
link_has_media = registry.custom_downloader.resolve(None, None, episode) is not None
episode.url = _url
media_available = audio_available or video_available or link_has_media
for enclosure in entry['enclosures']:
episode.mime_type = enclosure['mime_type']
# Skip images in feeds if audio or video is available (bug 979)
# This must (and does) also look in Media RSS enclosures (bug 1430)
if episode.mime_type.startswith('image/') and (audio_available or video_available):
if episode.mime_type.startswith('image/') and media_available:
continue
# If we have audio or video available later on, skip
# all 'application/*' data types (fixes Linux Outlaws and peertube feeds)
if episode.mime_type.startswith('application/') and (audio_available or video_available):
if episode.mime_type.startswith('application/') and media_available:
continue
episode.url = util.normalize_feed_url(enclosure['url'])
@ -327,6 +335,9 @@ class PodcastEpisode(PodcastModelObject):
if file_type is not None:
return episode
if link_has_media:
return episode
return None
def __init__(self, channel):