|
|
@ -10,6 +10,7 @@ from .common import InfoExtractor
|
|
|
|
from ..compat import (
|
|
|
|
from ..compat import (
|
|
|
|
compat_str,
|
|
|
|
compat_str,
|
|
|
|
compat_urllib_parse_urlencode,
|
|
|
|
compat_urllib_parse_urlencode,
|
|
|
|
|
|
|
|
compat_urllib_parse_unquote
|
|
|
|
)
|
|
|
|
)
|
|
|
|
from .openload import PhantomJSwrapper
|
|
|
|
from .openload import PhantomJSwrapper
|
|
|
|
from ..utils import (
|
|
|
|
from ..utils import (
|
|
|
@ -17,6 +18,7 @@ from ..utils import (
|
|
|
|
decode_packed_codes,
|
|
|
|
decode_packed_codes,
|
|
|
|
ExtractorError,
|
|
|
|
ExtractorError,
|
|
|
|
float_or_none,
|
|
|
|
float_or_none,
|
|
|
|
|
|
|
|
format_field,
|
|
|
|
get_element_by_id,
|
|
|
|
get_element_by_id,
|
|
|
|
get_element_by_attribute,
|
|
|
|
get_element_by_attribute,
|
|
|
|
int_or_none,
|
|
|
|
int_or_none,
|
|
|
@ -431,6 +433,10 @@ class IqIE(InfoExtractor):
|
|
|
|
'format': '500',
|
|
|
|
'format': '500',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
'expected_warnings': ['format is restricted']
|
|
|
|
'expected_warnings': ['format is restricted']
|
|
|
|
|
|
|
|
}, {
|
|
|
|
|
|
|
|
# VIP-restricted video
|
|
|
|
|
|
|
|
'url': 'https://www.iq.com/play/mermaid-in-the-fog-2021-gbdpx13bs4',
|
|
|
|
|
|
|
|
'only_matching': True
|
|
|
|
}]
|
|
|
|
}]
|
|
|
|
_BID_TAGS = {
|
|
|
|
_BID_TAGS = {
|
|
|
|
'100': '240P',
|
|
|
|
'100': '240P',
|
|
|
@ -457,8 +463,8 @@ class IqIE(InfoExtractor):
|
|
|
|
_DASH_JS = '''
|
|
|
|
_DASH_JS = '''
|
|
|
|
console.log(page.evaluate(function() {
|
|
|
|
console.log(page.evaluate(function() {
|
|
|
|
var tvid = "%(tvid)s"; var vid = "%(vid)s"; var src = "%(src)s";
|
|
|
|
var tvid = "%(tvid)s"; var vid = "%(vid)s"; var src = "%(src)s";
|
|
|
|
var dfp = "%(dfp)s"; var mode = "%(mode)s"; var lang = "%(lang)s"; var bid_list = %(bid_list)s;
|
|
|
|
var uid = "%(uid)s"; var dfp = "%(dfp)s"; var mode = "%(mode)s"; var lang = "%(lang)s";
|
|
|
|
var tm = new Date().getTime();
|
|
|
|
var bid_list = %(bid_list)s; var ut_list = %(ut_list)s; var tm = new Date().getTime();
|
|
|
|
var cmd5x_func = %(cmd5x_func)s; var cmd5x_exporter = {}; cmd5x_func({}, cmd5x_exporter, {}); var cmd5x = cmd5x_exporter.cmd5x;
|
|
|
|
var cmd5x_func = %(cmd5x_func)s; var cmd5x_exporter = {}; cmd5x_func({}, cmd5x_exporter, {}); var cmd5x = cmd5x_exporter.cmd5x;
|
|
|
|
var authKey = cmd5x(cmd5x('') + tm + '' + tvid);
|
|
|
|
var authKey = cmd5x(cmd5x('') + tm + '' + tvid);
|
|
|
|
var k_uid = Array.apply(null, Array(32)).map(function() {return Math.floor(Math.random() * 15).toString(16)}).join('');
|
|
|
|
var k_uid = Array.apply(null, Array(32)).map(function() {return Math.floor(Math.random() * 15).toString(16)}).join('');
|
|
|
@ -472,7 +478,7 @@ class IqIE(InfoExtractor):
|
|
|
|
'src': src,
|
|
|
|
'src': src,
|
|
|
|
'vt': 0,
|
|
|
|
'vt': 0,
|
|
|
|
'rs': 1,
|
|
|
|
'rs': 1,
|
|
|
|
'uid': 0,
|
|
|
|
'uid': uid,
|
|
|
|
'ori': 'pcw',
|
|
|
|
'ori': 'pcw',
|
|
|
|
'ps': 1,
|
|
|
|
'ps': 1,
|
|
|
|
'k_uid': k_uid,
|
|
|
|
'k_uid': k_uid,
|
|
|
@ -509,12 +515,14 @@ class IqIE(InfoExtractor):
|
|
|
|
'version': '10.0',
|
|
|
|
'version': '10.0',
|
|
|
|
'dfp': dfp
|
|
|
|
'dfp': dfp
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
'ut': 0, // TODO: Set ut param for VIP members
|
|
|
|
|
|
|
|
};
|
|
|
|
};
|
|
|
|
var enc_params = [];
|
|
|
|
var enc_params = [];
|
|
|
|
for (var prop in query) {
|
|
|
|
for (var prop in query) {
|
|
|
|
enc_params.push(encodeURIComponent(prop) + '=' + encodeURIComponent(query[prop]));
|
|
|
|
enc_params.push(encodeURIComponent(prop) + '=' + encodeURIComponent(query[prop]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ut_list.forEach(function(ut) {
|
|
|
|
|
|
|
|
enc_params.push('ut=' + ut);
|
|
|
|
|
|
|
|
})
|
|
|
|
var dash_path = '/dash?' + enc_params.join('&'); dash_path += '&vf=' + cmd5x(dash_path);
|
|
|
|
var dash_path = '/dash?' + enc_params.join('&'); dash_path += '&vf=' + cmd5x(dash_path);
|
|
|
|
dash_paths[bid] = dash_path;
|
|
|
|
dash_paths[bid] = dash_path;
|
|
|
|
});
|
|
|
|
});
|
|
|
@ -571,17 +579,37 @@ class IqIE(InfoExtractor):
|
|
|
|
page_data = next_props['initialState']['play']
|
|
|
|
page_data = next_props['initialState']['play']
|
|
|
|
video_info = page_data['curVideoInfo']
|
|
|
|
video_info = page_data['curVideoInfo']
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uid = traverse_obj(
|
|
|
|
|
|
|
|
self._parse_json(
|
|
|
|
|
|
|
|
self._get_cookie('I00002', '{}'), video_id, transform_source=compat_urllib_parse_unquote, fatal=False),
|
|
|
|
|
|
|
|
('data', 'uid'), default=0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if uid:
|
|
|
|
|
|
|
|
vip_data = self._download_json(
|
|
|
|
|
|
|
|
'https://pcw-api.iq.com/api/vtype', video_id, note='Downloading VIP data', errnote='Unable to download VIP data', query={
|
|
|
|
|
|
|
|
'batch': 1,
|
|
|
|
|
|
|
|
'platformId': 3,
|
|
|
|
|
|
|
|
'modeCode': self._get_cookie('mod', 'intl'),
|
|
|
|
|
|
|
|
'langCode': self._get_cookie('lang', 'en_us'),
|
|
|
|
|
|
|
|
'deviceId': self._get_cookie('QC005', '')
|
|
|
|
|
|
|
|
}, fatal=False)
|
|
|
|
|
|
|
|
ut_list = traverse_obj(vip_data, ('data', 'all_vip', ..., 'vipType'), expected_type=str_or_none, default=[])
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
ut_list = ['0']
|
|
|
|
|
|
|
|
|
|
|
|
# bid 0 as an initial format checker
|
|
|
|
# bid 0 as an initial format checker
|
|
|
|
dash_paths = self._parse_json(PhantomJSwrapper(self).get(
|
|
|
|
dash_paths = self._parse_json(PhantomJSwrapper(self).get(
|
|
|
|
url, html='<!DOCTYPE html>', video_id=video_id, note2='Executing signature code', jscode=self._DASH_JS % {
|
|
|
|
url, html='<!DOCTYPE html>', video_id=video_id, note2='Executing signature code', jscode=self._DASH_JS % {
|
|
|
|
'tvid': video_info['tvId'],
|
|
|
|
'tvid': video_info['tvId'],
|
|
|
|
'vid': video_info['vid'],
|
|
|
|
'vid': video_info['vid'],
|
|
|
|
'src': traverse_obj(next_props, ('initialProps', 'pageProps', 'ptid'),
|
|
|
|
'src': traverse_obj(next_props, ('initialProps', 'pageProps', 'ptid'),
|
|
|
|
expected_type=str, default='01010031010018000000'),
|
|
|
|
expected_type=str, default='04022001010011000000'),
|
|
|
|
|
|
|
|
'uid': uid,
|
|
|
|
'dfp': self._get_cookie('dfp', ''),
|
|
|
|
'dfp': self._get_cookie('dfp', ''),
|
|
|
|
'mode': self._get_cookie('mod', 'intl'),
|
|
|
|
'mode': self._get_cookie('mod', 'intl'),
|
|
|
|
'lang': self._get_cookie('lang', 'en_us'),
|
|
|
|
'lang': self._get_cookie('lang', 'en_us'),
|
|
|
|
'bid_list': '[' + ','.join(['0', *self._BID_TAGS.keys()]) + ']',
|
|
|
|
'bid_list': '[' + ','.join(['0', *self._BID_TAGS.keys()]) + ']',
|
|
|
|
|
|
|
|
'ut_list': '[' + ','.join(ut_list) + ']',
|
|
|
|
'cmd5x_func': self._extract_cmd5x_function(webpage, video_id),
|
|
|
|
'cmd5x_func': self._extract_cmd5x_function(webpage, video_id),
|
|
|
|
})[1].strip(), video_id)
|
|
|
|
})[1].strip(), video_id)
|
|
|
|
|
|
|
|
|
|
|
@ -590,9 +618,10 @@ class IqIE(InfoExtractor):
|
|
|
|
urljoin('https://cache-video.iq.com', dash_paths['0']), video_id,
|
|
|
|
urljoin('https://cache-video.iq.com', dash_paths['0']), video_id,
|
|
|
|
note='Downloading initial video format info', errnote='Unable to download initial video format info')['data']
|
|
|
|
note='Downloading initial video format info', errnote='Unable to download initial video format info')['data']
|
|
|
|
|
|
|
|
|
|
|
|
preview_time = traverse_obj(initial_format_data, ('boss_ts', 'data', 'previewTime'), expected_type=float_or_none)
|
|
|
|
preview_time = traverse_obj(
|
|
|
|
if preview_time:
|
|
|
|
initial_format_data, ('boss_ts', (None, 'data'), ('previewTime', 'rtime')), expected_type=float_or_none, get_all=False)
|
|
|
|
self.report_warning(f'This preview video is limited to {preview_time} seconds')
|
|
|
|
if traverse_obj(initial_format_data, ('boss_ts', 'data', 'prv'), expected_type=int_or_none):
|
|
|
|
|
|
|
|
self.report_warning('This preview video is limited%s' % format_field(preview_time, template='to %s seconds'))
|
|
|
|
|
|
|
|
|
|
|
|
# TODO: Extract audio-only formats
|
|
|
|
# TODO: Extract audio-only formats
|
|
|
|
for bid in set(traverse_obj(initial_format_data, ('program', 'video', ..., 'bid'), expected_type=str_or_none, default=[])):
|
|
|
|
for bid in set(traverse_obj(initial_format_data, ('program', 'video', ..., 'bid'), expected_type=str_or_none, default=[])):
|
|
|
|