5 from .common
import InfoExtractor
18 from ..utils
.traversal
import traverse_obj
21 class OnDemandKoreaIE(InfoExtractor
):
22 _VALID_URL
= r
'https?://(?:www\.)?ondemandkorea\.com/(?:en/)?player/vod/[a-z0-9-]+\?(?:[^#]+&)?contentId=(?P<id>\d+)'
23 _GEO_COUNTRIES
= ['US', 'CA']
26 'url': 'https://www.ondemandkorea.com/player/vod/ask-us-anything?contentId=686471',
27 'md5': 'e2ff77255d989e3135bde0c5889fbce8',
31 'title': 'Ask Us Anything: Jung Sung-ho, Park Seul-gi, Kim Bo-min, Yang Seung-won',
32 'thumbnail': r
're:^https?://.*\.(jpg|jpeg|png)',
34 'release_date': '20220924',
35 'series': 'Ask Us Anything',
37 'episode_number': 351,
38 'episode': 'Jung Sung-ho, Park Seul-gi, Kim Bo-min, Yang Seung-won',
41 'url': 'https://www.ondemandkorea.com/player/vod/breakup-probation-a-week?contentId=1595796',
42 'md5': '57266c720006962be7ff415b24775caa',
46 'title': 'Breakup Probation, A Week: E08',
47 'thumbnail': r
're:^https?://.*\.(jpg|jpeg|png)',
49 'release_date': '20231001',
50 'series': 'Breakup Probation, A Week',
56 'url': 'https://www.ondemandkorea.com/player/vod/the-outlaws?contentId=369531',
57 'md5': 'fa5523b87aa1f6d74fc622a97f2b47cd',
61 'release_date': '20220519',
63 'title': 'The Outlaws: Main Movie',
64 'thumbnail': r
're:^https?://.*\.(jpg|jpeg|png)',
68 'url': 'https://www.ondemandkorea.com/en/player/vod/capture-the-moment-how-is-that-possible?contentId=1605006',
69 'only_matching': True,
72 def _real_extract(self
, url
):
73 video_id
= self
._match
_id
(url
)
75 data
= self
._download
_json
(
76 f
'https://odkmedia.io/odx/api/v3/playback/{video_id}/', video_id
, fatal
=False,
77 headers
={'service-name': 'odk'}, query
={'did': str(uuid
.uuid4())}, expected_status
=(403, 404))
78 if not traverse_obj(data
, ('result', {dict}
)):
79 msg
= traverse_obj(data
, ('messages', '__default'), 'title', expected_type
=str)
80 raise ExtractorError(msg
or 'Got empty response from playback API', expected
=True)
84 def try_geo_bypass(url
):
85 return traverse_obj(url
, ({parse_qs}
, 'stream_url', 0, {url_or_none}
)) or url
88 for m3u8_url
in traverse_obj(data
, (('sources', 'manifest'), ..., 'url', {url_or_none}
, {try_geo_bypass}
)):
89 mod_url
= re
.sub(r
'_720(p?)\.m3u8', r
'_1080\1.m3u8', m3u8_url
)
90 if mod_url
!= m3u8_url
:
91 mod_format
= self
._extract
_m
3u8_formats
(
92 mod_url
, video_id
, note
='Checking for higher quality format',
93 errnote
='No higher quality format found', fatal
=False)
95 formats
.extend(mod_format
)
97 formats
.extend(self
._extract
_m
3u8_formats
(m3u8_url
, video_id
, fatal
=False))
100 for track
in traverse_obj(data
, ('text_tracks', lambda _
, v
: url_or_none(v
['url']))):
101 subtitles
.setdefault(track
.get('language', 'und'), []).append({
103 'ext': track
.get('codec'),
104 'name': track
.get('label'),
107 def if_series(key
=None):
108 return lambda obj
: obj
[key
] if key
and obj
['kind'] == 'series' else None
112 'title': join_nonempty(
113 ('episode', 'program', 'title'),
114 ('episode', 'title'), from_dict
=data
, delim
=': '),
115 **traverse_obj(data
, {
116 'thumbnail': ('episode', 'images', 'thumbnail', {url_or_none}
),
117 'release_date': ('episode', 'release_date', {lambda x
: x
.replace('-', '')}, {unified_strdate}
),
118 'duration': ('duration', {functools
.partial(float_or_none
, scale
=1000)}),
119 'age_limit': ('age_rating', 'name', {lambda x
: x
.replace('R', '')}, {parse_age_limit}
),
120 'series': ('episode', {if_series(key
='program')}, 'title'),
121 'series_id': ('episode', {if_series(key
='program')}, 'id', {str_or_none}
),
122 'episode': ('episode', {if_series(key
='title')}),
123 'episode_number': ('episode', {if_series(key
='number')}, {int_or_none}
),
126 'subtitles': subtitles
,
130 class OnDemandKoreaProgramIE(InfoExtractor
):
131 _VALID_URL
= r
'https?://(?:www\.)?ondemandkorea\.com/(?:en/)?player/vod/(?P<id>[a-z0-9-]+)(?:$|#)'
132 _GEO_COUNTRIES
= ['US', 'CA']
135 'url': 'https://www.ondemandkorea.com/player/vod/uskn-news',
139 'playlist_mincount': 755,
141 'url': 'https://www.ondemandkorea.com/en/player/vod/the-land',
145 'playlist_count': 52,
150 def _fetch_page(self
, display_id
, page
):
152 page_data
= self
._download
_json
(
153 f
'https://odkmedia.io/odx/api/v3/program/{display_id}/episodes/', display_id
,
154 headers
={'service-name': 'odk'}, query
={
156 'page_size': self
._PAGE
_SIZE
,
157 }, note
=f
'Downloading page {page}', expected_status
=404)
158 for episode
in traverse_obj(page_data
, ('result', 'results', ...)):
159 yield self
.url_result(
160 f
'https://www.ondemandkorea.com/player/vod/{display_id}?contentId={episode["id"]}',
161 ie
=OnDemandKoreaIE
, video_title
=episode
.get('title'))
163 def _real_extract(self
, url
):
164 display_id
= self
._match
_id
(url
)
166 entries
= OnDemandPagedList(functools
.partial(
167 self
._fetch
_page
, display_id
), self
._PAGE
_SIZE
)
169 return self
.playlist_result(entries
, display_id
)