mirror of
https://github.com/ytdl-org/youtube-dl
synced 2025-10-22 08:08:38 +09:00
Compare commits
12 Commits
c706fbe9fe
...
2020.12.31
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4066945919 | ||
![]() |
2a84694b1e | ||
![]() |
4046ffe1e1 | ||
![]() |
d1d0612160 | ||
![]() |
7b0f04ed1f | ||
![]() |
2e21b06ea2 | ||
![]() |
a6f75e6e89 | ||
![]() |
bd18824c2a | ||
![]() |
bdd044e67b | ||
![]() |
f7e95fb2a0 | ||
![]() |
9dd674e1d2 | ||
![]() |
9c1e164e0c |
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.12.29. 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.12.31. 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.12.29**
|
- [ ] I've verified that I'm running youtube-dl version **2020.12.31**
|
||||||
- [ ] 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.12.29
|
[debug] youtube-dl version 2020.12.31
|
||||||
[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.12.29. 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.12.31. 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.12.29**
|
- [ ] I've verified that I'm running youtube-dl version **2020.12.31**
|
||||||
- [ ] 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.12.29. 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.12.31. 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.12.29**
|
- [ ] I've verified that I'm running youtube-dl version **2020.12.31**
|
||||||
- [ ] 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.12.29. 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.12.31. 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.12.29**
|
- [ ] I've verified that I'm running youtube-dl version **2020.12.31**
|
||||||
- [ ] 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.12.29
|
[debug] youtube-dl version 2020.12.31
|
||||||
[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.12.29. 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.12.31. 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.12.29**
|
- [ ] I've verified that I'm running youtube-dl version **2020.12.31**
|
||||||
- [ ] I've searched the bugtracker for similar feature requests including closed ones
|
- [ ] I've searched the bugtracker for similar feature requests including closed ones
|
||||||
|
|
||||||
|
|
||||||
|
23
ChangeLog
23
ChangeLog
@@ -1,3 +1,26 @@
|
|||||||
|
version 2020.12.31
|
||||||
|
|
||||||
|
Core
|
||||||
|
* [utils] Accept only supported protocols in url_or_none
|
||||||
|
* [YoutubeDL] Allow format filtering using audio language (#16209)
|
||||||
|
|
||||||
|
Extractors
|
||||||
|
+ [redditr] Extract all thumbnails (#27503)
|
||||||
|
* [vvvvid] Improve info extraction
|
||||||
|
+ [vvvvid] Add support for playlists (#18130, #27574)
|
||||||
|
+ [yandexdisk] Extract info from webpage
|
||||||
|
* [yandexdisk] Fix extraction (#17861, #27131)
|
||||||
|
* [yandexvideo] Use old API call as fallback
|
||||||
|
* [yandexvideo] Fix extraction (#25000)
|
||||||
|
- [nbc] Remove CSNNE extractor
|
||||||
|
* [nbc] Fix NBCSport VPlayer URL extraction (#16640)
|
||||||
|
+ [aenetworks] Add support for biography.com (#3863)
|
||||||
|
* [uktvplay] Match new video URLs (#17909)
|
||||||
|
* [sevenplay] Detect API errors
|
||||||
|
* [tenplay] Fix format extraction (#26653)
|
||||||
|
* [brightcove] Raise error for DRM protected videos (#23467, #27568)
|
||||||
|
|
||||||
|
|
||||||
version 2020.12.29
|
version 2020.12.29
|
||||||
|
|
||||||
Extractors
|
Extractors
|
||||||
|
@@ -678,6 +678,7 @@ Also filtering work for comparisons `=` (equals), `^=` (starts with), `$=` (ends
|
|||||||
- `container`: Name of the container format
|
- `container`: Name of the container format
|
||||||
- `protocol`: The protocol that will be used for the actual download, lower-case (`http`, `https`, `rtsp`, `rtmp`, `rtmpe`, `mms`, `f4m`, `ism`, `http_dash_segments`, `m3u8`, or `m3u8_native`)
|
- `protocol`: The protocol that will be used for the actual download, lower-case (`http`, `https`, `rtsp`, `rtmp`, `rtmpe`, `mms`, `f4m`, `ism`, `http_dash_segments`, `m3u8`, or `m3u8_native`)
|
||||||
- `format_id`: A short description of the format
|
- `format_id`: A short description of the format
|
||||||
|
- `language`: Language code
|
||||||
|
|
||||||
Any string comparison may be prefixed with negation `!` in order to produce an opposite comparison, e.g. `!*=` (does not contain).
|
Any string comparison may be prefixed with negation `!` in order to produce an opposite comparison, e.g. `!*=` (does not contain).
|
||||||
|
|
||||||
|
@@ -104,6 +104,7 @@
|
|||||||
- **BilibiliAudioAlbum**
|
- **BilibiliAudioAlbum**
|
||||||
- **BiliBiliPlayer**
|
- **BiliBiliPlayer**
|
||||||
- **BioBioChileTV**
|
- **BioBioChileTV**
|
||||||
|
- **Biography**
|
||||||
- **BIQLE**
|
- **BIQLE**
|
||||||
- **BitChute**
|
- **BitChute**
|
||||||
- **BitChuteChannel**
|
- **BitChuteChannel**
|
||||||
@@ -197,7 +198,6 @@
|
|||||||
- **CrooksAndLiars**
|
- **CrooksAndLiars**
|
||||||
- **crunchyroll**
|
- **crunchyroll**
|
||||||
- **crunchyroll:playlist**
|
- **crunchyroll:playlist**
|
||||||
- **CSNNE**
|
|
||||||
- **CSpan**: C-SPAN
|
- **CSpan**: C-SPAN
|
||||||
- **CtsNews**: 華視新聞
|
- **CtsNews**: 華視新聞
|
||||||
- **CTV**
|
- **CTV**
|
||||||
@@ -349,6 +349,7 @@
|
|||||||
- **hgtv.com:show**
|
- **hgtv.com:show**
|
||||||
- **HiDive**
|
- **HiDive**
|
||||||
- **HistoricFilms**
|
- **HistoricFilms**
|
||||||
|
- **history:player**
|
||||||
- **history:topic**: History.com Topic
|
- **history:topic**: History.com Topic
|
||||||
- **hitbox**
|
- **hitbox**
|
||||||
- **hitbox:live**
|
- **hitbox:live**
|
||||||
@@ -1088,6 +1089,7 @@
|
|||||||
- **vube**: Vube.com
|
- **vube**: Vube.com
|
||||||
- **VuClip**
|
- **VuClip**
|
||||||
- **VVVVID**
|
- **VVVVID**
|
||||||
|
- **VVVVIDShow**
|
||||||
- **VyboryMos**
|
- **VyboryMos**
|
||||||
- **Vzaar**
|
- **Vzaar**
|
||||||
- **Wakanim**
|
- **Wakanim**
|
||||||
|
@@ -554,6 +554,11 @@ class TestUtil(unittest.TestCase):
|
|||||||
self.assertEqual(url_or_none('http$://foo.de'), None)
|
self.assertEqual(url_or_none('http$://foo.de'), None)
|
||||||
self.assertEqual(url_or_none('http://foo.de'), 'http://foo.de')
|
self.assertEqual(url_or_none('http://foo.de'), 'http://foo.de')
|
||||||
self.assertEqual(url_or_none('//foo.de'), '//foo.de')
|
self.assertEqual(url_or_none('//foo.de'), '//foo.de')
|
||||||
|
self.assertEqual(url_or_none('s3://foo.de'), None)
|
||||||
|
self.assertEqual(url_or_none('rtmpte://foo.de'), 'rtmpte://foo.de')
|
||||||
|
self.assertEqual(url_or_none('mms://foo.de'), 'mms://foo.de')
|
||||||
|
self.assertEqual(url_or_none('rtspu://foo.de'), 'rtspu://foo.de')
|
||||||
|
self.assertEqual(url_or_none('ftps://foo.de'), 'ftps://foo.de')
|
||||||
|
|
||||||
def test_parse_age_limit(self):
|
def test_parse_age_limit(self):
|
||||||
self.assertEqual(parse_age_limit(None), None)
|
self.assertEqual(parse_age_limit(None), None)
|
||||||
|
@@ -1083,7 +1083,7 @@ class YoutubeDL(object):
|
|||||||
'*=': lambda attr, value: value in attr,
|
'*=': lambda attr, value: value in attr,
|
||||||
}
|
}
|
||||||
str_operator_rex = re.compile(r'''(?x)
|
str_operator_rex = re.compile(r'''(?x)
|
||||||
\s*(?P<key>ext|acodec|vcodec|container|protocol|format_id)
|
\s*(?P<key>ext|acodec|vcodec|container|protocol|format_id|language)
|
||||||
\s*(?P<negation>!\s*)?(?P<op>%s)(?P<none_inclusive>\s*\?)?
|
\s*(?P<negation>!\s*)?(?P<op>%s)(?P<none_inclusive>\s*\?)?
|
||||||
\s*(?P<value>[a-zA-Z0-9._-]+)
|
\s*(?P<value>[a-zA-Z0-9._-]+)
|
||||||
\s*$
|
\s*$
|
||||||
|
@@ -1425,7 +1425,10 @@ from .vshare import VShareIE
|
|||||||
from .medialaan import MedialaanIE
|
from .medialaan import MedialaanIE
|
||||||
from .vube import VubeIE
|
from .vube import VubeIE
|
||||||
from .vuclip import VuClipIE
|
from .vuclip import VuClipIE
|
||||||
from .vvvvid import VVVVIDIE
|
from .vvvvid import (
|
||||||
|
VVVVIDIE,
|
||||||
|
VVVVIDShowIE,
|
||||||
|
)
|
||||||
from .vyborymos import VyboryMosIE
|
from .vyborymos import VyboryMosIE
|
||||||
from .vzaar import VzaarIE
|
from .vzaar import VzaarIE
|
||||||
from .wakanim import WakanimIE
|
from .wakanim import WakanimIE
|
||||||
|
@@ -8,6 +8,7 @@ from ..utils import (
|
|||||||
int_or_none,
|
int_or_none,
|
||||||
float_or_none,
|
float_or_none,
|
||||||
try_get,
|
try_get,
|
||||||
|
unescapeHTML,
|
||||||
url_or_none,
|
url_or_none,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -56,7 +57,8 @@ class RedditRIE(InfoExtractor):
|
|||||||
'id': 'zv89llsvexdz',
|
'id': 'zv89llsvexdz',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'title': 'That small heart attack.',
|
'title': 'That small heart attack.',
|
||||||
'thumbnail': r're:^https?://.*\.jpg$',
|
'thumbnail': r're:^https?://.*\.(?:jpg|png)',
|
||||||
|
'thumbnails': 'count:4',
|
||||||
'timestamp': 1501941939,
|
'timestamp': 1501941939,
|
||||||
'upload_date': '20170805',
|
'upload_date': '20170805',
|
||||||
'uploader': 'Antw87',
|
'uploader': 'Antw87',
|
||||||
@@ -118,11 +120,34 @@ class RedditRIE(InfoExtractor):
|
|||||||
else:
|
else:
|
||||||
age_limit = None
|
age_limit = None
|
||||||
|
|
||||||
|
thumbnails = []
|
||||||
|
|
||||||
|
def add_thumbnail(src):
|
||||||
|
if not isinstance(src, dict):
|
||||||
|
return
|
||||||
|
thumbnail_url = url_or_none(src.get('url'))
|
||||||
|
if not thumbnail_url:
|
||||||
|
return
|
||||||
|
thumbnails.append({
|
||||||
|
'url': unescapeHTML(thumbnail_url),
|
||||||
|
'width': int_or_none(src.get('width')),
|
||||||
|
'height': int_or_none(src.get('height')),
|
||||||
|
})
|
||||||
|
|
||||||
|
for image in try_get(data, lambda x: x['preview']['images']) or []:
|
||||||
|
if not isinstance(image, dict):
|
||||||
|
continue
|
||||||
|
add_thumbnail(image.get('source'))
|
||||||
|
resolutions = image.get('resolutions')
|
||||||
|
if isinstance(resolutions, list):
|
||||||
|
for resolution in resolutions:
|
||||||
|
add_thumbnail(resolution)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'_type': 'url_transparent',
|
'_type': 'url_transparent',
|
||||||
'url': video_url,
|
'url': video_url,
|
||||||
'title': data.get('title'),
|
'title': data.get('title'),
|
||||||
'thumbnail': url_or_none(data.get('thumbnail')),
|
'thumbnails': thumbnails,
|
||||||
'timestamp': float_or_none(data.get('created_utc')),
|
'timestamp': float_or_none(data.get('created_utc')),
|
||||||
'uploader': data.get('author'),
|
'uploader': data.get('author'),
|
||||||
'duration': int_or_none(try_get(
|
'duration': int_or_none(try_get(
|
||||||
|
@@ -12,7 +12,8 @@ from ..utils import (
|
|||||||
|
|
||||||
|
|
||||||
class VVVVIDIE(InfoExtractor):
|
class VVVVIDIE(InfoExtractor):
|
||||||
_VALID_URL = r'https?://(?:www\.)?vvvvid\.it/(?:#!)?(?:show|anime|film|series)/(?P<show_id>\d+)/[^/]+/(?P<season_id>\d+)/(?P<id>[0-9]+)'
|
_VALID_URL_BASE = r'https?://(?:www\.)?vvvvid\.it/(?:#!)?(?:show|anime|film|series)/'
|
||||||
|
_VALID_URL = r'%s(?P<show_id>\d+)/[^/]+/(?P<season_id>\d+)/(?P<id>[0-9]+)' % _VALID_URL_BASE
|
||||||
_TESTS = [{
|
_TESTS = [{
|
||||||
# video_type == 'video/vvvvid'
|
# video_type == 'video/vvvvid'
|
||||||
'url': 'https://www.vvvvid.it/#!show/434/perche-dovrei-guardarlo-di-dario-moccia/437/489048/ping-pong',
|
'url': 'https://www.vvvvid.it/#!show/434/perche-dovrei-guardarlo-di-dario-moccia/437/489048/ping-pong',
|
||||||
@@ -21,6 +22,16 @@ class VVVVIDIE(InfoExtractor):
|
|||||||
'id': '489048',
|
'id': '489048',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'title': 'Ping Pong',
|
'title': 'Ping Pong',
|
||||||
|
'duration': 239,
|
||||||
|
'series': '"Perché dovrei guardarlo?" di Dario Moccia',
|
||||||
|
'season_id': '437',
|
||||||
|
'season_number': 1,
|
||||||
|
'episode': 'Ping Pong',
|
||||||
|
'episode_number': 1,
|
||||||
|
'episode_id': '3334',
|
||||||
|
'view_count': int,
|
||||||
|
'like_count': int,
|
||||||
|
'repost_count': int,
|
||||||
},
|
},
|
||||||
'params': {
|
'params': {
|
||||||
'skip_download': True,
|
'skip_download': True,
|
||||||
@@ -37,6 +48,9 @@ class VVVVIDIE(InfoExtractor):
|
|||||||
'params': {
|
'params': {
|
||||||
'skip_download': True,
|
'skip_download': True,
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
'url': 'https://www.vvvvid.it/show/434/perche-dovrei-guardarlo-di-dario-moccia/437/489048',
|
||||||
|
'only_matching': True
|
||||||
}]
|
}]
|
||||||
_conn_id = None
|
_conn_id = None
|
||||||
|
|
||||||
@@ -45,20 +59,36 @@ class VVVVIDIE(InfoExtractor):
|
|||||||
'https://www.vvvvid.it/user/login',
|
'https://www.vvvvid.it/user/login',
|
||||||
None, headers=self.geo_verification_headers())['data']['conn_id']
|
None, headers=self.geo_verification_headers())['data']['conn_id']
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _download_info(self, show_id, path, video_id, fatal=True):
|
||||||
show_id, season_id, video_id = re.match(self._VALID_URL, url).groups()
|
|
||||||
response = self._download_json(
|
response = self._download_json(
|
||||||
'https://www.vvvvid.it/vvvvid/ondemand/%s/season/%s' % (show_id, season_id),
|
'https://www.vvvvid.it/vvvvid/ondemand/%s/%s' % (show_id, path),
|
||||||
video_id, headers=self.geo_verification_headers(), query={
|
video_id, headers=self.geo_verification_headers(), query={
|
||||||
'conn_id': self._conn_id,
|
'conn_id': self._conn_id,
|
||||||
})
|
}, fatal=fatal)
|
||||||
if response['result'] == 'error':
|
if not (response or fatal):
|
||||||
|
return
|
||||||
|
if response.get('result') == 'error':
|
||||||
raise ExtractorError('%s said: %s' % (
|
raise ExtractorError('%s said: %s' % (
|
||||||
self.IE_NAME, response['message']), expected=True)
|
self.IE_NAME, response['message']), expected=True)
|
||||||
|
return response['data']
|
||||||
|
|
||||||
|
def _extract_common_video_info(self, video_data):
|
||||||
|
return {
|
||||||
|
'thumbnail': video_data.get('thumbnail'),
|
||||||
|
'episode_number': int_or_none(video_data.get('number')),
|
||||||
|
'episode_id': str_or_none(video_data.get('id')),
|
||||||
|
}
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
show_id, season_id, video_id = re.match(self._VALID_URL, url).groups()
|
||||||
|
|
||||||
|
response = self._download_info(
|
||||||
|
show_id, 'season/%s' % season_id, video_id)
|
||||||
|
|
||||||
vid = int(video_id)
|
vid = int(video_id)
|
||||||
video_data = list(filter(
|
video_data = list(filter(
|
||||||
lambda episode: episode.get('video_id') == vid, response['data']))[0]
|
lambda episode: episode.get('video_id') == vid, response))[0]
|
||||||
|
title = video_data['title']
|
||||||
formats = []
|
formats = []
|
||||||
|
|
||||||
# vvvvid embed_info decryption algorithm is reverse engineered from function $ds(h) at vvvvid.js
|
# vvvvid embed_info decryption algorithm is reverse engineered from function $ds(h) at vvvvid.js
|
||||||
@@ -141,18 +171,67 @@ class VVVVIDIE(InfoExtractor):
|
|||||||
'http://sb.top-ix.org/videomg/_definst_/mp4:%s/playlist.m3u8' % embed_code, video_id))
|
'http://sb.top-ix.org/videomg/_definst_/mp4:%s/playlist.m3u8' % embed_code, video_id))
|
||||||
self._sort_formats(formats)
|
self._sort_formats(formats)
|
||||||
|
|
||||||
return {
|
info = self._extract_common_video_info(video_data)
|
||||||
|
info.update({
|
||||||
'id': video_id,
|
'id': video_id,
|
||||||
'title': video_data['title'],
|
'title': title,
|
||||||
'formats': formats,
|
'formats': formats,
|
||||||
'thumbnail': video_data.get('thumbnail'),
|
|
||||||
'duration': int_or_none(video_data.get('length')),
|
'duration': int_or_none(video_data.get('length')),
|
||||||
'series': video_data.get('show_title'),
|
'series': video_data.get('show_title'),
|
||||||
'season_id': season_id,
|
'season_id': season_id,
|
||||||
'season_number': video_data.get('season_number'),
|
'season_number': video_data.get('season_number'),
|
||||||
'episode_id': str_or_none(video_data.get('id')),
|
'episode': title,
|
||||||
'episode_number': int_or_none(video_data.get('number')),
|
|
||||||
'episode_title': video_data['title'],
|
|
||||||
'view_count': int_or_none(video_data.get('views')),
|
'view_count': int_or_none(video_data.get('views')),
|
||||||
'like_count': int_or_none(video_data.get('video_likes')),
|
'like_count': int_or_none(video_data.get('video_likes')),
|
||||||
}
|
'repost_count': int_or_none(video_data.get('video_shares')),
|
||||||
|
})
|
||||||
|
return info
|
||||||
|
|
||||||
|
|
||||||
|
class VVVVIDShowIE(VVVVIDIE):
|
||||||
|
_VALID_URL = r'(?P<base_url>%s(?P<id>\d+)(?:/(?P<show_title>[^/?&#]+))?)/?(?:[?#&]|$)' % VVVVIDIE._VALID_URL_BASE
|
||||||
|
_TESTS = [{
|
||||||
|
'url': 'https://www.vvvvid.it/show/156/psyco-pass',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '156',
|
||||||
|
'title': 'Psycho-Pass',
|
||||||
|
'description': 'md5:94d572c0bd85894b193b8aebc9a3a806',
|
||||||
|
},
|
||||||
|
'playlist_count': 46,
|
||||||
|
}, {
|
||||||
|
'url': 'https://www.vvvvid.it/show/156',
|
||||||
|
'only_matching': True,
|
||||||
|
}]
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
base_url, show_id, show_title = re.match(self._VALID_URL, url).groups()
|
||||||
|
|
||||||
|
seasons = self._download_info(
|
||||||
|
show_id, 'seasons/', show_title)
|
||||||
|
|
||||||
|
show_info = self._download_info(
|
||||||
|
show_id, 'info/', show_title, fatal=False)
|
||||||
|
|
||||||
|
entries = []
|
||||||
|
for season in (seasons or []):
|
||||||
|
season_number = int_or_none(season.get('number'))
|
||||||
|
episodes = season.get('episodes') or []
|
||||||
|
for episode in episodes:
|
||||||
|
season_id = str_or_none(episode.get('season_id'))
|
||||||
|
video_id = str_or_none(episode.get('video_id'))
|
||||||
|
if not (season_id and video_id):
|
||||||
|
continue
|
||||||
|
info = self._extract_common_video_info(episode)
|
||||||
|
info.update({
|
||||||
|
'_type': 'url',
|
||||||
|
'ie_key': VVVVIDIE.ie_key(),
|
||||||
|
'url': '/'.join([base_url, season_id, video_id]),
|
||||||
|
'title': episode.get('title'),
|
||||||
|
'description': episode.get('description'),
|
||||||
|
'season_number': season_number,
|
||||||
|
'season_id': season_id,
|
||||||
|
})
|
||||||
|
entries.append(info)
|
||||||
|
|
||||||
|
return self.playlist_result(
|
||||||
|
entries, show_id, show_info.get('title'), show_info.get('description'))
|
||||||
|
@@ -1,23 +1,43 @@
|
|||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
|
||||||
from .common import InfoExtractor
|
from .common import InfoExtractor
|
||||||
from ..compat import compat_str
|
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
determine_ext,
|
determine_ext,
|
||||||
float_or_none,
|
float_or_none,
|
||||||
int_or_none,
|
int_or_none,
|
||||||
|
mimetype2ext,
|
||||||
try_get,
|
try_get,
|
||||||
urlencode_postdata,
|
urljoin,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class YandexDiskIE(InfoExtractor):
|
class YandexDiskIE(InfoExtractor):
|
||||||
_VALID_URL = r'https?://yadi\.sk/[di]/(?P<id>[^/?#&]+)'
|
_VALID_URL = r'''(?x)https?://
|
||||||
|
(?P<domain>
|
||||||
|
yadi\.sk|
|
||||||
|
disk\.yandex\.
|
||||||
|
(?:
|
||||||
|
az|
|
||||||
|
by|
|
||||||
|
co(?:m(?:\.(?:am|ge|tr))?|\.il)|
|
||||||
|
ee|
|
||||||
|
fr|
|
||||||
|
k[gz]|
|
||||||
|
l[tv]|
|
||||||
|
md|
|
||||||
|
t[jm]|
|
||||||
|
u[az]|
|
||||||
|
ru
|
||||||
|
)
|
||||||
|
)/(?:[di]/|public.*?\bhash=)(?P<id>[^/?#&]+)'''
|
||||||
|
|
||||||
_TESTS = [{
|
_TESTS = [{
|
||||||
'url': 'https://yadi.sk/i/VdOeDou8eZs6Y',
|
'url': 'https://yadi.sk/i/VdOeDou8eZs6Y',
|
||||||
'md5': '33955d7ae052f15853dc41f35f17581c',
|
'md5': 'a4a8d52958c8fddcf9845935070402ae',
|
||||||
'info_dict': {
|
'info_dict': {
|
||||||
'id': 'VdOeDou8eZs6Y',
|
'id': 'VdOeDou8eZs6Y',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
@@ -27,92 +47,101 @@ class YandexDiskIE(InfoExtractor):
|
|||||||
'uploader_id': '300043621',
|
'uploader_id': '300043621',
|
||||||
'view_count': int,
|
'view_count': int,
|
||||||
},
|
},
|
||||||
|
'expected_warnings': ['Unable to download JSON metadata'],
|
||||||
}, {
|
}, {
|
||||||
'url': 'https://yadi.sk/d/h3WAXvDS3Li3Ce',
|
'url': 'https://yadi.sk/d/h3WAXvDS3Li3Ce',
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
|
}, {
|
||||||
|
'url': 'https://yadi.sk/public?hash=5DZ296JK9GWCLp02f6jrObjnctjRxMs8L6%2B%2FuhNqk38%3D',
|
||||||
|
'only_matching': True,
|
||||||
}]
|
}]
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
video_id = self._match_id(url)
|
domain, video_id = re.match(self._VALID_URL, url).groups()
|
||||||
|
|
||||||
status = self._download_webpage(
|
|
||||||
'https://disk.yandex.com/auth/status', video_id, query={
|
|
||||||
'urlOrigin': url,
|
|
||||||
'source': 'public',
|
|
||||||
'md5': 'false',
|
|
||||||
})
|
|
||||||
|
|
||||||
sk = self._search_regex(
|
|
||||||
r'(["\'])sk(?:External)?\1\s*:\s*(["\'])(?P<value>(?:(?!\2).)+)\2',
|
|
||||||
status, 'sk', group='value')
|
|
||||||
|
|
||||||
webpage = self._download_webpage(url, video_id)
|
webpage = self._download_webpage(url, video_id)
|
||||||
|
store = self._parse_json(self._search_regex(
|
||||||
|
r'<script[^>]+id="store-prefetch"[^>]*>\s*({.+?})\s*</script>',
|
||||||
|
webpage, 'store'), video_id)
|
||||||
|
resource = store['resources'][store['rootResourceId']]
|
||||||
|
|
||||||
models = self._parse_json(
|
title = resource['name']
|
||||||
self._search_regex(
|
meta = resource.get('meta') or {}
|
||||||
r'<script[^>]+id=["\']models-client[^>]+>\s*(\[.+?\])\s*</script',
|
|
||||||
webpage, 'video JSON'),
|
|
||||||
video_id)
|
|
||||||
|
|
||||||
data = next(
|
public_url = meta.get('short_url')
|
||||||
model['data'] for model in models
|
if public_url:
|
||||||
if model.get('model') == 'resource')
|
video_id = self._match_id(public_url)
|
||||||
|
|
||||||
video_hash = data['id']
|
source_url = (self._download_json(
|
||||||
title = data['name']
|
'https://cloud-api.yandex.net/v1/disk/public/resources/download',
|
||||||
|
video_id, query={'public_key': url}, fatal=False) or {}).get('href')
|
||||||
|
video_streams = resource.get('videoStreams') or {}
|
||||||
|
video_hash = resource.get('hash') or url
|
||||||
|
environment = store.get('environment') or {}
|
||||||
|
sk = environment.get('sk')
|
||||||
|
yandexuid = environment.get('yandexuid')
|
||||||
|
if sk and yandexuid and not (source_url and video_streams):
|
||||||
|
self._set_cookie(domain, 'yandexuid', yandexuid)
|
||||||
|
|
||||||
models = self._download_json(
|
def call_api(action):
|
||||||
'https://disk.yandex.com/models/', video_id,
|
return (self._download_json(
|
||||||
data=urlencode_postdata({
|
urljoin(url, '/public/api/') + action, video_id, data=json.dumps({
|
||||||
'_model.0': 'videoInfo',
|
'hash': video_hash,
|
||||||
'id.0': video_hash,
|
'sk': sk,
|
||||||
'_model.1': 'do-get-resource-url',
|
}).encode(), headers={
|
||||||
'id.1': video_hash,
|
'Content-Type': 'text/plain',
|
||||||
'version': '13.6',
|
}, fatal=False) or {}).get('data') or {}
|
||||||
'sk': sk,
|
if not source_url:
|
||||||
}), query={'_m': 'videoInfo'})['models']
|
# TODO: figure out how to detect if download limit has
|
||||||
|
# been reached and then avoid unnecessary source format
|
||||||
videos = try_get(models, lambda x: x[0]['data']['videos'], list) or []
|
# extraction requests
|
||||||
source_url = try_get(
|
source_url = call_api('download-url').get('url')
|
||||||
models, lambda x: x[1]['data']['file'], compat_str)
|
if not video_streams:
|
||||||
|
video_streams = call_api('get-video-streams')
|
||||||
|
|
||||||
formats = []
|
formats = []
|
||||||
if source_url:
|
if source_url:
|
||||||
formats.append({
|
formats.append({
|
||||||
'url': source_url,
|
'url': source_url,
|
||||||
'format_id': 'source',
|
'format_id': 'source',
|
||||||
'ext': determine_ext(title, 'mp4'),
|
'ext': determine_ext(title, meta.get('ext') or mimetype2ext(meta.get('mime_type')) or 'mp4'),
|
||||||
'quality': 1,
|
'quality': 1,
|
||||||
|
'filesize': int_or_none(meta.get('size'))
|
||||||
})
|
})
|
||||||
for video in videos:
|
|
||||||
|
for video in (video_streams.get('videos') or []):
|
||||||
format_url = video.get('url')
|
format_url = video.get('url')
|
||||||
if not format_url:
|
if not format_url:
|
||||||
continue
|
continue
|
||||||
if determine_ext(format_url) == 'm3u8':
|
if video.get('dimension') == 'adaptive':
|
||||||
formats.extend(self._extract_m3u8_formats(
|
formats.extend(self._extract_m3u8_formats(
|
||||||
format_url, video_id, 'mp4', entry_protocol='m3u8_native',
|
format_url, video_id, 'mp4', 'm3u8_native',
|
||||||
m3u8_id='hls', fatal=False))
|
m3u8_id='hls', fatal=False))
|
||||||
else:
|
else:
|
||||||
|
size = video.get('size') or {}
|
||||||
|
height = int_or_none(size.get('height'))
|
||||||
|
format_id = 'hls'
|
||||||
|
if height:
|
||||||
|
format_id += '-%dp' % height
|
||||||
formats.append({
|
formats.append({
|
||||||
|
'ext': 'mp4',
|
||||||
|
'format_id': format_id,
|
||||||
|
'height': height,
|
||||||
|
'protocol': 'm3u8_native',
|
||||||
'url': format_url,
|
'url': format_url,
|
||||||
|
'width': int_or_none(size.get('width')),
|
||||||
})
|
})
|
||||||
self._sort_formats(formats)
|
self._sort_formats(formats)
|
||||||
|
|
||||||
duration = float_or_none(try_get(
|
uid = resource.get('uid')
|
||||||
models, lambda x: x[0]['data']['duration']), 1000)
|
display_name = try_get(store, lambda x: x['users'][uid]['displayName'])
|
||||||
uploader = try_get(
|
|
||||||
data, lambda x: x['user']['display_name'], compat_str)
|
|
||||||
uploader_id = try_get(
|
|
||||||
data, lambda x: x['user']['uid'], compat_str)
|
|
||||||
view_count = int_or_none(try_get(
|
|
||||||
data, lambda x: x['meta']['views_counter']))
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'id': video_id,
|
'id': video_id,
|
||||||
'title': title,
|
'title': title,
|
||||||
'duration': duration,
|
'duration': float_or_none(video_streams.get('duration'), 1000),
|
||||||
'uploader': uploader,
|
'uploader': display_name,
|
||||||
'uploader_id': uploader_id,
|
'uploader_id': uid,
|
||||||
'view_count': view_count,
|
'view_count': int_or_none(meta.get('views_counter')),
|
||||||
'formats': formats,
|
'formats': formats,
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,7 @@ from .common import InfoExtractor
|
|||||||
from ..utils import (
|
from ..utils import (
|
||||||
determine_ext,
|
determine_ext,
|
||||||
int_or_none,
|
int_or_none,
|
||||||
|
try_get,
|
||||||
url_or_none,
|
url_or_none,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -13,26 +14,30 @@ class YandexVideoIE(InfoExtractor):
|
|||||||
_VALID_URL = r'''(?x)
|
_VALID_URL = r'''(?x)
|
||||||
https?://
|
https?://
|
||||||
(?:
|
(?:
|
||||||
yandex\.ru(?:/portal/(?:video|efir))?/?\?.*?stream_id=|
|
yandex\.ru(?:/(?:portal/(?:video|efir)|efir))?/?\?.*?stream_id=|
|
||||||
frontend\.vh\.yandex\.ru/player/
|
frontend\.vh\.yandex\.ru/player/
|
||||||
)
|
)
|
||||||
(?P<id>[\da-f]+)
|
(?P<id>(?:[\da-f]{32}|[\w-]{12}))
|
||||||
'''
|
'''
|
||||||
_TESTS = [{
|
_TESTS = [{
|
||||||
'url': 'https://yandex.ru/portal/video?stream_id=4dbb262b4fe5cf15a215de4f34eee34d',
|
'url': 'https://yandex.ru/portal/video?stream_id=4dbb36ec4e0526d58f9f2dc8f0ecf374',
|
||||||
'md5': '33955d7ae052f15853dc41f35f17581c',
|
'md5': 'e02a05bfaf0d9615ef07ae3a10f4faf4',
|
||||||
'info_dict': {
|
'info_dict': {
|
||||||
'id': '4dbb262b4fe5cf15a215de4f34eee34d',
|
'id': '4dbb36ec4e0526d58f9f2dc8f0ecf374',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'title': 'В Нью-Йорке баржи и теплоход оторвались от причала и расплылись по Гудзону',
|
'title': 'Русский Вудсток - главный рок-фест в истории СССР / вДудь',
|
||||||
'description': '',
|
'description': 'md5:7d6b8d4bc4a3b9a56499916c1ea5b5fa',
|
||||||
'thumbnail': r're:^https?://.*\.jpg$',
|
'thumbnail': r're:^https?://',
|
||||||
'timestamp': 0,
|
'timestamp': 1549972939,
|
||||||
'duration': 30,
|
'duration': 5575,
|
||||||
'age_limit': 18,
|
'age_limit': 18,
|
||||||
|
'upload_date': '20190212',
|
||||||
|
'view_count': int,
|
||||||
|
'like_count': int,
|
||||||
|
'dislike_count': int,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
'url': 'https://yandex.ru/portal/efir?stream_id=4dbb36ec4e0526d58f9f2dc8f0ecf374&from=morda',
|
'url': 'https://yandex.ru/portal/efir?stream_id=4dbb262b4fe5cf15a215de4f34eee34d&from=morda',
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
}, {
|
}, {
|
||||||
'url': 'https://yandex.ru/?stream_id=4dbb262b4fe5cf15a215de4f34eee34d',
|
'url': 'https://yandex.ru/?stream_id=4dbb262b4fe5cf15a215de4f34eee34d',
|
||||||
@@ -52,53 +57,88 @@ class YandexVideoIE(InfoExtractor):
|
|||||||
# DASH with DRM
|
# DASH with DRM
|
||||||
'url': 'https://yandex.ru/portal/video?from=morda&stream_id=485a92d94518d73a9d0ff778e13505f8',
|
'url': 'https://yandex.ru/portal/video?from=morda&stream_id=485a92d94518d73a9d0ff778e13505f8',
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
|
}, {
|
||||||
|
'url': 'https://yandex.ru/efir?stream_active=watching&stream_id=v7a2dZ-v5mSI&from_block=efir_newtab',
|
||||||
|
'only_matching': True,
|
||||||
}]
|
}]
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
video_id = self._match_id(url)
|
video_id = self._match_id(url)
|
||||||
|
|
||||||
content = self._download_json(
|
player = try_get((self._download_json(
|
||||||
'https://frontend.vh.yandex.ru/v22/player/%s.json' % video_id,
|
'https://frontend.vh.yandex.ru/graphql', video_id, data=b'''{
|
||||||
video_id, query={
|
player(content_id: "%s") {
|
||||||
'stream_options': 'hires',
|
computed_title
|
||||||
'disable_trackings': 1,
|
content_url
|
||||||
})['content']
|
description
|
||||||
|
dislikes
|
||||||
|
duration
|
||||||
|
likes
|
||||||
|
program_title
|
||||||
|
release_date
|
||||||
|
release_date_ut
|
||||||
|
release_year
|
||||||
|
restriction_age
|
||||||
|
season
|
||||||
|
start_time
|
||||||
|
streams
|
||||||
|
thumbnail
|
||||||
|
title
|
||||||
|
views_count
|
||||||
|
}
|
||||||
|
}''' % video_id.encode(), fatal=False)), lambda x: x['player']['content'])
|
||||||
|
if not player or player.get('error'):
|
||||||
|
player = self._download_json(
|
||||||
|
'https://frontend.vh.yandex.ru/v23/player/%s.json' % video_id,
|
||||||
|
video_id, query={
|
||||||
|
'stream_options': 'hires',
|
||||||
|
'disable_trackings': 1,
|
||||||
|
})
|
||||||
|
content = player['content']
|
||||||
|
|
||||||
content_url = url_or_none(content.get('content_url')) or url_or_none(
|
title = content.get('title') or content['computed_title']
|
||||||
content['streams'][0]['url'])
|
|
||||||
title = content.get('title') or content.get('computed_title')
|
|
||||||
|
|
||||||
ext = determine_ext(content_url)
|
formats = []
|
||||||
|
streams = content.get('streams') or []
|
||||||
if ext == 'm3u8':
|
streams.append({'url': content.get('content_url')})
|
||||||
formats = self._extract_m3u8_formats(
|
for stream in streams:
|
||||||
content_url, video_id, 'mp4', entry_protocol='m3u8_native',
|
content_url = url_or_none(stream.get('url'))
|
||||||
m3u8_id='hls')
|
if not content_url:
|
||||||
elif ext == 'mpd':
|
continue
|
||||||
formats = self._extract_mpd_formats(
|
ext = determine_ext(content_url)
|
||||||
content_url, video_id, mpd_id='dash')
|
if ext == 'ismc':
|
||||||
else:
|
continue
|
||||||
formats = [{'url': content_url}]
|
elif ext == 'm3u8':
|
||||||
|
formats.extend(self._extract_m3u8_formats(
|
||||||
|
content_url, video_id, 'mp4',
|
||||||
|
'm3u8_native', m3u8_id='hls', fatal=False))
|
||||||
|
elif ext == 'mpd':
|
||||||
|
formats.extend(self._extract_mpd_formats(
|
||||||
|
content_url, video_id, mpd_id='dash', fatal=False))
|
||||||
|
else:
|
||||||
|
formats.append({'url': content_url})
|
||||||
|
|
||||||
self._sort_formats(formats)
|
self._sort_formats(formats)
|
||||||
|
|
||||||
description = content.get('description')
|
|
||||||
thumbnail = content.get('thumbnail')
|
|
||||||
timestamp = (int_or_none(content.get('release_date'))
|
timestamp = (int_or_none(content.get('release_date'))
|
||||||
or int_or_none(content.get('release_date_ut'))
|
or int_or_none(content.get('release_date_ut'))
|
||||||
or int_or_none(content.get('start_time')))
|
or int_or_none(content.get('start_time')))
|
||||||
duration = int_or_none(content.get('duration'))
|
season = content.get('season') or {}
|
||||||
series = content.get('program_title')
|
|
||||||
age_limit = int_or_none(content.get('restriction_age'))
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'id': video_id,
|
'id': video_id,
|
||||||
'title': title,
|
'title': title,
|
||||||
'description': description,
|
'description': content.get('description'),
|
||||||
'thumbnail': thumbnail,
|
'thumbnail': content.get('thumbnail'),
|
||||||
'timestamp': timestamp,
|
'timestamp': timestamp,
|
||||||
'duration': duration,
|
'duration': int_or_none(content.get('duration')),
|
||||||
'series': series,
|
'series': content.get('program_title'),
|
||||||
'age_limit': age_limit,
|
'age_limit': int_or_none(content.get('restriction_age')),
|
||||||
|
'view_count': int_or_none(content.get('views_count')),
|
||||||
|
'like_count': int_or_none(content.get('likes')),
|
||||||
|
'dislike_count': int_or_none(content.get('dislikes')),
|
||||||
|
'season_number': int_or_none(season.get('season_number')),
|
||||||
|
'season_id': season.get('id'),
|
||||||
|
'release_year': int_or_none(content.get('release_year')),
|
||||||
'formats': formats,
|
'formats': formats,
|
||||||
}
|
}
|
||||||
|
@@ -3640,7 +3640,7 @@ def url_or_none(url):
|
|||||||
if not url or not isinstance(url, compat_str):
|
if not url or not isinstance(url, compat_str):
|
||||||
return None
|
return None
|
||||||
url = url.strip()
|
url = url.strip()
|
||||||
return url if re.match(r'^(?:[a-zA-Z][\da-zA-Z.+-]*:)?//', url) else None
|
return url if re.match(r'^(?:(?:https?|rt(?:m(?:pt?[es]?|fp)|sp[su]?)|mms|ftps?):)?//', url) else None
|
||||||
|
|
||||||
|
|
||||||
def parse_duration(s):
|
def parse_duration(s):
|
||||||
|
@@ -1,3 +1,3 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
__version__ = '2020.12.29'
|
__version__ = '2020.12.31'
|
||||||
|
Reference in New Issue
Block a user