Compare commits

...

5 Commits

Author SHA1 Message Date
Aaron Tan
e7ee7d756e
Merge e1dc38319cb5974496b9877958d491cec157a3a0 into 3eb8d22ddb8982ca4fb56bb7a8d6517538bf14c6 2025-04-01 08:06:52 +02:00
dirkf
3eb8d22ddb
[JSInterp] Temporary fix for #33102 2025-03-31 04:21:09 +01:00
dirkf
4e714f9df1 [Misc] Correct [_]IE_DESC/NAME in a few IEs
* thx seproDev, yt-dlp/yt-dlp/pull/12694/commits/ae69e3c
* also add documenting comment in `InfoExtractor`
2025-03-26 12:47:19 +00:00
dirkf
c1ea7f5a24 [ITV] Mark ITVX not working
* update old shim
* correct [_]IE_DESC
2025-03-26 12:17:49 +00:00
Aaron Tan
e1dc38319c [erocast] Update erocast
Build on code from PR #31631.
- Add playlist info extractor to download playlists
- Refactor code from suggestions by @dirkf
2023-08-16 16:24:46 +10:00
8 changed files with 115 additions and 15 deletions

View File

@ -32,7 +32,7 @@ class BokeCCBaseIE(InfoExtractor):
class BokeCCIE(BokeCCBaseIE): class BokeCCIE(BokeCCBaseIE):
_IE_DESC = 'CC视频' IE_DESC = 'CC视频'
_VALID_URL = r'https?://union\.bokecc\.com/playvideo\.bo\?(?P<query>.*)' _VALID_URL = r'https?://union\.bokecc\.com/playvideo\.bo\?(?P<query>.*)'
_TESTS = [{ _TESTS = [{

View File

@ -9,7 +9,7 @@ from ..utils import (
class CloudyIE(InfoExtractor): class CloudyIE(InfoExtractor):
_IE_DESC = 'cloudy.ec' IE_DESC = 'cloudy.ec'
_VALID_URL = r'https?://(?:www\.)?cloudy\.ec/(?:v/|embed\.php\?.*?\bid=)(?P<id>[A-Za-z0-9]+)' _VALID_URL = r'https?://(?:www\.)?cloudy\.ec/(?:v/|embed\.php\?.*?\bid=)(?P<id>[A-Za-z0-9]+)'
_TESTS = [{ _TESTS = [{
'url': 'https://www.cloudy.ec/v/af511e2527aac', 'url': 'https://www.cloudy.ec/v/af511e2527aac',

View File

@ -422,6 +422,8 @@ class InfoExtractor(object):
_GEO_COUNTRIES = None _GEO_COUNTRIES = None
_GEO_IP_BLOCKS = None _GEO_IP_BLOCKS = None
_WORKING = True _WORKING = True
# supply this in public subclasses: used in supported sites list, etc
# IE_DESC = 'short description of IE'
def __init__(self, downloader=None): def __init__(self, downloader=None):
"""Constructor. Receives an optional downloader.""" """Constructor. Receives an optional downloader."""

View File

@ -0,0 +1,99 @@
# coding: utf-8
from __future__ import unicode_literals
from .common import InfoExtractor
from ..utils import traverse_obj
import re
class ErocastIE(InfoExtractor):
IE_NAME = 'erocast'
_VALID_URL = r'https?://(?:www\.)?erocast\.me/track/(?P<id>[0-9]+)/(?P<display_id>[0-9a-zA-Z_-]+)'
_TESTS = [{
'url': 'https://erocast.me/track/6508/piano-sample-by-ytdl',
'md5': '6764726b2d19161e93c9cf3a9a69800a',
'info_dict': {
'id': '6508',
'ext': 'mp4',
'title': 'Piano sample by ytdl',
'uploader': 'ytdl',
}
}, {
'url': 'https://erocast.me/track/4254/intimate-morning-with-your-wife',
'md5': '45b06c21cf93612dd72a3d764c0bb362',
'info_dict': {
'id': '4254',
'ext': 'mp4',
'title': 'Intimate morning with your wife',
'uploader': 'ZLOY_ASMR',
}
}, {
'url': 'https://erocast.me/playlist/2278/rough-hot-and-dirty',
'only_matching': True
}]
def _real_extract(self, url):
video_id = self._match_id(url)
webpage = self._download_webpage(url, video_id)
# The Song data is in a script tag with the following format:
# (see https://github.com/ytdl-org/youtube-dl/issues/31203#issuecomment-1259867716)
searchPattern = r'<script\b[^>]*>var\s+song_data_%s\s*=\s*(.+?)</script>' % re.escape(video_id)
jsonString = self._html_search_regex(searchPattern, webpage, 'song_data')
# The data is in JSON format, so we convert the JSON String to a python object
# and read the data from this json object
jsonObject = self._parse_json(jsonString, None, fatal=False)
audio_url = jsonObject['stream_url']
title = jsonObject['title']
user_name = traverse_obj(jsonObject, ('user', 'name'), expected_type=lambda x: x.strip() or None)
# The audio url is a m3u8 playlist, so we extract the audio url from this playlist
formats = self._extract_m3u8_formats(
audio_url, video_id, 'mp4', 'm3u8_native',
m3u8_id='hls', fatal=False)
self._sort_formats(formats)
return {
'id': video_id,
'formats': formats,
'title': title,
'uploader': user_name,
}
class ErocastPlaylistIE(InfoExtractor):
_VALID_URL = r'https?://(?:www\.)?erocast\.me/playlist/(?P<playlist_id>[0-9]+)/(?P<playlist_title>[0-9a-zA-Z_-]+)'
_TESTS = [{
'url': 'https://erocast.me/playlist/2278/rough-hot-and-dirty',
'info_dict': {
'id': '2278',
'title': 'rough-hot-and-dirty',
},
'playlist_mincount': 3,
}, {
'url': 'https://erocast.me/playlist/1841/dilf',
'info_dict': {
'id': '1841',
'title': 'dilf',
},
'playlist_mincount': 7,
}]
def _real_extract(self, url):
mobj = re.match(self._VALID_URL, url)
playlist_id = mobj.group('playlist_id')
title = mobj.group('playlist_title')
webpage = self._download_webpage(url, playlist_id)
# Get URL for each track in the playlist
entries = [self.url_result(
'https://erocast.me/track/' + mobj.group('song_id') + '/' + mobj.group('track_url'),
ie=ErocastIE.ie_key(), video_id=mobj.group('song_id'))
for mobj in re.finditer(
r'<script\b[^>]*>var\s+song_data_(?P<song_id>[0-9]+)\s*=\s*.+?\\/track\\/[0-9]+\\/(?P<track_url>.+)\"\,\"stream_url.+?</script>', webpage)]
return self.playlist_result(entries, playlist_id, title)

View File

@ -360,6 +360,10 @@ from .embedly import EmbedlyIE
from .engadget import EngadgetIE from .engadget import EngadgetIE
from .epidemicsound import EpidemicSoundIE from .epidemicsound import EpidemicSoundIE
from .eporner import EpornerIE from .eporner import EpornerIE
from .erocast import (
ErocastIE,
ErocastPlaylistIE,
)
from .eroprofile import EroProfileIE from .eroprofile import EroProfileIE
from .escapist import EscapistIE from .escapist import EscapistIE
from .espn import ( from .espn import (

View File

@ -35,15 +35,6 @@ from ..utils import (
class ITVBaseIE(InfoExtractor): class ITVBaseIE(InfoExtractor):
def _search_nextjs_data(self, webpage, video_id, **kw):
transform_source = kw.pop('transform_source', None)
fatal = kw.pop('fatal', True)
return self._parse_json(
self._search_regex(
r'''<script\b[^>]+\bid=('|")__NEXT_DATA__\1[^>]*>(?P<js>[^<]+)</script>''',
webpage, 'next.js data', group='js', fatal=fatal, **kw),
video_id, transform_source=transform_source, fatal=fatal)
def __handle_request_webpage_error(self, err, video_id=None, errnote=None, fatal=True): def __handle_request_webpage_error(self, err, video_id=None, errnote=None, fatal=True):
if errnote is False: if errnote is False:
return False return False
@ -109,7 +100,9 @@ class ITVBaseIE(InfoExtractor):
class ITVIE(ITVBaseIE): class ITVIE(ITVBaseIE):
_VALID_URL = r'https?://(?:www\.)?itv\.com/(?:(?P<w>watch)|hub)/[^/]+/(?(w)[\w-]+/)(?P<id>\w+)' _VALID_URL = r'https?://(?:www\.)?itv\.com/(?:(?P<w>watch)|hub)/[^/]+/(?(w)[\w-]+/)(?P<id>\w+)'
_IE_DESC = 'ITVX' IE_DESC = 'ITVX'
_WORKING = False
_TESTS = [{ _TESTS = [{
'note': 'Hub URLs redirect to ITVX', 'note': 'Hub URLs redirect to ITVX',
'url': 'https://www.itv.com/hub/liar/2a4547a0012', 'url': 'https://www.itv.com/hub/liar/2a4547a0012',
@ -270,7 +263,7 @@ class ITVIE(ITVBaseIE):
'ext': determine_ext(href, 'vtt'), 'ext': determine_ext(href, 'vtt'),
}) })
next_data = self._search_nextjs_data(webpage, video_id, fatal=False, default='{}') next_data = self._search_nextjs_data(webpage, video_id, fatal=False, default={})
video_data.update(traverse_obj(next_data, ('props', 'pageProps', ('title', 'episode')), expected_type=dict)[0] or {}) video_data.update(traverse_obj(next_data, ('props', 'pageProps', ('title', 'episode')), expected_type=dict)[0] or {})
title = traverse_obj(video_data, 'headerTitle', 'episodeTitle') title = traverse_obj(video_data, 'headerTitle', 'episodeTitle')
info = self._og_extract(webpage, require_title=not title) info = self._og_extract(webpage, require_title=not title)
@ -323,7 +316,7 @@ class ITVIE(ITVBaseIE):
class ITVBTCCIE(ITVBaseIE): class ITVBTCCIE(ITVBaseIE):
_VALID_URL = r'https?://(?:www\.)?itv\.com/(?!(?:watch|hub)/)(?:[^/]+/)+(?P<id>[^/?#&]+)' _VALID_URL = r'https?://(?:www\.)?itv\.com/(?!(?:watch|hub)/)(?:[^/]+/)+(?P<id>[^/?#&]+)'
_IE_DESC = 'ITV articles: News, British Touring Car Championship' IE_DESC = 'ITV articles: News, British Touring Car Championship'
_TESTS = [{ _TESTS = [{
'note': 'British Touring Car Championship', 'note': 'British Touring Car Championship',
'url': 'https://www.itv.com/btcc/articles/btcc-2018-all-the-action-from-brands-hatch', 'url': 'https://www.itv.com/btcc/articles/btcc-2018-all-the-action-from-brands-hatch',

View File

@ -47,7 +47,7 @@ class SenateISVPIE(InfoExtractor):
['vetaff', '76462', 'http://vetaff-f.akamaihd.net'], ['vetaff', '76462', 'http://vetaff-f.akamaihd.net'],
['arch', '', 'http://ussenate-f.akamaihd.net/'] ['arch', '', 'http://ussenate-f.akamaihd.net/']
] ]
_IE_NAME = 'senate.gov' IE_NAME = 'senate.gov'
_VALID_URL = r'https?://(?:www\.)?senate\.gov/isvp/?\?(?P<qs>.+)' _VALID_URL = r'https?://(?:www\.)?senate\.gov/isvp/?\?(?P<qs>.+)'
_TESTS = [{ _TESTS = [{
'url': 'http://www.senate.gov/isvp/?comm=judiciary&type=live&stt=&filename=judiciary031715&auto_play=false&wmode=transparent&poster=http%3A%2F%2Fwww.judiciary.senate.gov%2Fthemes%2Fjudiciary%2Fimages%2Fvideo-poster-flash-fit.png', 'url': 'http://www.senate.gov/isvp/?comm=judiciary&type=live&stt=&filename=judiciary031715&auto_play=false&wmode=transparent&poster=http%3A%2F%2Fwww.judiciary.senate.gov%2Fthemes%2Fjudiciary%2Fimages%2Fvideo-poster-flash-fit.png',

View File

@ -686,6 +686,8 @@ class JSInterpreter(object):
raise self.Exception('Cannot get index {idx!r:.100}'.format(**locals()), expr=repr(obj), cause=e) raise self.Exception('Cannot get index {idx!r:.100}'.format(**locals()), expr=repr(obj), cause=e)
def _dump(self, obj, namespace): def _dump(self, obj, namespace):
if obj is JS_Undefined:
return 'undefined'
try: try:
return json.dumps(obj) return json.dumps(obj)
except TypeError: except TypeError: