mirror of
https://github.com/ytdl-org/youtube-dl
synced 2024-12-23 04:30:10 +09:00
Compare commits
6 Commits
cb2b9a22a5
...
9360936f26
Author | SHA1 | Date | |
---|---|---|---|
|
9360936f26 | ||
|
bb2b89e077 | ||
|
2d7a29081c | ||
|
2864179293 | ||
|
284f8306df | ||
|
aa613ef7e1 |
6
.github/ISSUE_TEMPLATE/1_broken_site.md
vendored
6
.github/ISSUE_TEMPLATE/1_broken_site.md
vendored
@ -18,7 +18,7 @@ title: ''
|
|||||||
|
|
||||||
<!--
|
<!--
|
||||||
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dl:
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dl:
|
||||||
- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is 2020.11.17. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
|
- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is 2020.11.18. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
|
||||||
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
||||||
- Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in http://yt-dl.org/escape.
|
- Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in http://yt-dl.org/escape.
|
||||||
- Search the bugtracker for similar issues: http://yt-dl.org/search-issues. DO NOT post duplicates.
|
- Search the bugtracker for similar issues: http://yt-dl.org/search-issues. DO NOT post duplicates.
|
||||||
@ -26,7 +26,7 @@ Carefully read and work through this check list in order to prevent the most com
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
- [ ] I'm reporting a broken site support
|
- [ ] I'm reporting a broken site support
|
||||||
- [ ] I've verified that I'm running youtube-dl version **2020.11.17**
|
- [ ] I've verified that I'm running youtube-dl version **2020.11.18**
|
||||||
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
||||||
- [ ] I've checked that all URLs and arguments with special characters are properly quoted or escaped
|
- [ ] I've checked that all URLs and arguments with special characters are properly quoted or escaped
|
||||||
- [ ] I've searched the bugtracker for similar issues including closed ones
|
- [ ] I've searched the bugtracker for similar issues including closed ones
|
||||||
@ -41,7 +41,7 @@ Add the `-v` flag to your command line you run youtube-dl with (`youtube-dl -v <
|
|||||||
[debug] User config: []
|
[debug] User config: []
|
||||||
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
|
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
|
||||||
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
|
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
|
||||||
[debug] youtube-dl version 2020.11.17
|
[debug] youtube-dl version 2020.11.18
|
||||||
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
|
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
|
||||||
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
||||||
[debug] Proxy map: {}
|
[debug] Proxy map: {}
|
||||||
|
@ -19,7 +19,7 @@ labels: 'site-support-request'
|
|||||||
|
|
||||||
<!--
|
<!--
|
||||||
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dl:
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dl:
|
||||||
- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is 2020.11.17. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
|
- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is 2020.11.18. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
|
||||||
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
||||||
- Make sure that site you are requesting is not dedicated to copyright infringement, see https://yt-dl.org/copyright-infringement. youtube-dl does not support such sites. In order for site support request to be accepted all provided example URLs should not violate any copyrights.
|
- Make sure that site you are requesting is not dedicated to copyright infringement, see https://yt-dl.org/copyright-infringement. youtube-dl does not support such sites. In order for site support request to be accepted all provided example URLs should not violate any copyrights.
|
||||||
- Search the bugtracker for similar site support requests: http://yt-dl.org/search-issues. DO NOT post duplicates.
|
- Search the bugtracker for similar site support requests: http://yt-dl.org/search-issues. DO NOT post duplicates.
|
||||||
@ -27,7 +27,7 @@ Carefully read and work through this check list in order to prevent the most com
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
- [ ] I'm reporting a new site support request
|
- [ ] I'm reporting a new site support request
|
||||||
- [ ] I've verified that I'm running youtube-dl version **2020.11.17**
|
- [ ] I've verified that I'm running youtube-dl version **2020.11.18**
|
||||||
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
||||||
- [ ] I've checked that none of provided URLs violate any copyrights
|
- [ ] I've checked that none of provided URLs violate any copyrights
|
||||||
- [ ] I've searched the bugtracker for similar site support requests including closed ones
|
- [ ] I've searched the bugtracker for similar site support requests including closed ones
|
||||||
|
@ -18,13 +18,13 @@ title: ''
|
|||||||
|
|
||||||
<!--
|
<!--
|
||||||
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dl:
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dl:
|
||||||
- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is 2020.11.17. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
|
- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is 2020.11.18. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
|
||||||
- Search the bugtracker for similar site feature requests: http://yt-dl.org/search-issues. DO NOT post duplicates.
|
- Search the bugtracker for similar site feature requests: http://yt-dl.org/search-issues. DO NOT post duplicates.
|
||||||
- Finally, put x into all relevant boxes (like this [x])
|
- Finally, put x into all relevant boxes (like this [x])
|
||||||
-->
|
-->
|
||||||
|
|
||||||
- [ ] I'm reporting a site feature request
|
- [ ] I'm reporting a site feature request
|
||||||
- [ ] I've verified that I'm running youtube-dl version **2020.11.17**
|
- [ ] I've verified that I'm running youtube-dl version **2020.11.18**
|
||||||
- [ ] I've searched the bugtracker for similar site feature requests including closed ones
|
- [ ] I've searched the bugtracker for similar site feature requests including closed ones
|
||||||
|
|
||||||
|
|
||||||
|
6
.github/ISSUE_TEMPLATE/4_bug_report.md
vendored
6
.github/ISSUE_TEMPLATE/4_bug_report.md
vendored
@ -18,7 +18,7 @@ title: ''
|
|||||||
|
|
||||||
<!--
|
<!--
|
||||||
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dl:
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dl:
|
||||||
- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is 2020.11.17. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
|
- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is 2020.11.18. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
|
||||||
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
|
||||||
- Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in http://yt-dl.org/escape.
|
- Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in http://yt-dl.org/escape.
|
||||||
- Search the bugtracker for similar issues: http://yt-dl.org/search-issues. DO NOT post duplicates.
|
- Search the bugtracker for similar issues: http://yt-dl.org/search-issues. DO NOT post duplicates.
|
||||||
@ -27,7 +27,7 @@ Carefully read and work through this check list in order to prevent the most com
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
- [ ] I'm reporting a broken site support issue
|
- [ ] I'm reporting a broken site support issue
|
||||||
- [ ] I've verified that I'm running youtube-dl version **2020.11.17**
|
- [ ] I've verified that I'm running youtube-dl version **2020.11.18**
|
||||||
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
- [ ] I've checked that all provided URLs are alive and playable in a browser
|
||||||
- [ ] I've checked that all URLs and arguments with special characters are properly quoted or escaped
|
- [ ] I've checked that all URLs and arguments with special characters are properly quoted or escaped
|
||||||
- [ ] I've searched the bugtracker for similar bug reports including closed ones
|
- [ ] I've searched the bugtracker for similar bug reports including closed ones
|
||||||
@ -43,7 +43,7 @@ Add the `-v` flag to your command line you run youtube-dl with (`youtube-dl -v <
|
|||||||
[debug] User config: []
|
[debug] User config: []
|
||||||
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
|
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
|
||||||
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
|
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
|
||||||
[debug] youtube-dl version 2020.11.17
|
[debug] youtube-dl version 2020.11.18
|
||||||
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
|
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
|
||||||
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
||||||
[debug] Proxy map: {}
|
[debug] Proxy map: {}
|
||||||
|
4
.github/ISSUE_TEMPLATE/5_feature_request.md
vendored
4
.github/ISSUE_TEMPLATE/5_feature_request.md
vendored
@ -19,13 +19,13 @@ labels: 'request'
|
|||||||
|
|
||||||
<!--
|
<!--
|
||||||
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dl:
|
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dl:
|
||||||
- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is 2020.11.17. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
|
- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is 2020.11.18. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
|
||||||
- Search the bugtracker for similar feature requests: http://yt-dl.org/search-issues. DO NOT post duplicates.
|
- Search the bugtracker for similar feature requests: http://yt-dl.org/search-issues. DO NOT post duplicates.
|
||||||
- Finally, put x into all relevant boxes (like this [x])
|
- Finally, put x into all relevant boxes (like this [x])
|
||||||
-->
|
-->
|
||||||
|
|
||||||
- [ ] I'm reporting a feature request
|
- [ ] I'm reporting a feature request
|
||||||
- [ ] I've verified that I'm running youtube-dl version **2020.11.17**
|
- [ ] I've verified that I'm running youtube-dl version **2020.11.18**
|
||||||
- [ ] I've searched the bugtracker for similar feature requests including closed ones
|
- [ ] I've searched the bugtracker for similar feature requests including closed ones
|
||||||
|
|
||||||
|
|
||||||
|
16
ChangeLog
16
ChangeLog
@ -1,3 +1,19 @@
|
|||||||
|
version 2020.11.18
|
||||||
|
|
||||||
|
Extractors
|
||||||
|
* [spiegel] Fix extraction (#24206, #24767)
|
||||||
|
* [youtube] Improve extraction
|
||||||
|
+ Add support for --no-playlist (#27009)
|
||||||
|
* Improve playlist and mix extraction (#26390, #26509, #26534, #27011)
|
||||||
|
+ Extract playlist uploader data
|
||||||
|
* [youtube:tab] Fix view count extraction (#27051)
|
||||||
|
* [malltv] Fix extraction (#27035)
|
||||||
|
+ [bandcamp] Extract playlist description (#22684)
|
||||||
|
* [urplay] Fix extraction (#26828)
|
||||||
|
* [youtube:tab] Fix playlist title extraction (#27015)
|
||||||
|
* [youtube] Fix chapters extraction (#26005)
|
||||||
|
|
||||||
|
|
||||||
version 2020.11.17
|
version 2020.11.17
|
||||||
|
|
||||||
Core
|
Core
|
||||||
|
@ -824,8 +824,6 @@
|
|||||||
- **SpankBangPlaylist**
|
- **SpankBangPlaylist**
|
||||||
- **Spankwire**
|
- **Spankwire**
|
||||||
- **Spiegel**
|
- **Spiegel**
|
||||||
- **Spiegel:Article**: Articles on spiegel.de
|
|
||||||
- **Spiegeltv**
|
|
||||||
- **sport.francetvinfo.fr**
|
- **sport.francetvinfo.fr**
|
||||||
- **Sport5**
|
- **Sport5**
|
||||||
- **SportBox**
|
- **SportBox**
|
||||||
|
@ -31,16 +31,17 @@ class TestAllURLsMatching(unittest.TestCase):
|
|||||||
|
|
||||||
def test_youtube_playlist_matching(self):
|
def test_youtube_playlist_matching(self):
|
||||||
assertPlaylist = lambda url: self.assertMatch(url, ['youtube:playlist'])
|
assertPlaylist = lambda url: self.assertMatch(url, ['youtube:playlist'])
|
||||||
|
assertTab = lambda url: self.assertMatch(url, ['youtube:tab'])
|
||||||
assertPlaylist('ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8')
|
assertPlaylist('ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8')
|
||||||
assertPlaylist('UUBABnxM4Ar9ten8Mdjj1j0Q') # 585
|
assertPlaylist('UUBABnxM4Ar9ten8Mdjj1j0Q') # 585
|
||||||
assertPlaylist('PL63F0C78739B09958')
|
assertPlaylist('PL63F0C78739B09958')
|
||||||
# assertPlaylist('https://www.youtube.com/playlist?list=UUBABnxM4Ar9ten8Mdjj1j0Q')
|
assertTab('https://www.youtube.com/playlist?list=UUBABnxM4Ar9ten8Mdjj1j0Q')
|
||||||
assertPlaylist('https://www.youtube.com/course?list=ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8')
|
assertPlaylist('https://www.youtube.com/course?list=ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8')
|
||||||
# assertPlaylist('https://www.youtube.com/playlist?list=PLwP_SiAcdui0KVebT0mU9Apz359a4ubsC')
|
assertTab('https://www.youtube.com/playlist?list=PLwP_SiAcdui0KVebT0mU9Apz359a4ubsC')
|
||||||
assertPlaylist('https://www.youtube.com/watch?v=AV6J6_AeFEQ&playnext=1&list=PL4023E734DA416012') # 668
|
assertTab('https://www.youtube.com/watch?v=AV6J6_AeFEQ&playnext=1&list=PL4023E734DA416012') # 668
|
||||||
self.assertFalse('youtube:playlist' in self.matching_ies('PLtS2H6bU1M'))
|
self.assertFalse('youtube:playlist' in self.matching_ies('PLtS2H6bU1M'))
|
||||||
# Top tracks
|
# Top tracks
|
||||||
# assertPlaylist('https://www.youtube.com/playlist?list=MCUS.20142101')
|
assertTab('https://www.youtube.com/playlist?list=MCUS.20142101')
|
||||||
|
|
||||||
def test_youtube_matching(self):
|
def test_youtube_matching(self):
|
||||||
self.assertTrue(YoutubeIE.suitable('PLtS2H6bU1M'))
|
self.assertTrue(YoutubeIE.suitable('PLtS2H6bU1M'))
|
||||||
|
@ -1054,8 +1054,7 @@ from .spankbang import (
|
|||||||
SpankBangPlaylistIE,
|
SpankBangPlaylistIE,
|
||||||
)
|
)
|
||||||
from .spankwire import SpankwireIE
|
from .spankwire import SpankwireIE
|
||||||
from .spiegel import SpiegelIE, SpiegelArticleIE
|
from .spiegel import SpiegelIE
|
||||||
from .spiegeltv import SpiegeltvIE
|
|
||||||
from .spike import (
|
from .spike import (
|
||||||
BellatorIE,
|
BellatorIE,
|
||||||
ParamountNetworkIE,
|
ParamountNetworkIE,
|
||||||
|
@ -1,10 +1,16 @@
|
|||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import re
|
|
||||||
|
|
||||||
from .common import InfoExtractor
|
from .common import InfoExtractor
|
||||||
from ..utils import merge_dicts
|
from ..utils import (
|
||||||
|
clean_html,
|
||||||
|
dict_get,
|
||||||
|
float_or_none,
|
||||||
|
int_or_none,
|
||||||
|
merge_dicts,
|
||||||
|
parse_duration,
|
||||||
|
try_get,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class MallTVIE(InfoExtractor):
|
class MallTVIE(InfoExtractor):
|
||||||
@ -17,7 +23,7 @@ class MallTVIE(InfoExtractor):
|
|||||||
'display_id': '18-miliard-pro-neziskovky-opravdu-jsou-sportovci-nebo-clovek-v-tisni-pijavice',
|
'display_id': '18-miliard-pro-neziskovky-opravdu-jsou-sportovci-nebo-clovek-v-tisni-pijavice',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'title': '18 miliard pro neziskovky. Opravdu jsou sportovci nebo Člověk v tísni pijavice?',
|
'title': '18 miliard pro neziskovky. Opravdu jsou sportovci nebo Člověk v tísni pijavice?',
|
||||||
'description': 'md5:25fc0ec42a72ba602b602c683fa29deb',
|
'description': 'md5:db7d5744a4bd4043d9d98324aa72ab35',
|
||||||
'duration': 216,
|
'duration': 216,
|
||||||
'timestamp': 1538870400,
|
'timestamp': 1538870400,
|
||||||
'upload_date': '20181007',
|
'upload_date': '20181007',
|
||||||
@ -37,20 +43,46 @@ class MallTVIE(InfoExtractor):
|
|||||||
webpage = self._download_webpage(
|
webpage = self._download_webpage(
|
||||||
url, display_id, headers=self.geo_verification_headers())
|
url, display_id, headers=self.geo_verification_headers())
|
||||||
|
|
||||||
SOURCE_RE = r'(<source[^>]+\bsrc=(?:(["\'])(?:(?!\2).)+|[^\s]+)/(?P<id>[\da-z]+)/index)\b'
|
video = self._parse_json(self._search_regex(
|
||||||
|
r'videoObject\s*=\s*JSON\.parse\(JSON\.stringify\(({.+?})\)\);',
|
||||||
|
webpage, 'video object'), display_id)
|
||||||
|
video_source = video['VideoSource']
|
||||||
video_id = self._search_regex(
|
video_id = self._search_regex(
|
||||||
SOURCE_RE, webpage, 'video id', group='id')
|
r'/([\da-z]+)/index\b', video_source, 'video id')
|
||||||
|
|
||||||
media = self._parse_html5_media_entries(
|
formats = self._extract_m3u8_formats(
|
||||||
url, re.sub(SOURCE_RE, r'\1.m3u8', webpage), video_id,
|
video_source + '.m3u8', video_id, 'mp4', 'm3u8_native')
|
||||||
m3u8_id='hls', m3u8_entry_protocol='m3u8_native')[0]
|
self._sort_formats(formats)
|
||||||
|
|
||||||
|
subtitles = {}
|
||||||
|
for s in (video.get('Subtitles') or {}):
|
||||||
|
s_url = s.get('Url')
|
||||||
|
if not s_url:
|
||||||
|
continue
|
||||||
|
subtitles.setdefault(s.get('Language') or 'cz', []).append({
|
||||||
|
'url': s_url,
|
||||||
|
})
|
||||||
|
|
||||||
|
entity_counts = video.get('EntityCounts') or {}
|
||||||
|
|
||||||
|
def get_count(k):
|
||||||
|
v = entity_counts.get(k + 's') or {}
|
||||||
|
return int_or_none(dict_get(v, ('Count', 'StrCount')))
|
||||||
|
|
||||||
info = self._search_json_ld(webpage, video_id, default={})
|
info = self._search_json_ld(webpage, video_id, default={})
|
||||||
|
|
||||||
return merge_dicts(media, info, {
|
return merge_dicts({
|
||||||
'id': video_id,
|
'id': video_id,
|
||||||
'display_id': display_id,
|
'display_id': display_id,
|
||||||
'title': self._og_search_title(webpage, default=None) or display_id,
|
'title': video.get('Title'),
|
||||||
'description': self._og_search_description(webpage, default=None),
|
'description': clean_html(video.get('Description')),
|
||||||
'thumbnail': self._og_search_thumbnail(webpage, default=None),
|
'thumbnail': video.get('ThumbnailUrl'),
|
||||||
})
|
'formats': formats,
|
||||||
|
'subtitles': subtitles,
|
||||||
|
'duration': int_or_none(video.get('DurationSeconds')) or parse_duration(video.get('Duration')),
|
||||||
|
'view_count': get_count('View'),
|
||||||
|
'like_count': get_count('Like'),
|
||||||
|
'dislike_count': get_count('Dislike'),
|
||||||
|
'average_rating': float_or_none(try_get(video, lambda x: x['EntityRating']['AvarageRate'])),
|
||||||
|
'comment_count': get_count('Comment'),
|
||||||
|
}, info)
|
||||||
|
@ -1,159 +1,54 @@
|
|||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import re
|
|
||||||
|
|
||||||
from .common import InfoExtractor
|
from .common import InfoExtractor
|
||||||
from .nexx import (
|
from .jwplatform import JWPlatformIE
|
||||||
NexxIE,
|
|
||||||
NexxEmbedIE,
|
|
||||||
)
|
|
||||||
from .spiegeltv import SpiegeltvIE
|
|
||||||
from ..compat import compat_urlparse
|
|
||||||
from ..utils import (
|
|
||||||
parse_duration,
|
|
||||||
strip_or_none,
|
|
||||||
unified_timestamp,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SpiegelIE(InfoExtractor):
|
class SpiegelIE(InfoExtractor):
|
||||||
_VALID_URL = r'https?://(?:www\.)?spiegel\.de/video/[^/]*-(?P<id>[0-9]+)(?:-embed|-iframe)?(?:\.html)?(?:#.*)?$'
|
_UUID_RE = r'[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}'
|
||||||
|
_VALID_URL = r'https?://(?:www\.)?(?:spiegel|manager-magazin)\.de(?:/[^/]+)+/[^/]*-(?P<id>[0-9]+|%s)(?:-embed|-iframe)?(?:\.html)?(?:#.*)?$' % _UUID_RE
|
||||||
_TESTS = [{
|
_TESTS = [{
|
||||||
'url': 'http://www.spiegel.de/video/vulkan-tungurahua-in-ecuador-ist-wieder-aktiv-video-1259285.html',
|
'url': 'http://www.spiegel.de/video/vulkan-tungurahua-in-ecuador-ist-wieder-aktiv-video-1259285.html',
|
||||||
'md5': 'b57399839d055fccfeb9a0455c439868',
|
'md5': '50c7948883ec85a3e431a0a44b7ad1d6',
|
||||||
'info_dict': {
|
'info_dict': {
|
||||||
'id': '563747',
|
'id': 'II0BUyxY',
|
||||||
|
'display_id': '1259285',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'title': 'Vulkanausbruch in Ecuador: Der "Feuerschlund" ist wieder aktiv',
|
'title': 'Vulkan Tungurahua in Ecuador ist wieder aktiv - DER SPIEGEL - Wissenschaft',
|
||||||
'description': 'md5:8029d8310232196eb235d27575a8b9f4',
|
'description': 'md5:8029d8310232196eb235d27575a8b9f4',
|
||||||
'duration': 49,
|
'duration': 48.0,
|
||||||
'upload_date': '20130311',
|
'upload_date': '20130311',
|
||||||
'timestamp': 1362994320,
|
'timestamp': 1362997920,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
'url': 'http://www.spiegel.de/video/schach-wm-videoanalyse-des-fuenften-spiels-video-1309159.html',
|
'url': 'http://www.spiegel.de/video/schach-wm-videoanalyse-des-fuenften-spiels-video-1309159.html',
|
||||||
'md5': '5b6c2f4add9d62912ed5fc78a1faed80',
|
|
||||||
'info_dict': {
|
|
||||||
'id': '580988',
|
|
||||||
'ext': 'mp4',
|
|
||||||
'title': 'Schach-WM in der Videoanalyse: Carlsen nutzt die Fehlgriffe des Titelverteidigers',
|
|
||||||
'description': 'md5:c2322b65e58f385a820c10fa03b2d088',
|
|
||||||
'duration': 983,
|
|
||||||
'upload_date': '20131115',
|
|
||||||
'timestamp': 1384546642,
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
'url': 'http://www.spiegel.de/video/astronaut-alexander-gerst-von-der-iss-station-beantwortet-fragen-video-1519126-embed.html',
|
|
||||||
'md5': '97b91083a672d72976faa8433430afb9',
|
|
||||||
'info_dict': {
|
|
||||||
'id': '601883',
|
|
||||||
'ext': 'mp4',
|
|
||||||
'description': 'SPIEGEL ONLINE-Nutzer durften den deutschen Astronauten Alexander Gerst über sein Leben auf der ISS-Station befragen. Hier kommen seine Antworten auf die besten sechs Fragen.',
|
|
||||||
'title': 'Fragen an Astronaut Alexander Gerst: "Bekommen Sie die Tageszeiten mit?"',
|
|
||||||
'upload_date': '20140904',
|
|
||||||
'timestamp': 1409834160,
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
'url': 'http://www.spiegel.de/video/astronaut-alexander-gerst-von-der-iss-station-beantwortet-fragen-video-1519126-iframe.html',
|
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
}, {
|
}, {
|
||||||
# nexx video
|
'url': 'https://www.spiegel.de/video/eifel-zoo-aufregung-um-ausgebrochene-raubtiere-video-99018031.html',
|
||||||
|
'only_matching': True,
|
||||||
|
}, {
|
||||||
|
'url': 'https://www.spiegel.de/panorama/urteile-im-goldmuenzenprozess-haftstrafen-fuer-clanmitglieder-a-aae8df48-43c1-4c61-867d-23f0a2d254b7',
|
||||||
|
'only_matching': True,
|
||||||
|
}, {
|
||||||
'url': 'http://www.spiegel.de/video/spiegel-tv-magazin-ueber-guellekrise-in-schleswig-holstein-video-99012776.html',
|
'url': 'http://www.spiegel.de/video/spiegel-tv-magazin-ueber-guellekrise-in-schleswig-holstein-video-99012776.html',
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
}]
|
}, {
|
||||||
|
|
||||||
def _real_extract(self, url):
|
|
||||||
video_id = self._match_id(url)
|
|
||||||
metadata_url = 'http://www.spiegel.de/video/metadata/video-%s.json' % video_id
|
|
||||||
handle = self._request_webpage(metadata_url, video_id)
|
|
||||||
|
|
||||||
# 302 to spiegel.tv, like http://www.spiegel.de/video/der-film-zum-wochenende-die-wahrheit-ueber-maenner-video-99003272.html
|
|
||||||
if SpiegeltvIE.suitable(handle.geturl()):
|
|
||||||
return self.url_result(handle.geturl(), 'Spiegeltv')
|
|
||||||
|
|
||||||
video_data = self._parse_json(self._webpage_read_content(
|
|
||||||
handle, metadata_url, video_id), video_id)
|
|
||||||
title = video_data['title']
|
|
||||||
nexx_id = video_data['nexxOmniaId']
|
|
||||||
domain_id = video_data.get('nexxOmniaDomain') or '748'
|
|
||||||
|
|
||||||
return {
|
|
||||||
'_type': 'url_transparent',
|
|
||||||
'id': video_id,
|
|
||||||
'url': 'nexx:%s:%s' % (domain_id, nexx_id),
|
|
||||||
'title': title,
|
|
||||||
'description': strip_or_none(video_data.get('teaser')),
|
|
||||||
'duration': parse_duration(video_data.get('duration')),
|
|
||||||
'timestamp': unified_timestamp(video_data.get('datum')),
|
|
||||||
'ie_key': NexxIE.ie_key(),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class SpiegelArticleIE(InfoExtractor):
|
|
||||||
_VALID_URL = r'https?://(?:www\.)?spiegel\.de/(?!video/)[^?#]*?-(?P<id>[0-9]+)\.html'
|
|
||||||
IE_NAME = 'Spiegel:Article'
|
|
||||||
IE_DESC = 'Articles on spiegel.de'
|
|
||||||
_TESTS = [{
|
|
||||||
'url': 'http://www.spiegel.de/sport/sonst/badminton-wm-die-randsportart-soll-populaerer-werden-a-987092.html',
|
'url': 'http://www.spiegel.de/sport/sonst/badminton-wm-die-randsportart-soll-populaerer-werden-a-987092.html',
|
||||||
'info_dict': {
|
'only_matching': True,
|
||||||
'id': '1516455',
|
|
||||||
'ext': 'mp4',
|
|
||||||
'title': 'Faszination Badminton: Nennt es bloß nicht Federball',
|
|
||||||
'description': 're:^Patrick Kämnitz gehört.{100,}',
|
|
||||||
'upload_date': '20140825',
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
'url': 'http://www.spiegel.de/wissenschaft/weltall/astronaut-alexander-gerst-antwortet-spiegel-online-lesern-a-989876.html',
|
|
||||||
'info_dict': {
|
|
||||||
|
|
||||||
},
|
|
||||||
'playlist_count': 6,
|
|
||||||
}, {
|
|
||||||
# Nexx iFrame embed
|
|
||||||
'url': 'http://www.spiegel.de/sptv/spiegeltv/spiegel-tv-ueber-schnellste-katapult-achterbahn-der-welt-taron-a-1137884.html',
|
|
||||||
'info_dict': {
|
|
||||||
'id': '161464',
|
|
||||||
'ext': 'mp4',
|
|
||||||
'title': 'Nervenkitzel Achterbahn',
|
|
||||||
'alt_title': 'Karussellbauer in Deutschland',
|
|
||||||
'description': 'md5:ffe7b1cc59a01f585e0569949aef73cc',
|
|
||||||
'release_year': 2005,
|
|
||||||
'creator': 'SPIEGEL TV',
|
|
||||||
'thumbnail': r're:^https?://.*\.jpg$',
|
|
||||||
'duration': 2761,
|
|
||||||
'timestamp': 1394021479,
|
|
||||||
'upload_date': '20140305',
|
|
||||||
},
|
|
||||||
'params': {
|
|
||||||
'format': 'bestvideo',
|
|
||||||
'skip_download': True,
|
|
||||||
},
|
|
||||||
}]
|
}]
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
video_id = self._match_id(url)
|
video_id = self._match_id(url)
|
||||||
webpage = self._download_webpage(url, video_id)
|
webpage = self._download_webpage(url, video_id)
|
||||||
|
media_id = self._html_search_regex(
|
||||||
# Single video on top of the page
|
r'("|["\'])mediaId\1\s*:\s*("|["\'])(?P<id>(?:(?!\2).)+)\2',
|
||||||
video_link = self._search_regex(
|
webpage, 'media id', group='id')
|
||||||
r'<a href="([^"]+)" onclick="return spOpenVideo\(this,', webpage,
|
return {
|
||||||
'video page URL', default=None)
|
'_type': 'url_transparent',
|
||||||
if video_link:
|
'id': video_id,
|
||||||
video_url = compat_urlparse.urljoin(
|
'display_id': video_id,
|
||||||
self.http_scheme() + '//spiegel.de/', video_link)
|
'url': 'jwplatform:%s' % media_id,
|
||||||
return self.url_result(video_url)
|
'title': self._og_search_title(webpage, default=None),
|
||||||
|
'ie_key': JWPlatformIE.ie_key(),
|
||||||
# Multiple embedded videos
|
}
|
||||||
embeds = re.findall(
|
|
||||||
r'<div class="vid_holder[0-9]+.*?</div>\s*.*?url\s*=\s*"([^"]+)"',
|
|
||||||
webpage)
|
|
||||||
entries = [
|
|
||||||
self.url_result(compat_urlparse.urljoin(
|
|
||||||
self.http_scheme() + '//spiegel.de/', embed_path))
|
|
||||||
for embed_path in embeds]
|
|
||||||
if embeds:
|
|
||||||
return self.playlist_result(entries)
|
|
||||||
|
|
||||||
return self.playlist_from_matches(
|
|
||||||
NexxEmbedIE._extract_urls(webpage), ie=NexxEmbedIE.ie_key())
|
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from .common import InfoExtractor
|
|
||||||
from .nexx import NexxIE
|
|
||||||
|
|
||||||
|
|
||||||
class SpiegeltvIE(InfoExtractor):
|
|
||||||
_VALID_URL = r'https?://(?:www\.)?spiegel\.tv/videos/(?P<id>\d+)'
|
|
||||||
_TEST = {
|
|
||||||
'url': 'http://www.spiegel.tv/videos/161681-flug-mh370/',
|
|
||||||
'only_matching': True,
|
|
||||||
}
|
|
||||||
|
|
||||||
def _real_extract(self, url):
|
|
||||||
return self.url_result(
|
|
||||||
'https://api.nexx.cloud/v3/748/videos/byid/%s'
|
|
||||||
% self._match_id(url), ie=NexxIE.ie_key())
|
|
@ -45,6 +45,7 @@ from ..utils import (
|
|||||||
unescapeHTML,
|
unescapeHTML,
|
||||||
unified_strdate,
|
unified_strdate,
|
||||||
unsmuggle_url,
|
unsmuggle_url,
|
||||||
|
update_url_query,
|
||||||
uppercase_escape,
|
uppercase_escape,
|
||||||
url_or_none,
|
url_or_none,
|
||||||
urlencode_postdata,
|
urlencode_postdata,
|
||||||
@ -65,7 +66,7 @@ class YoutubeBaseInfoExtractor(InfoExtractor):
|
|||||||
# If True it will raise an error if no login info is provided
|
# If True it will raise an error if no login info is provided
|
||||||
_LOGIN_REQUIRED = False
|
_LOGIN_REQUIRED = False
|
||||||
|
|
||||||
_PLAYLIST_ID_RE = r'(?:PL|LL|EC|UU|FL|RD|UL|TL|PU|OLAK5uy_)[0-9A-Za-z-_]{10,}'
|
_PLAYLIST_ID_RE = r'(?:(?:PL|LL|EC|UU|FL|RD|UL|TL|PU|OLAK5uy_)[0-9A-Za-z-_]{10,}|RDMM)'
|
||||||
|
|
||||||
_YOUTUBE_CLIENT_HEADERS = {
|
_YOUTUBE_CLIENT_HEADERS = {
|
||||||
'x-youtube-client-name': '1',
|
'x-youtube-client-name': '1',
|
||||||
@ -974,10 +975,6 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
'url': 'sJL6WA-aGkQ',
|
'url': 'sJL6WA-aGkQ',
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
'url': 'https://www.youtube.com/watch?v=MuAGGZNfUkU&list=RDMM',
|
|
||||||
'only_matching': True,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
'url': 'https://invidio.us/watch?v=BaW_jenozKc',
|
'url': 'https://invidio.us/watch?v=BaW_jenozKc',
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
@ -2351,7 +2348,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
|
|
||||||
class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
||||||
IE_DESC = 'YouTube.com tab'
|
IE_DESC = 'YouTube.com tab'
|
||||||
_VALID_URL = r'https?://(?:\w+\.)?(?:youtube(?:kids)?\.com|invidio\.us)/(?:(?:channel|c|user)/|playlist\?.*?\blist=)(?P<id>[^/?#&]+)'
|
_VALID_URL = r'https?://(?:\w+\.)?(?:youtube(?:kids)?\.com|invidio\.us)/(?:(?:channel|c|user)/|(?:playlist|watch)\?.*?\blist=)(?P<id>[^/?#&]+)'
|
||||||
IE_NAME = 'youtube:tab'
|
IE_NAME = 'youtube:tab'
|
||||||
|
|
||||||
_TESTS = [{
|
_TESTS = [{
|
||||||
@ -2361,6 +2358,7 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
|||||||
'info_dict': {
|
'info_dict': {
|
||||||
'id': 'UCqj7Cz7revf5maW9g5pgNcg',
|
'id': 'UCqj7Cz7revf5maW9g5pgNcg',
|
||||||
'title': 'Игорь Клейнер - Playlists',
|
'title': 'Игорь Клейнер - Playlists',
|
||||||
|
'description': 'md5:be97ee0f14ee314f1f002cf187166ee2',
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
# playlists, multipage, different order
|
# playlists, multipage, different order
|
||||||
@ -2369,14 +2367,16 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
|||||||
'info_dict': {
|
'info_dict': {
|
||||||
'id': 'UCqj7Cz7revf5maW9g5pgNcg',
|
'id': 'UCqj7Cz7revf5maW9g5pgNcg',
|
||||||
'title': 'Игорь Клейнер - Playlists',
|
'title': 'Игорь Клейнер - Playlists',
|
||||||
|
'description': 'md5:be97ee0f14ee314f1f002cf187166ee2',
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
# playlists, singlepage
|
# playlists, singlepage
|
||||||
'url': 'https://www.youtube.com/user/ThirstForScience/playlists',
|
'url': 'https://www.youtube.com/user/ThirstForScience/playlists',
|
||||||
'playlist_mincount': 4,
|
'playlist_mincount': 4,
|
||||||
'info_dict': {
|
'info_dict': {
|
||||||
'id': 'ThirstForScience',
|
'id': 'UCAEtajcuhQ6an9WEzY9LEMQ',
|
||||||
'title': 'ThirstForScience',
|
'title': 'ThirstForScience - Playlists',
|
||||||
|
'description': 'md5:609399d937ea957b0f53cbffb747a14c',
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
'url': 'https://www.youtube.com/c/ChristophLaimer/playlists',
|
'url': 'https://www.youtube.com/c/ChristophLaimer/playlists',
|
||||||
@ -2407,6 +2407,7 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
|||||||
'info_dict': {
|
'info_dict': {
|
||||||
'id': 'UCKfVa3S1e4PHvxWcwyMMg8w',
|
'id': 'UCKfVa3S1e4PHvxWcwyMMg8w',
|
||||||
'title': 'lex will - Home',
|
'title': 'lex will - Home',
|
||||||
|
'description': 'md5:2163c5d0ff54ed5f598d6a7e6211e488',
|
||||||
},
|
},
|
||||||
'playlist_mincount': 2,
|
'playlist_mincount': 2,
|
||||||
}, {
|
}, {
|
||||||
@ -2415,6 +2416,7 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
|||||||
'info_dict': {
|
'info_dict': {
|
||||||
'id': 'UCKfVa3S1e4PHvxWcwyMMg8w',
|
'id': 'UCKfVa3S1e4PHvxWcwyMMg8w',
|
||||||
'title': 'lex will - Videos',
|
'title': 'lex will - Videos',
|
||||||
|
'description': 'md5:2163c5d0ff54ed5f598d6a7e6211e488',
|
||||||
},
|
},
|
||||||
'playlist_mincount': 975,
|
'playlist_mincount': 975,
|
||||||
}, {
|
}, {
|
||||||
@ -2423,6 +2425,7 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
|||||||
'info_dict': {
|
'info_dict': {
|
||||||
'id': 'UCKfVa3S1e4PHvxWcwyMMg8w',
|
'id': 'UCKfVa3S1e4PHvxWcwyMMg8w',
|
||||||
'title': 'lex will - Videos',
|
'title': 'lex will - Videos',
|
||||||
|
'description': 'md5:2163c5d0ff54ed5f598d6a7e6211e488',
|
||||||
},
|
},
|
||||||
'playlist_mincount': 199,
|
'playlist_mincount': 199,
|
||||||
}, {
|
}, {
|
||||||
@ -2431,6 +2434,7 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
|||||||
'info_dict': {
|
'info_dict': {
|
||||||
'id': 'UCKfVa3S1e4PHvxWcwyMMg8w',
|
'id': 'UCKfVa3S1e4PHvxWcwyMMg8w',
|
||||||
'title': 'lex will - Playlists',
|
'title': 'lex will - Playlists',
|
||||||
|
'description': 'md5:2163c5d0ff54ed5f598d6a7e6211e488',
|
||||||
},
|
},
|
||||||
'playlist_mincount': 17,
|
'playlist_mincount': 17,
|
||||||
}, {
|
}, {
|
||||||
@ -2439,6 +2443,7 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
|||||||
'info_dict': {
|
'info_dict': {
|
||||||
'id': 'UCKfVa3S1e4PHvxWcwyMMg8w',
|
'id': 'UCKfVa3S1e4PHvxWcwyMMg8w',
|
||||||
'title': 'lex will - Community',
|
'title': 'lex will - Community',
|
||||||
|
'description': 'md5:2163c5d0ff54ed5f598d6a7e6211e488',
|
||||||
},
|
},
|
||||||
'playlist_mincount': 18,
|
'playlist_mincount': 18,
|
||||||
}, {
|
}, {
|
||||||
@ -2447,6 +2452,7 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
|||||||
'info_dict': {
|
'info_dict': {
|
||||||
'id': 'UCKfVa3S1e4PHvxWcwyMMg8w',
|
'id': 'UCKfVa3S1e4PHvxWcwyMMg8w',
|
||||||
'title': 'lex will - Channels',
|
'title': 'lex will - Channels',
|
||||||
|
'description': 'md5:2163c5d0ff54ed5f598d6a7e6211e488',
|
||||||
},
|
},
|
||||||
'playlist_mincount': 138,
|
'playlist_mincount': 138,
|
||||||
}, {
|
}, {
|
||||||
@ -2465,7 +2471,7 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
|||||||
'title': '29C3: Not my department',
|
'title': '29C3: Not my department',
|
||||||
'id': 'PLwP_SiAcdui0KVebT0mU9Apz359a4ubsC',
|
'id': 'PLwP_SiAcdui0KVebT0mU9Apz359a4ubsC',
|
||||||
'uploader': 'Christiaan008',
|
'uploader': 'Christiaan008',
|
||||||
'uploader_id': 'ChRiStIaAn008',
|
'uploader_id': 'UCEPzS1rYsrkqzSLNp76nrcg',
|
||||||
},
|
},
|
||||||
'playlist_count': 96,
|
'playlist_count': 96,
|
||||||
}, {
|
}, {
|
||||||
@ -2475,7 +2481,7 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
|||||||
'title': 'Uploads from Cauchemar',
|
'title': 'Uploads from Cauchemar',
|
||||||
'id': 'UUBABnxM4Ar9ten8Mdjj1j0Q',
|
'id': 'UUBABnxM4Ar9ten8Mdjj1j0Q',
|
||||||
'uploader': 'Cauchemar',
|
'uploader': 'Cauchemar',
|
||||||
'uploader_id': 'Cauchemar89',
|
'uploader_id': 'UCBABnxM4Ar9ten8Mdjj1j0Q',
|
||||||
},
|
},
|
||||||
'playlist_mincount': 1123,
|
'playlist_mincount': 1123,
|
||||||
}, {
|
}, {
|
||||||
@ -2489,7 +2495,7 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
|||||||
'title': 'Uploads from Interstellar Movie',
|
'title': 'Uploads from Interstellar Movie',
|
||||||
'id': 'UUXw-G3eDE9trcvY2sBMM_aA',
|
'id': 'UUXw-G3eDE9trcvY2sBMM_aA',
|
||||||
'uploader': 'Interstellar Movie',
|
'uploader': 'Interstellar Movie',
|
||||||
'uploader_id': 'InterstellarMovie1',
|
'uploader_id': 'UCXw-G3eDE9trcvY2sBMM_aA',
|
||||||
},
|
},
|
||||||
'playlist_mincount': 21,
|
'playlist_mincount': 21,
|
||||||
}, {
|
}, {
|
||||||
@ -2498,13 +2504,43 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
|||||||
'info_dict': {
|
'info_dict': {
|
||||||
'title': 'Data Analysis with Dr Mike Pound',
|
'title': 'Data Analysis with Dr Mike Pound',
|
||||||
'id': 'PLzH6n4zXuckpfMu_4Ff8E7Z1behQks5ba',
|
'id': 'PLzH6n4zXuckpfMu_4Ff8E7Z1behQks5ba',
|
||||||
'uploader_id': 'Computerphile',
|
'uploader_id': 'UC9-y-6csu5WGm29I7JiwpnA',
|
||||||
'uploader': 'Computerphile',
|
'uploader': 'Computerphile',
|
||||||
},
|
},
|
||||||
'playlist_mincount': 11,
|
'playlist_mincount': 11,
|
||||||
}, {
|
}, {
|
||||||
'url': 'https://invidio.us/playlist?list=PLDIoUOhQQPlXr63I_vwF9GD8sAKh77dWU',
|
'url': 'https://invidio.us/playlist?list=PLDIoUOhQQPlXr63I_vwF9GD8sAKh77dWU',
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
|
}, {
|
||||||
|
# Playlist URL that does not actually serve a playlist
|
||||||
|
'url': 'https://www.youtube.com/watch?v=FqZTN594JQw&list=PLMYEtVRpaqY00V9W81Cwmzp6N6vZqfUKD4',
|
||||||
|
'info_dict': {
|
||||||
|
'id': 'FqZTN594JQw',
|
||||||
|
'ext': 'webm',
|
||||||
|
'title': "Smiley's People 01 detective, Adventure Series, Action",
|
||||||
|
'uploader': 'STREEM',
|
||||||
|
'uploader_id': 'UCyPhqAZgwYWZfxElWVbVJng',
|
||||||
|
'uploader_url': r're:https?://(?:www\.)?youtube\.com/channel/UCyPhqAZgwYWZfxElWVbVJng',
|
||||||
|
'upload_date': '20150526',
|
||||||
|
'license': 'Standard YouTube License',
|
||||||
|
'description': 'md5:507cdcb5a49ac0da37a920ece610be80',
|
||||||
|
'categories': ['People & Blogs'],
|
||||||
|
'tags': list,
|
||||||
|
'view_count': int,
|
||||||
|
'like_count': int,
|
||||||
|
'dislike_count': int,
|
||||||
|
},
|
||||||
|
'params': {
|
||||||
|
'skip_download': True,
|
||||||
|
},
|
||||||
|
'skip': 'This video is not available.',
|
||||||
|
'add_ie': [YoutubeIE.ie_key()],
|
||||||
|
}, {
|
||||||
|
'url': 'https://www.youtubekids.com/watch?v=Agk7R8I8o5U&list=PUZ6jURNr1WQZCNHF0ao-c0g',
|
||||||
|
'only_matching': True,
|
||||||
|
}, {
|
||||||
|
'url': 'https://www.youtube.com/watch?v=MuAGGZNfUkU&list=RDMM',
|
||||||
|
'only_matching': True,
|
||||||
}]
|
}]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -2535,7 +2571,9 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
|||||||
def _extract_video(self, renderer):
|
def _extract_video(self, renderer):
|
||||||
video_id = renderer.get('videoId')
|
video_id = renderer.get('videoId')
|
||||||
title = try_get(
|
title = try_get(
|
||||||
renderer, lambda x: x['title']['runs'][0]['text'], compat_str)
|
renderer,
|
||||||
|
(lambda x: x['title']['runs'][0]['text'],
|
||||||
|
lambda x: x['title']['simpleText']), compat_str)
|
||||||
description = try_get(
|
description = try_get(
|
||||||
renderer, lambda x: x['descriptionSnippet']['runs'][0]['text'],
|
renderer, lambda x: x['descriptionSnippet']['runs'][0]['text'],
|
||||||
compat_str)
|
compat_str)
|
||||||
@ -2543,8 +2581,8 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
|||||||
renderer, lambda x: x['lengthText']['simpleText'], compat_str))
|
renderer, lambda x: x['lengthText']['simpleText'], compat_str))
|
||||||
view_count_text = try_get(
|
view_count_text = try_get(
|
||||||
renderer, lambda x: x['viewCountText']['simpleText'], compat_str) or ''
|
renderer, lambda x: x['viewCountText']['simpleText'], compat_str) or ''
|
||||||
view_count = int_or_none(self._search_regex(
|
view_count = str_to_int(self._search_regex(
|
||||||
r'^(\d+)', re.sub(r'\s', '', view_count_text),
|
r'^([\d,]+)', re.sub(r'\s', '', view_count_text),
|
||||||
'view count', default=None))
|
'view count', default=None))
|
||||||
uploader = try_get(
|
uploader = try_get(
|
||||||
renderer, lambda x: x['ownerText']['runs'][0]['text'], compat_str)
|
renderer, lambda x: x['ownerText']['runs'][0]['text'], compat_str)
|
||||||
@ -2615,7 +2653,7 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
|||||||
for content in video_list_renderer['contents']:
|
for content in video_list_renderer['contents']:
|
||||||
if not isinstance(content, dict):
|
if not isinstance(content, dict):
|
||||||
continue
|
continue
|
||||||
renderer = content.get('playlistVideoRenderer')
|
renderer = content.get('playlistVideoRenderer') or content.get('playlistPanelVideoRenderer')
|
||||||
if not isinstance(renderer, dict):
|
if not isinstance(renderer, dict):
|
||||||
continue
|
continue
|
||||||
video_id = renderer.get('videoId')
|
video_id = renderer.get('videoId')
|
||||||
@ -2715,7 +2753,7 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
|||||||
|
|
||||||
def _entries(self, tab, identity_token):
|
def _entries(self, tab, identity_token):
|
||||||
continuation = None
|
continuation = None
|
||||||
slr_contents = tab['sectionListRenderer']['contents']
|
slr_contents = try_get(tab, lambda x: x['sectionListRenderer']['contents'], list) or []
|
||||||
for slr_content in slr_contents:
|
for slr_content in slr_contents:
|
||||||
if not isinstance(slr_content, dict):
|
if not isinstance(slr_content, dict):
|
||||||
continue
|
continue
|
||||||
@ -2824,13 +2862,30 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
|||||||
else:
|
else:
|
||||||
raise ExtractorError('Unable to find selected tab')
|
raise ExtractorError('Unable to find selected tab')
|
||||||
|
|
||||||
def _real_extract(self, url):
|
@staticmethod
|
||||||
item_id = self._match_id(url)
|
def _extract_uploader(data):
|
||||||
url = compat_urlparse.urlunparse(
|
uploader = {}
|
||||||
compat_urlparse.urlparse(url)._replace(netloc='www.youtube.com'))
|
sidebar_renderer = try_get(
|
||||||
webpage = self._download_webpage(url, item_id)
|
data, lambda x: x['sidebar']['playlistSidebarRenderer']['items'], list)
|
||||||
data = self._extract_yt_initial_data(item_id, webpage)
|
if sidebar_renderer:
|
||||||
tabs = data['contents']['twoColumnBrowseResultsRenderer']['tabs']
|
for item in sidebar_renderer:
|
||||||
|
if not isinstance(item, dict):
|
||||||
|
continue
|
||||||
|
renderer = item.get('playlistSidebarSecondaryInfoRenderer')
|
||||||
|
if not isinstance(renderer, dict):
|
||||||
|
continue
|
||||||
|
owner = try_get(
|
||||||
|
renderer, lambda x: x['videoOwner']['videoOwnerRenderer']['title']['runs'][0], dict)
|
||||||
|
if owner:
|
||||||
|
uploader['uploader'] = owner.get('text')
|
||||||
|
uploader['uploader_id'] = try_get(
|
||||||
|
owner, lambda x: x['navigationEndpoint']['browseEndpoint']['browseId'], compat_str)
|
||||||
|
uploader['uploader_url'] = urljoin(
|
||||||
|
'https://www.youtube.com/',
|
||||||
|
try_get(owner, lambda x: x['navigationEndpoint']['browseEndpoint']['canonicalBaseUrl'], compat_str))
|
||||||
|
return uploader
|
||||||
|
|
||||||
|
def _extract_from_tabs(self, item_id, webpage, data, tabs, identity_token):
|
||||||
selected_tab = self._extract_selected_tab(tabs)
|
selected_tab = self._extract_selected_tab(tabs)
|
||||||
renderer = try_get(
|
renderer = try_get(
|
||||||
data, lambda x: x['metadata']['channelMetadataRenderer'], dict)
|
data, lambda x: x['metadata']['channelMetadataRenderer'], dict)
|
||||||
@ -2848,42 +2903,69 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
|||||||
title = renderer.get('title')
|
title = renderer.get('title')
|
||||||
description = None
|
description = None
|
||||||
playlist_id = item_id
|
playlist_id = item_id
|
||||||
identity_token = self._search_regex(
|
playlist = self.playlist_result(
|
||||||
r'\bID_TOKEN["\']\s*:\s*["\'](.+?)["\']', webpage,
|
|
||||||
'identity token', default=None)
|
|
||||||
return self.playlist_result(
|
|
||||||
self._entries(selected_tab['content'], identity_token),
|
self._entries(selected_tab['content'], identity_token),
|
||||||
playlist_id=playlist_id, playlist_title=title,
|
playlist_id=playlist_id, playlist_title=title,
|
||||||
playlist_description=description)
|
playlist_description=description)
|
||||||
|
playlist.update(self._extract_uploader(data))
|
||||||
|
return playlist
|
||||||
|
|
||||||
|
def _extract_from_playlist(self, item_id, data, playlist):
|
||||||
|
title = playlist.get('title') or try_get(
|
||||||
|
data, lambda x: x['titleText']['simpleText'], compat_str)
|
||||||
|
playlist_id = playlist.get('playlistId') or item_id
|
||||||
|
return self.playlist_result(
|
||||||
|
self._playlist_entries(playlist), playlist_id=playlist_id,
|
||||||
|
playlist_title=title)
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
item_id = self._match_id(url)
|
||||||
|
url = compat_urlparse.urlunparse(
|
||||||
|
compat_urlparse.urlparse(url)._replace(netloc='www.youtube.com'))
|
||||||
|
# Handle both video/playlist URLs
|
||||||
|
qs = compat_urlparse.parse_qs(compat_urlparse.urlparse(url).query)
|
||||||
|
video_id = qs.get('v', [None])[0]
|
||||||
|
playlist_id = qs.get('list', [None])[0]
|
||||||
|
if video_id and playlist_id:
|
||||||
|
if self._downloader.params.get('noplaylist'):
|
||||||
|
self.to_screen('Downloading just video %s because of --no-playlist' % video_id)
|
||||||
|
return self.url_result(video_id, ie=YoutubeIE.ie_key(), video_id=video_id)
|
||||||
|
self.to_screen('Downloading playlist %s - add --no-playlist to just download video %s' % (playlist_id, video_id))
|
||||||
|
webpage = self._download_webpage(url, item_id)
|
||||||
|
identity_token = self._search_regex(
|
||||||
|
r'\bID_TOKEN["\']\s*:\s*["\'](.+?)["\']', webpage,
|
||||||
|
'identity token', default=None)
|
||||||
|
data = self._extract_yt_initial_data(item_id, webpage)
|
||||||
|
tabs = try_get(
|
||||||
|
data, lambda x: x['contents']['twoColumnBrowseResultsRenderer']['tabs'], list)
|
||||||
|
if tabs:
|
||||||
|
return self._extract_from_tabs(item_id, webpage, data, tabs, identity_token)
|
||||||
|
playlist = try_get(
|
||||||
|
data, lambda x: x['contents']['twoColumnWatchNextResults']['playlist']['playlist'], dict)
|
||||||
|
if playlist:
|
||||||
|
return self._extract_from_playlist(item_id, data, playlist)
|
||||||
|
# Fallback to video extraction if no playlist alike page is recognized
|
||||||
|
if video_id:
|
||||||
|
return self.url_result(video_id, ie=YoutubeIE.ie_key(), video_id=video_id)
|
||||||
|
# Failed to recognize
|
||||||
|
raise ExtractorError('Unable to recognize tab page')
|
||||||
|
|
||||||
|
|
||||||
class YoutubePlaylistIE(InfoExtractor):
|
class YoutubePlaylistIE(InfoExtractor):
|
||||||
IE_DESC = 'YouTube.com playlists'
|
IE_DESC = 'YouTube.com playlists'
|
||||||
_VALID_URL = r"""(?x)(?:
|
_VALID_URL = r'''(?x)(?:
|
||||||
(?:https?://)?
|
(?:https?://)?
|
||||||
(?:\w+\.)?
|
(?:\w+\.)?
|
||||||
(?:
|
(?:
|
||||||
(?:
|
(?:
|
||||||
youtube(?:kids)?\.com|
|
youtube(?:kids)?\.com|
|
||||||
invidio\.us
|
invidio\.us|
|
||||||
|
youtu\.be
|
||||||
)
|
)
|
||||||
/
|
/.*?\?.*?\blist=
|
||||||
(?:
|
)?
|
||||||
(?:course|view_play_list|my_playlists|artist|playlist|watch|embed/(?:videoseries|[0-9A-Za-z_-]{11}))
|
(?P<id>%(playlist_id)s)
|
||||||
\? (?:.*?[&;])*? (?:p|a|list)=
|
)''' % {'playlist_id': YoutubeBaseInfoExtractor._PLAYLIST_ID_RE}
|
||||||
| p/
|
|
||||||
)|
|
|
||||||
youtu\.be/[0-9A-Za-z_-]{11}\?.*?\blist=
|
|
||||||
)
|
|
||||||
(
|
|
||||||
(?:PL|LL|EC|UU|FL|RD|UL|TL|PU|OLAK5uy_)?[0-9A-Za-z-_]{10,}
|
|
||||||
# Top tracks, they can also include dots
|
|
||||||
|(?:MC)[\w\.]*
|
|
||||||
)
|
|
||||||
.*
|
|
||||||
|
|
|
||||||
(%(playlist_id)s)
|
|
||||||
)""" % {'playlist_id': YoutubeBaseInfoExtractor._PLAYLIST_ID_RE}
|
|
||||||
IE_NAME = 'youtube:playlist'
|
IE_NAME = 'youtube:playlist'
|
||||||
_TESTS = [{
|
_TESTS = [{
|
||||||
'note': 'issue #673',
|
'note': 'issue #673',
|
||||||
@ -2892,7 +2974,7 @@ class YoutubePlaylistIE(InfoExtractor):
|
|||||||
'title': '[OLD]Team Fortress 2 (Class-based LP)',
|
'title': '[OLD]Team Fortress 2 (Class-based LP)',
|
||||||
'id': 'PLBB231211A4F62143',
|
'id': 'PLBB231211A4F62143',
|
||||||
'uploader': 'Wickydoo',
|
'uploader': 'Wickydoo',
|
||||||
'uploader_id': 'Wickydoo',
|
'uploader_id': 'UCKSpbfbl5kRQpTdL7kMc-1Q',
|
||||||
},
|
},
|
||||||
'playlist_mincount': 29,
|
'playlist_mincount': 29,
|
||||||
}, {
|
}, {
|
||||||
@ -2920,41 +3002,8 @@ class YoutubePlaylistIE(InfoExtractor):
|
|||||||
'title': '2018 Chinese New Singles (11/6 updated)',
|
'title': '2018 Chinese New Singles (11/6 updated)',
|
||||||
'id': 'PLsyOSbh5bs16vubvKePAQ1x3PhKavfBIl',
|
'id': 'PLsyOSbh5bs16vubvKePAQ1x3PhKavfBIl',
|
||||||
'uploader': 'LBK',
|
'uploader': 'LBK',
|
||||||
'uploader_id': 'sdragonfang',
|
'uploader_id': 'UC21nz3_MesPLqtDqwdvnoxA',
|
||||||
}
|
}
|
||||||
}, {
|
|
||||||
'note': 'Embedded SWF player',
|
|
||||||
'url': 'https://www.youtube.com/p/YN5VISEtHet5D4NEvfTd0zcgFk84NqFZ?hl=en_US&fs=1&rel=0',
|
|
||||||
'playlist_count': 4,
|
|
||||||
'info_dict': {
|
|
||||||
'title': 'JODA7',
|
|
||||||
'id': 'YN5VISEtHet5D4NEvfTd0zcgFk84NqFZ',
|
|
||||||
},
|
|
||||||
'skip': 'This playlist does not exist',
|
|
||||||
}, {
|
|
||||||
# Playlist URL that does not actually serve a playlist
|
|
||||||
'url': 'https://www.youtube.com/watch?v=FqZTN594JQw&list=PLMYEtVRpaqY00V9W81Cwmzp6N6vZqfUKD4',
|
|
||||||
'info_dict': {
|
|
||||||
'id': 'FqZTN594JQw',
|
|
||||||
'ext': 'webm',
|
|
||||||
'title': "Smiley's People 01 detective, Adventure Series, Action",
|
|
||||||
'uploader': 'STREEM',
|
|
||||||
'uploader_id': 'UCyPhqAZgwYWZfxElWVbVJng',
|
|
||||||
'uploader_url': r're:https?://(?:www\.)?youtube\.com/channel/UCyPhqAZgwYWZfxElWVbVJng',
|
|
||||||
'upload_date': '20150526',
|
|
||||||
'license': 'Standard YouTube License',
|
|
||||||
'description': 'md5:507cdcb5a49ac0da37a920ece610be80',
|
|
||||||
'categories': ['People & Blogs'],
|
|
||||||
'tags': list,
|
|
||||||
'view_count': int,
|
|
||||||
'like_count': int,
|
|
||||||
'dislike_count': int,
|
|
||||||
},
|
|
||||||
'params': {
|
|
||||||
'skip_download': True,
|
|
||||||
},
|
|
||||||
'skip': 'This video is not available.',
|
|
||||||
'add_ie': [YoutubeIE.ie_key()],
|
|
||||||
}, {
|
}, {
|
||||||
'url': 'https://youtu.be/yeWKywCrFtk?list=PL2qgrgXsNUG5ig9cat4ohreBjYLAPC0J5',
|
'url': 'https://youtu.be/yeWKywCrFtk?list=PL2qgrgXsNUG5ig9cat4ohreBjYLAPC0J5',
|
||||||
'info_dict': {
|
'info_dict': {
|
||||||
@ -2985,9 +3034,6 @@ class YoutubePlaylistIE(InfoExtractor):
|
|||||||
# music album playlist
|
# music album playlist
|
||||||
'url': 'OLAK5uy_m4xAFdmMC5rX3Ji3g93pQe3hqLZw_9LhM',
|
'url': 'OLAK5uy_m4xAFdmMC5rX3Ji3g93pQe3hqLZw_9LhM',
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
}, {
|
|
||||||
'url': 'https://www.youtubekids.com/watch?v=Agk7R8I8o5U&list=PUZ6jURNr1WQZCNHF0ao-c0g',
|
|
||||||
'only_matching': True,
|
|
||||||
}]
|
}]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -2996,13 +3042,12 @@ class YoutubePlaylistIE(InfoExtractor):
|
|||||||
YoutubePlaylistIE, cls).suitable(url)
|
YoutubePlaylistIE, cls).suitable(url)
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
# Extract playlist id
|
playlist_id = self._match_id(url)
|
||||||
mobj = re.match(self._VALID_URL, url)
|
qs = compat_urlparse.parse_qs(compat_urlparse.urlparse(url).query)
|
||||||
if mobj is None:
|
if not qs:
|
||||||
raise ExtractorError('Invalid URL: %s' % url)
|
qs = {'list': playlist_id}
|
||||||
playlist_id = mobj.group(1) or mobj.group(2)
|
|
||||||
return self.url_result(
|
return self.url_result(
|
||||||
'https://www.youtube.com/playlist?list=%s' % playlist_id,
|
update_url_query('https://www.youtube.com/playlist', qs),
|
||||||
ie=YoutubeTabIE.ie_key(), video_id=playlist_id)
|
ie=YoutubeTabIE.ie_key(), video_id=playlist_id)
|
||||||
|
|
||||||
|
|
||||||
@ -3250,13 +3295,13 @@ class YoutubeFeedsInfoExtractor(YoutubeBaseInfoExtractor):
|
|||||||
class YoutubeWatchLaterIE(InfoExtractor):
|
class YoutubeWatchLaterIE(InfoExtractor):
|
||||||
IE_NAME = 'youtube:watchlater'
|
IE_NAME = 'youtube:watchlater'
|
||||||
IE_DESC = 'Youtube watch later list, ":ytwatchlater" for short (requires authentication)'
|
IE_DESC = 'Youtube watch later list, ":ytwatchlater" for short (requires authentication)'
|
||||||
_VALID_URL = r'https?://(?:www\.)?youtube\.com/(?:feed/watch_later|(?:playlist|watch)\?(?:.+&)?list=WL)|:ytwatchlater'
|
_VALID_URL = r'https?://(?:www\.)?youtube\.com/feed/watch_later|:ytwatchlater'
|
||||||
|
|
||||||
_TESTS = [{
|
_TESTS = [{
|
||||||
'url': 'https://www.youtube.com/watch?v=bCNU9TrbiRk&index=1&list=WL',
|
'url': 'https://www.youtube.com/feed/watch_later',
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
}, {
|
}, {
|
||||||
'url': 'https://www.youtube.com/feed/watch_later',
|
'url': ':ytwatchlater',
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
}]
|
}]
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
__version__ = '2020.11.17'
|
__version__ = '2020.11.18'
|
||||||
|
Loading…
Reference in New Issue
Block a user