mirror of https://github.com/yt-dlp/yt-dlp.git
parent
6324fd1d74
commit
89de9eb125
|
@ -11,12 +11,18 @@ from youtube_dl.InfoExtractors import YoutubeIE, YoutubePlaylistIE
|
||||||
|
|
||||||
class TestAllURLsMatching(unittest.TestCase):
|
class TestAllURLsMatching(unittest.TestCase):
|
||||||
def test_youtube_playlist_matching(self):
|
def test_youtube_playlist_matching(self):
|
||||||
self.assertTrue(YoutubePlaylistIE().suitable(u'ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8'))
|
self.assertTrue(YoutubePlaylistIE.suitable(u'ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8'))
|
||||||
self.assertTrue(YoutubePlaylistIE().suitable(u'PL63F0C78739B09958'))
|
self.assertTrue(YoutubePlaylistIE.suitable(u'UUBABnxM4Ar9ten8Mdjj1j0Q')) #585
|
||||||
self.assertFalse(YoutubePlaylistIE().suitable(u'PLtS2H6bU1M'))
|
self.assertTrue(YoutubePlaylistIE.suitable(u'PL63F0C78739B09958'))
|
||||||
|
self.assertTrue(YoutubePlaylistIE.suitable(u'https://www.youtube.com/playlist?list=UUBABnxM4Ar9ten8Mdjj1j0Q'))
|
||||||
|
self.assertTrue(YoutubePlaylistIE.suitable(u'https://www.youtube.com/course?list=ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8'))
|
||||||
|
self.assertTrue(YoutubePlaylistIE.suitable(u'https://www.youtube.com/playlist?list=PLwP_SiAcdui0KVebT0mU9Apz359a4ubsC'))
|
||||||
|
self.assertTrue(YoutubePlaylistIE.suitable(u'https://www.youtube.com/watch?v=AV6J6_AeFEQ&playnext=1&list=PL4023E734DA416012')) #668
|
||||||
|
self.assertFalse(YoutubePlaylistIE.suitable(u'PLtS2H6bU1M'))
|
||||||
|
|
||||||
def test_youtube_matching(self):
|
def test_youtube_matching(self):
|
||||||
self.assertTrue(YoutubeIE().suitable(u'PLtS2H6bU1M'))
|
self.assertTrue(YoutubeIE.suitable(u'PLtS2H6bU1M'))
|
||||||
|
self.assertFalse(YoutubeIE.suitable(u'https://www.youtube.com/watch?v=AV6J6_AeFEQ&playnext=1&list=PL4023E734DA416012')) #668
|
||||||
|
|
||||||
def test_youtube_extract(self):
|
def test_youtube_extract(self):
|
||||||
self.assertEqual(YoutubeIE()._extract_id('http://www.youtube.com/watch?&v=BaW_jenozKc'), 'BaW_jenozKc')
|
self.assertEqual(YoutubeIE()._extract_id('http://www.youtube.com/watch?&v=BaW_jenozKc'), 'BaW_jenozKc')
|
||||||
|
|
|
@ -41,6 +41,18 @@ class TestYoutubeLists(unittest.TestCase):
|
||||||
self.assertEqual(map(lambda x: YoutubeIE()._extract_id(x[0]), DL.result),
|
self.assertEqual(map(lambda x: YoutubeIE()._extract_id(x[0]), DL.result),
|
||||||
[ 'bV9L5Ht9LgY', 'FXxLjLQi3Fg', 'tU3Bgo5qJZE' ])
|
[ 'bV9L5Ht9LgY', 'FXxLjLQi3Fg', 'tU3Bgo5qJZE' ])
|
||||||
|
|
||||||
|
#661
|
||||||
|
DL = FakeDownloader()
|
||||||
|
IE = YoutubePlaylistIE(DL)
|
||||||
|
IE.extract('PLMCmkNmxw6Z9eduM7BZjSEh7HiU543Ig0')
|
||||||
|
self.assertTrue(len(DL.result) > 20)
|
||||||
|
|
||||||
|
#673
|
||||||
|
DL = FakeDownloader()
|
||||||
|
IE = YoutubePlaylistIE(DL)
|
||||||
|
IE.extract('PLBB231211A4F62143')
|
||||||
|
self.assertTrue(len(DL.result) > 40)
|
||||||
|
|
||||||
def test_youtube_playlist_long(self):
|
def test_youtube_playlist_long(self):
|
||||||
DL = FakeDownloader()
|
DL = FakeDownloader()
|
||||||
IE = YoutubePlaylistIE(DL)
|
IE = YoutubePlaylistIE(DL)
|
||||||
|
@ -48,6 +60,7 @@ class TestYoutubeLists(unittest.TestCase):
|
||||||
self.assertTrue(len(DL.result) >= 799)
|
self.assertTrue(len(DL.result) >= 799)
|
||||||
|
|
||||||
def test_youtube_playlist_with_deleted(self):
|
def test_youtube_playlist_with_deleted(self):
|
||||||
|
#651
|
||||||
DL = FakeDownloader()
|
DL = FakeDownloader()
|
||||||
IE = YoutubePlaylistIE(DL)
|
IE = YoutubePlaylistIE(DL)
|
||||||
IE.extract('https://www.youtube.com/playlist?list=PLwP_SiAcdui0KVebT0mU9Apz359a4ubsC')
|
IE.extract('https://www.youtube.com/playlist?list=PLwP_SiAcdui0KVebT0mU9Apz359a4ubsC')
|
||||||
|
|
|
@ -74,13 +74,15 @@ class InfoExtractor(object):
|
||||||
self._ready = False
|
self._ready = False
|
||||||
self.set_downloader(downloader)
|
self.set_downloader(downloader)
|
||||||
|
|
||||||
def suitable(self, url):
|
@classmethod
|
||||||
|
def suitable(cls, url):
|
||||||
"""Receives a URL and returns True if suitable for this IE."""
|
"""Receives a URL and returns True if suitable for this IE."""
|
||||||
return re.match(self._VALID_URL, url) is not None
|
return re.match(cls._VALID_URL, url) is not None
|
||||||
|
|
||||||
def working(self):
|
@classmethod
|
||||||
|
def working(cls):
|
||||||
"""Getter method for _WORKING."""
|
"""Getter method for _WORKING."""
|
||||||
return self._WORKING
|
return cls._WORKING
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
"""Initializes an instance (authentication, etc)."""
|
"""Initializes an instance (authentication, etc)."""
|
||||||
|
@ -137,7 +139,6 @@ class YoutubeIE(InfoExtractor):
|
||||||
(?:youtu\.be/|(?:\w+\.)?youtube(?:-nocookie)?\.com/|
|
(?:youtu\.be/|(?:\w+\.)?youtube(?:-nocookie)?\.com/|
|
||||||
tube\.majestyc\.net/) # the various hostnames, with wildcard subdomains
|
tube\.majestyc\.net/) # the various hostnames, with wildcard subdomains
|
||||||
(?:.*?\#/)? # handle anchor (#/) redirect urls
|
(?:.*?\#/)? # handle anchor (#/) redirect urls
|
||||||
(?!view_play_list|my_playlists|artist|playlist) # ignore playlist URLs
|
|
||||||
(?: # the various things that can precede the ID:
|
(?: # the various things that can precede the ID:
|
||||||
(?:(?:v|embed|e)/) # v/ or embed/ or e/
|
(?:(?:v|embed|e)/) # v/ or embed/ or e/
|
||||||
|(?: # or the v= param in all its forms
|
|(?: # or the v= param in all its forms
|
||||||
|
@ -189,9 +190,11 @@ class YoutubeIE(InfoExtractor):
|
||||||
}
|
}
|
||||||
IE_NAME = u'youtube'
|
IE_NAME = u'youtube'
|
||||||
|
|
||||||
def suitable(self, url):
|
@classmethod
|
||||||
|
def suitable(cls, url):
|
||||||
"""Receives a URL and returns True if suitable for this IE."""
|
"""Receives a URL and returns True if suitable for this IE."""
|
||||||
return re.match(self._VALID_URL, url, re.VERBOSE) is not None
|
if YoutubePlaylistIE.suitable(url): return False
|
||||||
|
return re.match(cls._VALID_URL, url, re.VERBOSE) is not None
|
||||||
|
|
||||||
def report_lang(self):
|
def report_lang(self):
|
||||||
"""Report attempt to set language."""
|
"""Report attempt to set language."""
|
||||||
|
@ -1668,17 +1671,17 @@ class YoutubePlaylistIE(InfoExtractor):
|
||||||
(?:\w+\.)?
|
(?:\w+\.)?
|
||||||
youtube\.com/
|
youtube\.com/
|
||||||
(?:
|
(?:
|
||||||
(?:course|view_play_list|my_playlists|artist|playlist)
|
(?:course|view_play_list|my_playlists|artist|playlist|watch)
|
||||||
\? .*? (p|a|list)=
|
\? (?:.*?&)*? (?:p|a|list)=
|
||||||
| user/.*?/user/
|
| user/.*?/user/
|
||||||
| p/
|
| p/
|
||||||
| user/.*?#[pg]/c/
|
| user/.*?#[pg]/c/
|
||||||
)
|
)
|
||||||
(?:PL|EC)?
|
((?:PL|EC|UU)?[0-9A-Za-z-_]{10,})
|
||||||
|PL|EC)
|
.*
|
||||||
([0-9A-Za-z-_]{10,})
|
|
|
||||||
(?:/.*?/([0-9A-Za-z_-]+))?
|
((?:PL|EC|UU)[0-9A-Za-z-_]{10,})
|
||||||
.*"""
|
)"""
|
||||||
_TEMPLATE_URL = 'https://gdata.youtube.com/feeds/api/playlists/%s?max-results=%i&start-index=%i&v=2&alt=json'
|
_TEMPLATE_URL = 'https://gdata.youtube.com/feeds/api/playlists/%s?max-results=%i&start-index=%i&v=2&alt=json'
|
||||||
_MAX_RESULTS = 50
|
_MAX_RESULTS = 50
|
||||||
IE_NAME = u'youtube:playlist'
|
IE_NAME = u'youtube:playlist'
|
||||||
|
@ -1686,9 +1689,10 @@ class YoutubePlaylistIE(InfoExtractor):
|
||||||
def __init__(self, downloader=None):
|
def __init__(self, downloader=None):
|
||||||
InfoExtractor.__init__(self, downloader)
|
InfoExtractor.__init__(self, downloader)
|
||||||
|
|
||||||
def suitable(self, url):
|
@classmethod
|
||||||
|
def suitable(cls, url):
|
||||||
"""Receives a URL and returns True if suitable for this IE."""
|
"""Receives a URL and returns True if suitable for this IE."""
|
||||||
return re.match(self._VALID_URL, url, re.VERBOSE) is not None
|
return re.match(cls._VALID_URL, url, re.VERBOSE) is not None
|
||||||
|
|
||||||
def report_download_page(self, playlist_id, pagenum):
|
def report_download_page(self, playlist_id, pagenum):
|
||||||
"""Report attempt to download playlist page with given number."""
|
"""Report attempt to download playlist page with given number."""
|
||||||
|
@ -1701,13 +1705,8 @@ class YoutubePlaylistIE(InfoExtractor):
|
||||||
self._downloader.trouble(u'ERROR: invalid url: %s' % url)
|
self._downloader.trouble(u'ERROR: invalid url: %s' % url)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Single video case
|
|
||||||
if mobj.group(3) is not None:
|
|
||||||
self._downloader.download([mobj.group(3)])
|
|
||||||
return
|
|
||||||
|
|
||||||
# Download playlist videos from API
|
# Download playlist videos from API
|
||||||
playlist_id = mobj.group(2)
|
playlist_id = mobj.group(1) or mobj.group(2)
|
||||||
page_num = 1
|
page_num = 1
|
||||||
videos = []
|
videos = []
|
||||||
|
|
||||||
|
@ -1727,7 +1726,12 @@ class YoutubePlaylistIE(InfoExtractor):
|
||||||
self._downloader.trouble(u'ERROR: Invalid JSON in API response: ' + compat_str(err))
|
self._downloader.trouble(u'ERROR: Invalid JSON in API response: ' + compat_str(err))
|
||||||
return
|
return
|
||||||
|
|
||||||
videos += [(entry['yt$position']['$t'], entry['content']['src']) for entry in response['feed']['entry']]
|
if not 'feed' in response or not 'entry' in response['feed']:
|
||||||
|
self._downloader.trouble(u'ERROR: Got a malformed response from YouTube API')
|
||||||
|
return
|
||||||
|
videos += [ (entry['yt$position']['$t'], entry['content']['src'])
|
||||||
|
for entry in response['feed']['entry']
|
||||||
|
if 'content' in entry ]
|
||||||
|
|
||||||
if len(response['feed']['entry']) < self._MAX_RESULTS:
|
if len(response['feed']['entry']) < self._MAX_RESULTS:
|
||||||
break
|
break
|
||||||
|
@ -2313,9 +2317,10 @@ class ComedyCentralIE(InfoExtractor):
|
||||||
'400': '384x216',
|
'400': '384x216',
|
||||||
}
|
}
|
||||||
|
|
||||||
def suitable(self, url):
|
@classmethod
|
||||||
|
def suitable(cls, url):
|
||||||
"""Receives a URL and returns True if suitable for this IE."""
|
"""Receives a URL and returns True if suitable for this IE."""
|
||||||
return re.match(self._VALID_URL, url, re.VERBOSE) is not None
|
return re.match(cls._VALID_URL, url, re.VERBOSE) is not None
|
||||||
|
|
||||||
def report_extraction(self, episode_id):
|
def report_extraction(self, episode_id):
|
||||||
self._downloader.to_screen(u'[comedycentral] %s: Extracting information' % episode_id)
|
self._downloader.to_screen(u'[comedycentral] %s: Extracting information' % episode_id)
|
||||||
|
@ -3628,9 +3633,10 @@ class SteamIE(InfoExtractor):
|
||||||
(?P<videoID>\d*)(?P<extra>\??) #For urltype == video we sometimes get the videoID
|
(?P<videoID>\d*)(?P<extra>\??) #For urltype == video we sometimes get the videoID
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def suitable(self, url):
|
@classmethod
|
||||||
|
def suitable(cls, url):
|
||||||
"""Receives a URL and returns True if suitable for this IE."""
|
"""Receives a URL and returns True if suitable for this IE."""
|
||||||
return re.match(self._VALID_URL, url, re.VERBOSE) is not None
|
return re.match(cls._VALID_URL, url, re.VERBOSE) is not None
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
m = re.match(self._VALID_URL, url, re.VERBOSE)
|
m = re.match(self._VALID_URL, url, re.VERBOSE)
|
||||||
|
@ -4004,9 +4010,10 @@ class TEDIE(InfoExtractor):
|
||||||
/(?P<name>\w+) # Here goes the name and then ".html"
|
/(?P<name>\w+) # Here goes the name and then ".html"
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def suitable(self, url):
|
@classmethod
|
||||||
|
def suitable(cls, url):
|
||||||
"""Receives a URL and returns True if suitable for this IE."""
|
"""Receives a URL and returns True if suitable for this IE."""
|
||||||
return re.match(self._VALID_URL, url, re.VERBOSE) is not None
|
return re.match(cls._VALID_URL, url, re.VERBOSE) is not None
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
m=re.match(self._VALID_URL, url, re.VERBOSE)
|
m=re.match(self._VALID_URL, url, re.VERBOSE)
|
||||||
|
|
Loading…
Reference in New Issue