|
|
@ -3139,8 +3139,7 @@ class YoutubePlaylistIE(InfoExtractor):
|
|
|
|
(?:
|
|
|
|
(?:
|
|
|
|
(?:
|
|
|
|
(?:
|
|
|
|
youtube(?:kids)?\.com|
|
|
|
|
youtube(?:kids)?\.com|
|
|
|
|
invidio\.us|
|
|
|
|
invidio\.us
|
|
|
|
youtu\.be
|
|
|
|
|
|
|
|
)
|
|
|
|
)
|
|
|
|
/.*?\?.*?\blist=
|
|
|
|
/.*?\?.*?\blist=
|
|
|
|
)?
|
|
|
|
)?
|
|
|
@ -3185,6 +3184,32 @@ class YoutubePlaylistIE(InfoExtractor):
|
|
|
|
'uploader_id': 'UC21nz3_MesPLqtDqwdvnoxA',
|
|
|
|
'uploader_id': 'UC21nz3_MesPLqtDqwdvnoxA',
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, {
|
|
|
|
}, {
|
|
|
|
|
|
|
|
'url': 'TLGGrESM50VT6acwMjAyMjAxNw',
|
|
|
|
|
|
|
|
'only_matching': True,
|
|
|
|
|
|
|
|
}, {
|
|
|
|
|
|
|
|
# music album playlist
|
|
|
|
|
|
|
|
'url': 'OLAK5uy_m4xAFdmMC5rX3Ji3g93pQe3hqLZw_9LhM',
|
|
|
|
|
|
|
|
'only_matching': True,
|
|
|
|
|
|
|
|
}]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
|
|
|
def suitable(cls, url):
|
|
|
|
|
|
|
|
return False if YoutubeTabIE.suitable(url) else super(
|
|
|
|
|
|
|
|
YoutubePlaylistIE, cls).suitable(url)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _real_extract(self, url):
|
|
|
|
|
|
|
|
playlist_id = self._match_id(url)
|
|
|
|
|
|
|
|
qs = compat_urlparse.parse_qs(compat_urlparse.urlparse(url).query)
|
|
|
|
|
|
|
|
if not qs:
|
|
|
|
|
|
|
|
qs = {'list': playlist_id}
|
|
|
|
|
|
|
|
return self.url_result(
|
|
|
|
|
|
|
|
update_url_query('https://www.youtube.com/playlist', qs),
|
|
|
|
|
|
|
|
ie=YoutubeTabIE.ie_key(), video_id=playlist_id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class YoutubeYtBeIE(InfoExtractor):
|
|
|
|
|
|
|
|
_VALID_URL = r'https?://youtu\.be/(?P<id>[0-9A-Za-z_-]{11})/*?.*?\blist=(?P<playlist_id>%(playlist_id)s)' % {'playlist_id': YoutubeBaseInfoExtractor._PLAYLIST_ID_RE}
|
|
|
|
|
|
|
|
_TESTS = [{
|
|
|
|
'url': 'https://youtu.be/yeWKywCrFtk?list=PL2qgrgXsNUG5ig9cat4ohreBjYLAPC0J5',
|
|
|
|
'url': 'https://youtu.be/yeWKywCrFtk?list=PL2qgrgXsNUG5ig9cat4ohreBjYLAPC0J5',
|
|
|
|
'info_dict': {
|
|
|
|
'info_dict': {
|
|
|
|
'id': 'yeWKywCrFtk',
|
|
|
|
'id': 'yeWKywCrFtk',
|
|
|
@ -3207,28 +3232,18 @@ class YoutubePlaylistIE(InfoExtractor):
|
|
|
|
}, {
|
|
|
|
}, {
|
|
|
|
'url': 'https://youtu.be/uWyaPkt-VOI?list=PL9D9FC436B881BA21',
|
|
|
|
'url': 'https://youtu.be/uWyaPkt-VOI?list=PL9D9FC436B881BA21',
|
|
|
|
'only_matching': True,
|
|
|
|
'only_matching': True,
|
|
|
|
}, {
|
|
|
|
|
|
|
|
'url': 'TLGGrESM50VT6acwMjAyMjAxNw',
|
|
|
|
|
|
|
|
'only_matching': True,
|
|
|
|
|
|
|
|
}, {
|
|
|
|
|
|
|
|
# music album playlist
|
|
|
|
|
|
|
|
'url': 'OLAK5uy_m4xAFdmMC5rX3Ji3g93pQe3hqLZw_9LhM',
|
|
|
|
|
|
|
|
'only_matching': True,
|
|
|
|
|
|
|
|
}]
|
|
|
|
}]
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
|
|
|
def suitable(cls, url):
|
|
|
|
|
|
|
|
return False if YoutubeTabIE.suitable(url) else super(
|
|
|
|
|
|
|
|
YoutubePlaylistIE, cls).suitable(url)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _real_extract(self, url):
|
|
|
|
def _real_extract(self, url):
|
|
|
|
playlist_id = self._match_id(url)
|
|
|
|
mobj = re.match(self._VALID_URL, url)
|
|
|
|
qs = compat_urlparse.parse_qs(compat_urlparse.urlparse(url).query)
|
|
|
|
video_id = mobj.group('id')
|
|
|
|
if not qs:
|
|
|
|
playlist_id = mobj.group('playlist_id')
|
|
|
|
qs = {'list': playlist_id}
|
|
|
|
|
|
|
|
return self.url_result(
|
|
|
|
return self.url_result(
|
|
|
|
update_url_query('https://www.youtube.com/playlist', qs),
|
|
|
|
update_url_query('https://www.youtube.com/watch', {
|
|
|
|
ie=YoutubeTabIE.ie_key(), video_id=playlist_id)
|
|
|
|
'v': video_id,
|
|
|
|
|
|
|
|
'list': playlist_id,
|
|
|
|
|
|
|
|
'feature': 'youtu.be',
|
|
|
|
|
|
|
|
}), ie=YoutubeTabIE.ie_key(), video_id=playlist_id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class YoutubeYtUserIE(InfoExtractor):
|
|
|
|
class YoutubeYtUserIE(InfoExtractor):
|
|
|
|