mirror of
https://github.com/yt-dlp/yt-dlp
synced 2025-12-16 06:05:41 +07:00
Compare commits
7 Commits
5f94f05490
...
264044286d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
264044286d | ||
|
|
a98e7f9f58 | ||
|
|
0ea5d5882d | ||
|
|
cdc533b114 | ||
|
|
c2e124881f | ||
|
|
ad55bfcfb7 | ||
|
|
739125d40f |
@@ -811,3 +811,10 @@ zakaryan2004
|
||||
cdce8p
|
||||
nicolaasjan
|
||||
willsmillie
|
||||
CasualYT31
|
||||
cecilia-sanare
|
||||
dhwz
|
||||
robin-mu
|
||||
shssoichiro
|
||||
thanhtaivtt
|
||||
uoag
|
||||
|
||||
26
Changelog.md
26
Changelog.md
@@ -4,6 +4,32 @@ # Changelog
|
||||
# To create a release, dispatch the https://github.com/yt-dlp/yt-dlp/actions/workflows/release.yml workflow on master
|
||||
-->
|
||||
|
||||
### 2025.10.14
|
||||
|
||||
#### Core changes
|
||||
- [Fix `prefer-vp9-sort` compat option](https://github.com/yt-dlp/yt-dlp/commit/a6673a8e82276ea529c1773ed09e5bc4a22e822a) ([#14603](https://github.com/yt-dlp/yt-dlp/issues/14603)) by [seproDev](https://github.com/seproDev)
|
||||
|
||||
#### Extractor changes
|
||||
- **10play**
|
||||
- [Handle geo-restriction errors](https://github.com/yt-dlp/yt-dlp/commit/ad55bfcfb700fbfc1364c04e3425761d6f95c0a7) ([#14618](https://github.com/yt-dlp/yt-dlp/issues/14618)) by [bashonly](https://github.com/bashonly)
|
||||
- [Rework extractor](https://github.com/yt-dlp/yt-dlp/commit/eafedc21817bb0de20e9aaccd7151a1d4c4e1ebd) ([#14417](https://github.com/yt-dlp/yt-dlp/issues/14417)) by [seproDev](https://github.com/seproDev), [Sipherdrakon](https://github.com/Sipherdrakon)
|
||||
- **abc.net.au**: [Support listen URLs](https://github.com/yt-dlp/yt-dlp/commit/0ea5d5882def84415f946907cfc00ab431c18fed) ([#14389](https://github.com/yt-dlp/yt-dlp/issues/14389)) by [uoag](https://github.com/uoag)
|
||||
- **cbc.ca**: listen: [Add extractor](https://github.com/yt-dlp/yt-dlp/commit/df160ab18db523f6629f2e7e20123d7a3551df28) ([#14391](https://github.com/yt-dlp/yt-dlp/issues/14391)) by [uoag](https://github.com/uoag)
|
||||
- **dropout**: [Update extractor for new domain](https://github.com/yt-dlp/yt-dlp/commit/8eb8695139dece6351aac10463df63b87b45b000) ([#14531](https://github.com/yt-dlp/yt-dlp/issues/14531)) by [cecilia-sanare](https://github.com/cecilia-sanare)
|
||||
- **idagio**: [Add extractors](https://github.com/yt-dlp/yt-dlp/commit/a98e7f9f58a9492d2cb216baa59c890ed8ce02f3) ([#14586](https://github.com/yt-dlp/yt-dlp/issues/14586)) by [robin-mu](https://github.com/robin-mu)
|
||||
- **musescore**: [Fix extractor](https://github.com/yt-dlp/yt-dlp/commit/87be1bb96ac47abaaa4cfc6d7dd651e511b74551) ([#14598](https://github.com/yt-dlp/yt-dlp/issues/14598)) by [seproDev](https://github.com/seproDev)
|
||||
- **prankcastpost**: [Rework extractor](https://github.com/yt-dlp/yt-dlp/commit/5d7678195a7d0c045a9fe0418383171a71a7ea43) ([#14445](https://github.com/yt-dlp/yt-dlp/issues/14445)) by [columndeeply](https://github.com/columndeeply)
|
||||
- **slideslive**: [Fix extractor](https://github.com/yt-dlp/yt-dlp/commit/c2e124881f9aa02097589e853b3d3505e78372c4) ([#14619](https://github.com/yt-dlp/yt-dlp/issues/14619)) by [bashonly](https://github.com/bashonly)
|
||||
- **soundcloud**: [Support new API URLs](https://github.com/yt-dlp/yt-dlp/commit/6d41aaf21c61a87e74564646abd0a8ee887e888d) ([#14449](https://github.com/yt-dlp/yt-dlp/issues/14449)) by [seproDev](https://github.com/seproDev)
|
||||
- **tiktok**
|
||||
- [Support browser impersonation](https://github.com/yt-dlp/yt-dlp/commit/5513036104ed9710f624c537fb3644b07a0680db) ([#14473](https://github.com/yt-dlp/yt-dlp/issues/14473)) by [bashonly](https://github.com/bashonly), [thanhtaivtt](https://github.com/thanhtaivtt)
|
||||
- user: [Fix private account extraction](https://github.com/yt-dlp/yt-dlp/commit/cdc533b114c35ceb8a2e9dd3eb9c172a8737ae5e) ([#14585](https://github.com/yt-dlp/yt-dlp/issues/14585)) by [CasualYT31](https://github.com/CasualYT31)
|
||||
- **vidyard**: [Extract chapters](https://github.com/yt-dlp/yt-dlp/commit/5f94f054907c12e68129cd9ac2508ed8aba1b223) ([#14478](https://github.com/yt-dlp/yt-dlp/issues/14478)) by [exterrestris](https://github.com/exterrestris)
|
||||
- **xhamster**: [Fix extractor](https://github.com/yt-dlp/yt-dlp/commit/739125d40f8ede3beb7be68fc4df55bec0d226fd) ([#14446](https://github.com/yt-dlp/yt-dlp/issues/14446)) by [dhwz](https://github.com/dhwz), [dirkf](https://github.com/dirkf), [shssoichiro](https://github.com/shssoichiro)
|
||||
- **youtube**
|
||||
- [Detect experiment binding GVS PO Token to video id](https://github.com/yt-dlp/yt-dlp/commit/bd5ed90419eea18adfb2f0d8efa9d22b2029119f) ([#14471](https://github.com/yt-dlp/yt-dlp/issues/14471)) by [coletdjnz](https://github.com/coletdjnz)
|
||||
- tab: [Fix approximate timestamp extraction for feeds](https://github.com/yt-dlp/yt-dlp/commit/ccc25d6710a4aa373b7e15c558e07f8a2ffae5f3) ([#14539](https://github.com/yt-dlp/yt-dlp/issues/14539)) by [coletdjnz](https://github.com/coletdjnz)
|
||||
|
||||
### 2025.09.26
|
||||
|
||||
#### Extractor changes
|
||||
|
||||
@@ -242,6 +242,7 @@ # Supported sites
|
||||
- **Canalsurmas**
|
||||
- **CaracolTvPlay**: [*caracoltv-play*](## "netrc machine")
|
||||
- **cbc.ca**
|
||||
- **cbc.ca:listen**
|
||||
- **cbc.ca:player**
|
||||
- **cbc.ca:player:playlist**
|
||||
- **CBS**: (**Currently broken**)
|
||||
@@ -579,6 +580,11 @@ # Supported sites
|
||||
- **Hypem**
|
||||
- **Hytale**
|
||||
- **Icareus**
|
||||
- **IdagioAlbum**
|
||||
- **IdagioPersonalPlaylist**
|
||||
- **IdagioPlaylist**
|
||||
- **IdagioRecording**
|
||||
- **IdagioTrack**
|
||||
- **IdolPlus**
|
||||
- **iflix:episode**
|
||||
- **IflixSeries**
|
||||
|
||||
@@ -824,6 +824,13 @@
|
||||
IchinanaLiveIE,
|
||||
IchinanaLiveVODIE,
|
||||
)
|
||||
from .idagio import (
|
||||
IdagioAlbumIE,
|
||||
IdagioPersonalPlaylistIE,
|
||||
IdagioPlaylistIE,
|
||||
IdagioRecordingIE,
|
||||
IdagioTrackIE,
|
||||
)
|
||||
from .idolplus import IdolPlusIE
|
||||
from .ign import (
|
||||
IGNIE,
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
class ABCIE(InfoExtractor):
|
||||
IE_NAME = 'abc.net.au'
|
||||
_VALID_URL = r'https?://(?:www\.)?abc\.net\.au/(?:news|btn)/(?:[^/]+/){1,4}(?P<id>\d{5,})'
|
||||
_VALID_URL = r'https?://(?:www\.)?abc\.net\.au/(?:news|btn|listen)/(?:[^/?#]+/){1,4}(?P<id>\d{5,})'
|
||||
|
||||
_TESTS = [{
|
||||
'url': 'http://www.abc.net.au/news/2014-11-05/australia-to-staff-ebola-treatment-centre-in-sierra-leone/5868334',
|
||||
@@ -53,8 +53,9 @@ class ABCIE(InfoExtractor):
|
||||
'info_dict': {
|
||||
'id': '6880080',
|
||||
'ext': 'mp3',
|
||||
'title': 'NAB lifts interest rates, following Westpac and CBA',
|
||||
'title': 'NAB lifts interest rates, following Westpac and CBA - ABC listen',
|
||||
'description': 'md5:f13d8edc81e462fce4a0437c7dc04728',
|
||||
'thumbnail': r're:https://live-production\.wcms\.abc-cdn\.net\.au/2193d7437c84b25eafd6360c82b5fa21',
|
||||
},
|
||||
}, {
|
||||
'url': 'http://www.abc.net.au/news/2015-10-19/6866214',
|
||||
@@ -64,8 +65,9 @@ class ABCIE(InfoExtractor):
|
||||
'info_dict': {
|
||||
'id': '10527914',
|
||||
'ext': 'mp4',
|
||||
'title': 'WWI Centenary',
|
||||
'description': 'md5:c2379ec0ca84072e86b446e536954546',
|
||||
'title': 'WWI Centenary - Behind The News',
|
||||
'description': 'md5:fa4405939ff750fade46ff0cd4c66a52',
|
||||
'thumbnail': r're:https://live-production\.wcms\.abc-cdn\.net\.au/bcc3433c97bf992dff32ec5a768713c9',
|
||||
},
|
||||
}, {
|
||||
'url': 'https://www.abc.net.au/news/programs/the-world/2020-06-10/black-lives-matter-protests-spawn-support-for/12342074',
|
||||
@@ -73,7 +75,8 @@ class ABCIE(InfoExtractor):
|
||||
'id': '12342074',
|
||||
'ext': 'mp4',
|
||||
'title': 'Black Lives Matter protests spawn support for Papuans in Indonesia',
|
||||
'description': 'md5:2961a17dc53abc558589ccd0fb8edd6f',
|
||||
'description': 'md5:625257209f2d14ce23cb4e3785da9beb',
|
||||
'thumbnail': r're:https://live-production\.wcms\.abc-cdn\.net\.au/7ee6f190de6d7dbb04203e514bfae9ec',
|
||||
},
|
||||
}, {
|
||||
'url': 'https://www.abc.net.au/btn/newsbreak/btn-newsbreak-20200814/12560476',
|
||||
@@ -93,7 +96,16 @@ class ABCIE(InfoExtractor):
|
||||
'title': 'Wagner Group retreating from Russia, leader Prigozhin to move to Belarus',
|
||||
'ext': 'mp4',
|
||||
'description': 'Wagner troops leave Rostov-on-Don and\xa0Yevgeny Prigozhin will move to Belarus under a deal brokered by Belarusian President Alexander Lukashenko to end the mutiny.',
|
||||
'thumbnail': 'https://live-production.wcms.abc-cdn.net.au/0c170f5b57f0105c432f366c0e8e267b?impolicy=wcms_crop_resize&cropH=2813&cropW=5000&xPos=0&yPos=249&width=862&height=485',
|
||||
'thumbnail': r're:https://live-production\.wcm\.abc-cdn\.net\.au/0c170f5b57f0105c432f366c0e8e267b',
|
||||
},
|
||||
}, {
|
||||
'url': 'https://www.abc.net.au/listen/programs/the-followers-madness-of-two/presents-followers-madness-of-two/105697646',
|
||||
'info_dict': {
|
||||
'id': '105697646',
|
||||
'title': 'INTRODUCING — The Followers: Madness of Two - ABC listen',
|
||||
'ext': 'mp3',
|
||||
'description': 'md5:2310cd0d440a4e01656abea15db8d1f3',
|
||||
'thumbnail': r're:https://live-production\.wcms\.abc-cdn\.net\.au/90d7078214e5d66553ffb7fcf0da0cda',
|
||||
},
|
||||
}]
|
||||
|
||||
|
||||
233
yt_dlp/extractor/idagio.py
Normal file
233
yt_dlp/extractor/idagio.py
Normal file
@@ -0,0 +1,233 @@
|
||||
from .common import InfoExtractor
|
||||
from ..utils import int_or_none, unified_timestamp, url_or_none
|
||||
from ..utils.traversal import traverse_obj
|
||||
|
||||
|
||||
class IdagioTrackIE(InfoExtractor):
|
||||
_VALID_URL = r'https?://(?:www\.)?app\.idagio\.com/recordings/\d+\?(?:[^#]+&)?trackId=(?P<id>\d+)'
|
||||
_TESTS = [{
|
||||
'url': 'https://app.idagio.com/recordings/30576934?trackId=30576943',
|
||||
'md5': '15148bd71804b2450a2508931a116b56',
|
||||
'info_dict': {
|
||||
'id': '30576943',
|
||||
'ext': 'mp3',
|
||||
'title': 'Theme. Andante',
|
||||
'duration': 82,
|
||||
'composers': ['Edward Elgar'],
|
||||
'artists': ['Vasily Petrenko', 'Royal Liverpool Philharmonic Orchestra'],
|
||||
'genres': ['Orchestral', 'Other Orchestral Music'],
|
||||
'track': 'Theme. Andante',
|
||||
'timestamp': 1554474370,
|
||||
'upload_date': '20190405',
|
||||
},
|
||||
}, {
|
||||
'url': 'https://app.idagio.com/recordings/20514467?trackId=20514478&utm_source=pcl',
|
||||
'md5': '3acef2ea0feadf889123b70e5a1e7fa7',
|
||||
'info_dict': {
|
||||
'id': '20514478',
|
||||
'ext': 'mp3',
|
||||
'title': 'I. Adagio sostenuto',
|
||||
'duration': 316,
|
||||
'composers': ['Ludwig van Beethoven'],
|
||||
'artists': [],
|
||||
'genres': ['Keyboard', 'Sonata (Keyboard)'],
|
||||
'track': 'I. Adagio sostenuto',
|
||||
'timestamp': 1518076337,
|
||||
'upload_date': '20180208',
|
||||
},
|
||||
}]
|
||||
|
||||
def _real_extract(self, url):
|
||||
track_id = self._match_id(url)
|
||||
track_info = self._download_json(
|
||||
f'https://api.idagio.com/v2.0/metadata/tracks/{track_id}',
|
||||
track_id, fatal=False, expected_status=406)
|
||||
if traverse_obj(track_info, 'error_code') == 'idagio.error.blocked.location':
|
||||
self.raise_geo_restricted()
|
||||
|
||||
content_info = self._download_json(
|
||||
f'https://api.idagio.com/v1.8/content/track/{track_id}', track_id,
|
||||
query={
|
||||
'quality': '0',
|
||||
'format': '2',
|
||||
'client_type': 'web-4',
|
||||
})
|
||||
|
||||
return {
|
||||
'ext': 'mp3',
|
||||
'vcodec': 'none',
|
||||
'id': track_id,
|
||||
'url': traverse_obj(content_info, ('url', {url_or_none})),
|
||||
**traverse_obj(track_info, ('result', {
|
||||
'title': ('piece', 'title', {str}),
|
||||
'timestamp': ('recording', 'created_at', {int_or_none(scale=1000)}),
|
||||
'location': ('recording', 'location', {str}),
|
||||
'duration': ('duration', {int_or_none}),
|
||||
'track': ('piece', 'title', {str}),
|
||||
'artists': ('recording', ('conductor', ('ensembles', ...), ('soloists', ...)), 'name', {str}, filter),
|
||||
'composers': ('piece', 'workpart', 'work', 'composer', 'name', {str}, filter, all, filter),
|
||||
'genres': ('piece', 'workpart', 'work', ('genre', 'subgenre'), 'title', {str}, filter),
|
||||
})),
|
||||
}
|
||||
|
||||
|
||||
class IdagioPlaylistBaseIE(InfoExtractor):
|
||||
"""Subclasses must set _API_URL_TMPL and define _parse_playlist_metadata"""
|
||||
_PLAYLIST_ID_KEY = 'id' # vs. 'display_id'
|
||||
|
||||
def _entries(self, playlist_info):
|
||||
for track_data in traverse_obj(playlist_info, ('tracks', lambda _, v: v['id'] and v['recording']['id'])):
|
||||
track_id = track_data['id']
|
||||
recording_id = track_data['recording']['id']
|
||||
yield self.url_result(
|
||||
f'https://app.idagio.com/recordings/{recording_id}?trackId={track_id}',
|
||||
ie=IdagioTrackIE, video_id=track_id)
|
||||
|
||||
def _real_extract(self, url):
|
||||
playlist_id = self._match_id(url)
|
||||
playlist_info = self._download_json(
|
||||
self._API_URL_TMPL.format(playlist_id), playlist_id)['result']
|
||||
|
||||
return {
|
||||
'_type': 'playlist',
|
||||
self._PLAYLIST_ID_KEY: playlist_id,
|
||||
'entries': self._entries(playlist_info),
|
||||
**self._parse_playlist_metadata(playlist_info),
|
||||
}
|
||||
|
||||
|
||||
class IdagioRecordingIE(IdagioPlaylistBaseIE):
|
||||
_VALID_URL = r'https?://(?:www\.)?app\.idagio\.com/recordings/(?P<id>\d+)(?![^#]*[&?]trackId=\d+)'
|
||||
_TESTS = [{
|
||||
'url': 'https://app.idagio.com/recordings/30576934',
|
||||
'info_dict': {
|
||||
'id': '30576934',
|
||||
'title': 'Variations on an Original Theme op. 36',
|
||||
'composers': ['Edward Elgar'],
|
||||
'artists': ['Vasily Petrenko', 'Royal Liverpool Philharmonic Orchestra'],
|
||||
'genres': ['Orchestral', 'Other Orchestral Music'],
|
||||
'timestamp': 1554474370,
|
||||
'modified_timestamp': 1554474370,
|
||||
'modified_date': '20190405',
|
||||
'upload_date': '20190405',
|
||||
},
|
||||
'playlist_count': 15,
|
||||
}]
|
||||
_API_URL_TMPL = 'https://api.idagio.com/v2.0/metadata/recordings/{}'
|
||||
|
||||
def _parse_playlist_metadata(self, playlist_info):
|
||||
return traverse_obj(playlist_info, {
|
||||
'title': ('work', 'title', {str}),
|
||||
'timestamp': ('created_at', {int_or_none(scale=1000)}),
|
||||
'modified_timestamp': ('created_at', {int_or_none(scale=1000)}),
|
||||
'location': ('location', {str}),
|
||||
'artists': (('conductor', ('ensembles', ...), ('soloists', ...)), 'name', {str}),
|
||||
'composers': ('work', 'composer', 'name', {str}, all),
|
||||
'genres': ('work', ('genre', 'subgenre'), 'title', {str}),
|
||||
'tags': ('tags', ..., {str}),
|
||||
})
|
||||
|
||||
|
||||
class IdagioAlbumIE(IdagioPlaylistBaseIE):
|
||||
_VALID_URL = r'https?://(?:www\.)?app\.idagio\.com/albums/(?P<id>[\w-]+)'
|
||||
_TESTS = [{
|
||||
'url': 'https://app.idagio.com/albums/elgar-enigma-variations-in-the-south-serenade-for-strings',
|
||||
'info_dict': {
|
||||
'id': 'a9f139b8-f70d-4b8a-a9a4-5fe8d35eaf9c',
|
||||
'display_id': 'elgar-enigma-variations-in-the-south-serenade-for-strings',
|
||||
'title': 'Elgar: Enigma Variations, In the South, Serenade for Strings',
|
||||
'description': '',
|
||||
'thumbnail': 'https://idagio-images.global.ssl.fastly.net/albums/880040420521/main.jpg',
|
||||
'artists': ['Vasily Petrenko', 'Royal Liverpool Philharmonic Orchestra', 'Edward Elgar'],
|
||||
'timestamp': 1553817600,
|
||||
'upload_date': '20190329',
|
||||
'modified_timestamp': 1562566559.0,
|
||||
'modified_date': '20190708',
|
||||
},
|
||||
'playlist_count': 19,
|
||||
}, {
|
||||
'url': 'https://app.idagio.com/albums/brahms-ein-deutsches-requiem-3B403DF6-62D7-4A42-807B-47173F3E0192',
|
||||
'info_dict': {
|
||||
'id': '2862ad4e-4a61-45ad-9ce4-7fcf0c2626fe',
|
||||
'display_id': 'brahms-ein-deutsches-requiem-3B403DF6-62D7-4A42-807B-47173F3E0192',
|
||||
'title': 'Brahms: Ein deutsches Requiem',
|
||||
'description': '',
|
||||
'thumbnail': 'https://idagio-images.global.ssl.fastly.net/albums/3149020954522/main.jpg',
|
||||
'tags': ['recent-release'],
|
||||
'artists': ['Sabine Devieilhe', 'Stéphane Degout', 'Raphaël Pichon', 'Pygmalion', 'Johannes Brahms'],
|
||||
'timestamp': 1760054400,
|
||||
'upload_date': '20251010',
|
||||
'modified_timestamp': 1760101611,
|
||||
'modified_date': '20251010',
|
||||
},
|
||||
'playlist_count': 7,
|
||||
}]
|
||||
_API_URL_TMPL = 'https://api.idagio.com/v2.0/metadata/albums/{}'
|
||||
_PLAYLIST_ID_KEY = 'display_id'
|
||||
|
||||
def _parse_playlist_metadata(self, playlist_info):
|
||||
return traverse_obj(playlist_info, {
|
||||
'id': ('id', {str}),
|
||||
'title': ('title', {str}),
|
||||
'timestamp': ('publishDate', {unified_timestamp}),
|
||||
'modified_timestamp': ('lastModified', {unified_timestamp}),
|
||||
'thumbnail': ('imageUrl', {url_or_none}),
|
||||
'description': ('description', {str}),
|
||||
'artists': ('participants', ..., 'name', {str}),
|
||||
'tags': ('tags', ..., {str}),
|
||||
})
|
||||
|
||||
|
||||
class IdagioPlaylistIE(IdagioPlaylistBaseIE):
|
||||
_VALID_URL = r'https?://(?:www\.)?app\.idagio\.com/playlists/(?!personal/)(?P<id>[\w-]+)'
|
||||
_TESTS = [{
|
||||
'url': 'https://app.idagio.com/playlists/beethoven-the-most-beautiful-piano-music',
|
||||
'info_dict': {
|
||||
'id': '31652bec-8c5b-460e-a3f0-cf1f69817f53',
|
||||
'display_id': 'beethoven-the-most-beautiful-piano-music',
|
||||
'title': 'Beethoven: the most beautiful piano music',
|
||||
'description': 'md5:d41bb04b8896bb69377f5c2cd9345ad1',
|
||||
'thumbnail': r're:https://.+/playlists/31652bec-8c5b-460e-a3f0-cf1f69817f53/main\.jpg',
|
||||
'creators': ['IDAGIO'],
|
||||
},
|
||||
'playlist_mincount': 16, # one entry is geo-restricted
|
||||
}]
|
||||
_API_URL_TMPL = 'https://api.idagio.com/v2.0/playlists/{}'
|
||||
_PLAYLIST_ID_KEY = 'display_id'
|
||||
|
||||
def _parse_playlist_metadata(self, playlist_info):
|
||||
return traverse_obj(playlist_info, {
|
||||
'id': ('id', {str}),
|
||||
'title': ('title', {str}),
|
||||
'thumbnail': ('imageUrl', {url_or_none}),
|
||||
'description': ('description', {str}),
|
||||
'creators': ('curator', 'name', {str}, all),
|
||||
})
|
||||
|
||||
|
||||
class IdagioPersonalPlaylistIE(IdagioPlaylistBaseIE):
|
||||
_VALID_URL = r'https?://(?:www\.)?app\.idagio\.com/playlists/personal/(?P<id>[\da-f-]+)'
|
||||
_TESTS = [{
|
||||
'url': 'https://app.idagio.com/playlists/personal/99dad72e-7b3a-45a4-b216-867c08046ed8',
|
||||
'info_dict': {
|
||||
'id': '99dad72e-7b3a-45a4-b216-867c08046ed8',
|
||||
'title': 'Test',
|
||||
'creators': ['1a6f16a6-4514-4d0c-b481-3a9877835626'],
|
||||
'thumbnail': r're:https://.+/artists/86371/main\.jpg',
|
||||
'timestamp': 1602859138,
|
||||
'modified_timestamp': 1755616667,
|
||||
'upload_date': '20201016',
|
||||
'modified_date': '20250819',
|
||||
},
|
||||
'playlist_count': 100,
|
||||
}]
|
||||
_API_URL_TMPL = 'https://api.idagio.com/v1.0/personal-playlists/{}'
|
||||
|
||||
def _parse_playlist_metadata(self, playlist_info):
|
||||
return traverse_obj(playlist_info, {
|
||||
'title': ('title', {str}),
|
||||
'thumbnail': ('image_url', {url_or_none}),
|
||||
'creators': ('user_id', {str}, all),
|
||||
'timestamp': ('created_at', {int_or_none(scale=1000)}),
|
||||
'modified_timestamp': ('updated_at', {int_or_none(scale=1000)}),
|
||||
})
|
||||
@@ -248,35 +248,17 @@ class SlidesLiveIE(InfoExtractor):
|
||||
'skip_download': 'm3u8',
|
||||
},
|
||||
}, {
|
||||
# /v3/ slides, .jpg and .png, service_name = youtube
|
||||
# /v3/ slides, .jpg and .png, formerly service_name = youtube, now native
|
||||
'url': 'https://slideslive.com/embed/38932460/',
|
||||
'info_dict': {
|
||||
'id': 'RTPdrgkyTiE',
|
||||
'display_id': '38932460',
|
||||
'id': '38932460',
|
||||
'ext': 'mp4',
|
||||
'title': 'Active Learning for Hierarchical Multi-Label Classification',
|
||||
'description': 'Watch full version of this video at https://slideslive.com/38932460.',
|
||||
'channel': 'SlidesLive Videos - A',
|
||||
'channel_id': 'UC62SdArr41t_-_fX40QCLRw',
|
||||
'channel_url': 'https://www.youtube.com/channel/UC62SdArr41t_-_fX40QCLRw',
|
||||
'uploader': 'SlidesLive Videos - A',
|
||||
'uploader_id': '@slideslivevideos-a6075',
|
||||
'uploader_url': 'https://www.youtube.com/@slideslivevideos-a6075',
|
||||
'upload_date': '20200903',
|
||||
'timestamp': 1697805922,
|
||||
'duration': 942,
|
||||
'age_limit': 0,
|
||||
'live_status': 'not_live',
|
||||
'playable_in_embed': True,
|
||||
'availability': 'unlisted',
|
||||
'categories': ['People & Blogs'],
|
||||
'tags': [],
|
||||
'channel_follower_count': int,
|
||||
'like_count': int,
|
||||
'view_count': int,
|
||||
'thumbnail': r're:^https?://.*\.(?:jpg|png|webp)',
|
||||
'thumbnails': 'count:21',
|
||||
'duration': 941,
|
||||
'thumbnail': r're:https?://.+/.+\.(?:jpg|png)',
|
||||
'chapters': 'count:20',
|
||||
'timestamp': 1708338974,
|
||||
'upload_date': '20240219',
|
||||
},
|
||||
'params': {
|
||||
'skip_download': 'm3u8',
|
||||
@@ -425,7 +407,7 @@ def _real_extract(self, url):
|
||||
|
||||
player_token = self._search_regex(r'data-player-token="([^"]+)"', webpage, 'player token')
|
||||
player_data = self._download_webpage(
|
||||
f'https://ben.slideslive.com/player/{video_id}', video_id,
|
||||
f'https://slideslive.com/player/{video_id}', video_id,
|
||||
note='Downloading player info', query={'player_token': player_token})
|
||||
player_info = self._extract_custom_m3u8_info(player_data)
|
||||
|
||||
@@ -525,7 +507,7 @@ def entries():
|
||||
yield info
|
||||
|
||||
service_data = self._download_json(
|
||||
f'https://ben.slideslive.com/player/{video_id}/slides_video_service_data',
|
||||
f'https://slideslive.com/player/{video_id}/slides_video_service_data',
|
||||
video_id, fatal=False, query={
|
||||
'player_token': player_token,
|
||||
'videos': ','.join(video_slides),
|
||||
|
||||
@@ -98,7 +98,7 @@ class TenPlayIE(InfoExtractor):
|
||||
'only_matching': True,
|
||||
}]
|
||||
_GEO_BYPASS = False
|
||||
|
||||
_GEO_COUNTRIES = ['AU']
|
||||
_AUS_AGES = {
|
||||
'G': 0,
|
||||
'PG': 15,
|
||||
@@ -208,8 +208,15 @@ def _call_playback_api(self, content_id):
|
||||
|
||||
def _real_extract(self, url):
|
||||
content_id = self._match_id(url)
|
||||
data = self._download_json(
|
||||
f'https://10.com.au/api/v1/videos/{content_id}', content_id)
|
||||
try:
|
||||
data = self._download_json(f'https://10.com.au/api/v1/videos/{content_id}', content_id)
|
||||
except ExtractorError as e:
|
||||
if (
|
||||
isinstance(e.cause, HTTPError) and e.cause.status == 403
|
||||
and 'Error 54113' in e.cause.response.read().decode()
|
||||
):
|
||||
self.raise_geo_restricted(countries=self._GEO_COUNTRIES)
|
||||
raise
|
||||
|
||||
video_data, urlh = self._call_playback_api(content_id)
|
||||
content_source_id = video_data['dai']['contentSourceId']
|
||||
|
||||
@@ -1074,9 +1074,12 @@ def _real_extract(self, url):
|
||||
fatal=False, impersonate=True) or ''
|
||||
detail = traverse_obj(
|
||||
self._get_universal_data(webpage, user_name), ('webapp.user-detail', {dict})) or {}
|
||||
if detail.get('statusCode') == 10222:
|
||||
video_count = traverse_obj(detail, ('userInfo', ('stats', 'statsV2'), 'videoCount', {int}, any))
|
||||
if not video_count and detail.get('statusCode') == 10222:
|
||||
self.raise_login_required(
|
||||
'This user\'s account is private. Log into an account that has access')
|
||||
elif video_count == 0:
|
||||
raise ExtractorError('This account does not have any videos posted', expected=True)
|
||||
sec_uid = traverse_obj(detail, ('userInfo', 'user', 'secUid', {str}))
|
||||
if sec_uid:
|
||||
fail_early = not traverse_obj(detail, ('userInfo', 'itemList', ...))
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import codecs
|
||||
import itertools
|
||||
import re
|
||||
import string
|
||||
|
||||
from .common import InfoExtractor
|
||||
from ..utils import (
|
||||
@@ -22,6 +23,47 @@
|
||||
)
|
||||
|
||||
|
||||
def to_signed_32(n):
|
||||
return n % ((-1 if n < 0 else 1) * 2**32)
|
||||
|
||||
|
||||
class _ByteGenerator:
|
||||
def __init__(self, algo_id, seed):
|
||||
try:
|
||||
self._algorithm = getattr(self, f'_algo{algo_id}')
|
||||
except AttributeError:
|
||||
raise ExtractorError(f'Unknown algorithm ID: {algo_id}')
|
||||
self._s = to_signed_32(seed)
|
||||
|
||||
def _algo1(self, s):
|
||||
# LCG (a=1664525, c=1013904223, m=2^32)
|
||||
# Ref: https://en.wikipedia.org/wiki/Linear_congruential_generator
|
||||
s = self._s = to_signed_32(s * 1664525 + 1013904223)
|
||||
return s
|
||||
|
||||
def _algo2(self, s):
|
||||
# xorshift32
|
||||
# Ref: https://en.wikipedia.org/wiki/Xorshift
|
||||
s = to_signed_32(s ^ (s << 13))
|
||||
s = to_signed_32(s ^ ((s & 0xFFFFFFFF) >> 17))
|
||||
s = self._s = to_signed_32(s ^ (s << 5))
|
||||
return s
|
||||
|
||||
def _algo3(self, s):
|
||||
# Weyl Sequence (k≈2^32*φ, m=2^32) + MurmurHash3 (fmix32)
|
||||
# Ref: https://en.wikipedia.org/wiki/Weyl_sequence
|
||||
# https://commons.apache.org/proper/commons-codec/jacoco/org.apache.commons.codec.digest/MurmurHash3.java.html
|
||||
s = self._s = to_signed_32(s + 0x9e3779b9)
|
||||
s = to_signed_32(s ^ ((s & 0xFFFFFFFF) >> 16))
|
||||
s = to_signed_32(s * to_signed_32(0x85ebca77))
|
||||
s = to_signed_32(s ^ ((s & 0xFFFFFFFF) >> 13))
|
||||
s = to_signed_32(s * to_signed_32(0xc2b2ae3d))
|
||||
return to_signed_32(s ^ ((s & 0xFFFFFFFF) >> 16))
|
||||
|
||||
def __next__(self):
|
||||
return self._algorithm(self._s) & 0xFF
|
||||
|
||||
|
||||
class XHamsterIE(InfoExtractor):
|
||||
_DOMAINS = r'(?:xhamster\.(?:com|one|desi)|xhms\.pro|xhamster\d+\.(?:com|desi)|xhday\.com|xhvid\.com)'
|
||||
_VALID_URL = rf'''(?x)
|
||||
@@ -146,6 +188,12 @@ class XHamsterIE(InfoExtractor):
|
||||
_XOR_KEY = b'xh7999'
|
||||
|
||||
def _decipher_format_url(self, format_url, format_id):
|
||||
if all(char in string.hexdigits for char in format_url):
|
||||
byte_data = bytes.fromhex(format_url)
|
||||
seed = int.from_bytes(byte_data[1:5], byteorder='little', signed=True)
|
||||
byte_gen = _ByteGenerator(byte_data[0], seed)
|
||||
return bytearray(byte ^ next(byte_gen) for byte in byte_data[5:]).decode('latin-1')
|
||||
|
||||
cipher_type, _, ciphertext = try_call(
|
||||
lambda: base64.b64decode(format_url).decode().partition('_')) or [None] * 3
|
||||
|
||||
@@ -164,6 +212,16 @@ def _decipher_format_url(self, format_url, format_id):
|
||||
self.report_warning(f'Skipping format "{format_id}": unsupported cipher type "{cipher_type}"')
|
||||
return None
|
||||
|
||||
def _fixup_formats(self, formats):
|
||||
for f in formats:
|
||||
if f.get('vcodec'):
|
||||
continue
|
||||
for vcodec in ('av1', 'h264'):
|
||||
if any(f'.{vcodec}.' in f_url for f_url in (f['url'], f.get('manifest_url', ''))):
|
||||
f['vcodec'] = vcodec
|
||||
break
|
||||
return formats
|
||||
|
||||
def _real_extract(self, url):
|
||||
mobj = self._match_valid_url(url)
|
||||
video_id = mobj.group('id') or mobj.group('id_2')
|
||||
@@ -312,7 +370,8 @@ def get_height(s):
|
||||
'comment_count': int_or_none(video.get('comments')),
|
||||
'age_limit': age_limit if age_limit is not None else 18,
|
||||
'categories': categories,
|
||||
'formats': formats,
|
||||
'formats': self._fixup_formats(formats),
|
||||
'_format_sort_fields': ('res', 'proto', 'tbr'),
|
||||
}
|
||||
|
||||
# Old layout fallback
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Autogenerated by devscripts/update-version.py
|
||||
|
||||
__version__ = '2025.09.26'
|
||||
__version__ = '2025.10.14'
|
||||
|
||||
RELEASE_GIT_HEAD = '12b57d2858845c0c7fb33bf9aa8ed7be6905535d'
|
||||
RELEASE_GIT_HEAD = 'a98e7f9f58a9492d2cb216baa59c890ed8ce02f3'
|
||||
|
||||
VARIANT = None
|
||||
|
||||
@@ -12,4 +12,4 @@
|
||||
|
||||
ORIGIN = 'yt-dlp/yt-dlp'
|
||||
|
||||
_pkg_version = '2025.09.26'
|
||||
_pkg_version = '2025.10.14'
|
||||
|
||||
Reference in New Issue
Block a user