| @@ -11,12 +11,18 @@ from youtube_dl.InfoExtractors import YoutubeIE, YoutubePlaylistIE | ||||
|  | ||||
| class TestAllURLsMatching(unittest.TestCase): | ||||
|     def test_youtube_playlist_matching(self): | ||||
|         self.assertTrue(YoutubePlaylistIE().suitable(u'ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8')) | ||||
|         self.assertTrue(YoutubePlaylistIE().suitable(u'PL63F0C78739B09958')) | ||||
|         self.assertFalse(YoutubePlaylistIE().suitable(u'PLtS2H6bU1M')) | ||||
|         self.assertTrue(YoutubePlaylistIE.suitable(u'ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8')) | ||||
|         self.assertTrue(YoutubePlaylistIE.suitable(u'UUBABnxM4Ar9ten8Mdjj1j0Q')) #585 | ||||
|         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): | ||||
|         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): | ||||
|         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), | ||||
|             [ '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): | ||||
|         DL = FakeDownloader() | ||||
|         IE = YoutubePlaylistIE(DL) | ||||
| @@ -48,6 +60,7 @@ class TestYoutubeLists(unittest.TestCase): | ||||
|         self.assertTrue(len(DL.result) >= 799) | ||||
|  | ||||
|     def test_youtube_playlist_with_deleted(self): | ||||
|         #651 | ||||
|         DL = FakeDownloader() | ||||
|         IE = YoutubePlaylistIE(DL) | ||||
|         IE.extract('https://www.youtube.com/playlist?list=PLwP_SiAcdui0KVebT0mU9Apz359a4ubsC') | ||||
|   | ||||
| @@ -74,13 +74,15 @@ class InfoExtractor(object): | ||||
|         self._ready = False | ||||
|         self.set_downloader(downloader) | ||||
|  | ||||
|     def suitable(self, url): | ||||
|     @classmethod | ||||
|     def suitable(cls, url): | ||||
|         """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.""" | ||||
|         return self._WORKING | ||||
|         return cls._WORKING | ||||
|  | ||||
|     def initialize(self): | ||||
|         """Initializes an instance (authentication, etc).""" | ||||
| @@ -137,7 +139,6 @@ class YoutubeIE(InfoExtractor): | ||||
|                          (?:youtu\.be/|(?:\w+\.)?youtube(?:-nocookie)?\.com/| | ||||
|                             tube\.majestyc\.net/)                             # the various hostnames, with wildcard subdomains | ||||
|                          (?:.*?\#/)?                                          # handle anchor (#/) redirect urls | ||||
|                          (?!view_play_list|my_playlists|artist|playlist)      # ignore playlist URLs | ||||
|                          (?:                                                  # the various things that can precede the ID: | ||||
|                              (?:(?:v|embed|e)/)                               # v/ or embed/ or e/ | ||||
|                              |(?:                                             # or the v= param in all its forms | ||||
| @@ -189,9 +190,11 @@ class YoutubeIE(InfoExtractor): | ||||
|     } | ||||
|     IE_NAME = u'youtube' | ||||
|  | ||||
|     def suitable(self, url): | ||||
|     @classmethod | ||||
|     def suitable(cls, url): | ||||
|         """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): | ||||
|         """Report attempt to set language.""" | ||||
| @@ -1668,17 +1671,17 @@ class YoutubePlaylistIE(InfoExtractor): | ||||
|                         (?:\w+\.)? | ||||
|                         youtube\.com/ | ||||
|                         (?: | ||||
|                            (?:course|view_play_list|my_playlists|artist|playlist) | ||||
|                            \? .*? (p|a|list)= | ||||
|                            (?:course|view_play_list|my_playlists|artist|playlist|watch) | ||||
|                            \? (?:.*?&)*? (?:p|a|list)= | ||||
|                         |  user/.*?/user/ | ||||
|                         |  p/ | ||||
|                         |  user/.*?#[pg]/c/ | ||||
|                         ) | ||||
|                         (?:PL|EC)? | ||||
|                      |PL|EC) | ||||
|                      ([0-9A-Za-z-_]{10,}) | ||||
|                      (?:/.*?/([0-9A-Za-z_-]+))? | ||||
|                      .*""" | ||||
|                         ((?:PL|EC|UU)?[0-9A-Za-z-_]{10,}) | ||||
|                         .* | ||||
|                      | | ||||
|                         ((?: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' | ||||
|     _MAX_RESULTS = 50 | ||||
|     IE_NAME = u'youtube:playlist' | ||||
| @@ -1686,9 +1689,10 @@ class YoutubePlaylistIE(InfoExtractor): | ||||
|     def __init__(self, downloader=None): | ||||
|         InfoExtractor.__init__(self, downloader) | ||||
|  | ||||
|     def suitable(self, url): | ||||
|     @classmethod | ||||
|     def suitable(cls, url): | ||||
|         """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): | ||||
|         """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) | ||||
|             return | ||||
|  | ||||
|         # Single video case | ||||
|         if mobj.group(3) is not None: | ||||
|             self._downloader.download([mobj.group(3)]) | ||||
|             return | ||||
|  | ||||
|         # Download playlist videos from API | ||||
|         playlist_id = mobj.group(2) | ||||
|         playlist_id = mobj.group(1) or mobj.group(2) | ||||
|         page_num = 1 | ||||
|         videos = [] | ||||
|  | ||||
| @@ -1727,7 +1726,12 @@ class YoutubePlaylistIE(InfoExtractor): | ||||
|                 self._downloader.trouble(u'ERROR: Invalid JSON in API response: ' + compat_str(err)) | ||||
|                 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: | ||||
|                 break | ||||
| @@ -2313,9 +2317,10 @@ class ComedyCentralIE(InfoExtractor): | ||||
|         '400': '384x216', | ||||
|     } | ||||
|  | ||||
|     def suitable(self, url): | ||||
|     @classmethod | ||||
|     def suitable(cls, url): | ||||
|         """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): | ||||
|         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 | ||||
|                 """ | ||||
|  | ||||
|     def suitable(self, url): | ||||
|     @classmethod | ||||
|     def suitable(cls, url): | ||||
|         """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): | ||||
|         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" | ||||
|                    ''' | ||||
|  | ||||
|     def suitable(self, url): | ||||
|     @classmethod | ||||
|     def suitable(cls, url): | ||||
|         """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): | ||||
|         m=re.match(self._VALID_URL, url, re.VERBOSE) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user