10
10
from ..compat import (
11
11
compat_str ,
12
12
compat_urllib_parse_urlencode ,
13
+ compat_urllib_parse_unquote
13
14
)
14
15
from .openload import PhantomJSwrapper
15
16
from ..utils import (
16
17
clean_html ,
17
18
decode_packed_codes ,
18
19
ExtractorError ,
19
20
float_or_none ,
21
+ format_field ,
20
22
get_element_by_id ,
21
23
get_element_by_attribute ,
22
24
int_or_none ,
@@ -431,6 +433,10 @@ class IqIE(InfoExtractor):
431
433
'format' : '500' ,
432
434
},
433
435
'expected_warnings' : ['format is restricted' ]
436
+ }, {
437
+ # VIP-restricted video
438
+ 'url' : 'https://www.iq.com/play/mermaid-in-the-fog-2021-gbdpx13bs4' ,
439
+ 'only_matching' : True
434
440
}]
435
441
_BID_TAGS = {
436
442
'100' : '240P' ,
@@ -457,8 +463,8 @@ class IqIE(InfoExtractor):
457
463
_DASH_JS = '''
458
464
console.log(page.evaluate(function() {
459
465
var tvid = "%(tvid)s"; var vid = "%(vid)s"; var src = "%(src)s";
460
- var dfp = "%(dfp )s"; var mode = "%(mode )s"; var lang = "%(lang )s"; var bid_list = %(bid_list)s ;
461
- var tm = new Date().getTime();
466
+ var uid = "%(uid )s"; var dfp = "%(dfp )s"; var mode = "%(mode )s"; var lang = "%(lang)s" ;
467
+ var bid_list = %(bid_list)s; var ut_list = %(ut_list)s; var tm = new Date().getTime();
462
468
var cmd5x_func = %(cmd5x_func)s; var cmd5x_exporter = {}; cmd5x_func({}, cmd5x_exporter, {}); var cmd5x = cmd5x_exporter.cmd5x;
463
469
var authKey = cmd5x(cmd5x('') + tm + '' + tvid);
464
470
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):
472
478
'src': src,
473
479
'vt': 0,
474
480
'rs': 1,
475
- 'uid': 0 ,
481
+ 'uid': uid ,
476
482
'ori': 'pcw',
477
483
'ps': 1,
478
484
'k_uid': k_uid,
@@ -509,12 +515,14 @@ class IqIE(InfoExtractor):
509
515
'version': '10.0',
510
516
'dfp': dfp
511
517
}),
512
- 'ut': 0, // TODO: Set ut param for VIP members
513
518
};
514
519
var enc_params = [];
515
520
for (var prop in query) {
516
521
enc_params.push(encodeURIComponent(prop) + '=' + encodeURIComponent(query[prop]));
517
522
}
523
+ ut_list.forEach(function(ut) {
524
+ enc_params.push('ut=' + ut);
525
+ })
518
526
var dash_path = '/dash?' + enc_params.join('&'); dash_path += '&vf=' + cmd5x(dash_path);
519
527
dash_paths[bid] = dash_path;
520
528
});
@@ -571,17 +579,37 @@ def _real_extract(self, url):
571
579
page_data = next_props ['initialState' ]['play' ]
572
580
video_info = page_data ['curVideoInfo' ]
573
581
582
+ uid = traverse_obj (
583
+ self ._parse_json (
584
+ self ._get_cookie ('I00002' , '{}' ), video_id , transform_source = compat_urllib_parse_unquote , fatal = False ),
585
+ ('data' , 'uid' ), default = 0 )
586
+
587
+ if uid :
588
+ vip_data = self ._download_json (
589
+ 'https://pcw-api.iq.com/api/vtype' , video_id , note = 'Downloading VIP data' , errnote = 'Unable to download VIP data' , query = {
590
+ 'batch' : 1 ,
591
+ 'platformId' : 3 ,
592
+ 'modeCode' : self ._get_cookie ('mod' , 'intl' ),
593
+ 'langCode' : self ._get_cookie ('lang' , 'en_us' ),
594
+ 'deviceId' : self ._get_cookie ('QC005' , '' )
595
+ }, fatal = False )
596
+ ut_list = traverse_obj (vip_data , ('data' , 'all_vip' , ..., 'vipType' ), expected_type = str_or_none , default = [])
597
+ else :
598
+ ut_list = ['0' ]
599
+
574
600
# bid 0 as an initial format checker
575
601
dash_paths = self ._parse_json (PhantomJSwrapper (self ).get (
576
602
url , html = '<!DOCTYPE html>' , video_id = video_id , note2 = 'Executing signature code' , jscode = self ._DASH_JS % {
577
603
'tvid' : video_info ['tvId' ],
578
604
'vid' : video_info ['vid' ],
579
605
'src' : traverse_obj (next_props , ('initialProps' , 'pageProps' , 'ptid' ),
580
- expected_type = str , default = '01010031010018000000' ),
606
+ expected_type = str , default = '04022001010011000000' ),
607
+ 'uid' : uid ,
581
608
'dfp' : self ._get_cookie ('dfp' , '' ),
582
609
'mode' : self ._get_cookie ('mod' , 'intl' ),
583
610
'lang' : self ._get_cookie ('lang' , 'en_us' ),
584
611
'bid_list' : '[' + ',' .join (['0' , * self ._BID_TAGS .keys ()]) + ']' ,
612
+ 'ut_list' : '[' + ',' .join (ut_list ) + ']' ,
585
613
'cmd5x_func' : self ._extract_cmd5x_function (webpage , video_id ),
586
614
})[1 ].strip (), video_id )
587
615
@@ -590,9 +618,10 @@ def _real_extract(self, url):
590
618
urljoin ('https://cache-video.iq.com' , dash_paths ['0' ]), video_id ,
591
619
note = 'Downloading initial video format info' , errnote = 'Unable to download initial video format info' )['data' ]
592
620
593
- preview_time = traverse_obj (initial_format_data , ('boss_ts' , 'data' , 'previewTime' ), expected_type = float_or_none )
594
- if preview_time :
595
- self .report_warning (f'This preview video is limited to { preview_time } seconds' )
621
+ preview_time = traverse_obj (
622
+ initial_format_data , ('boss_ts' , (None , 'data' ), ('previewTime' , 'rtime' )), expected_type = float_or_none , get_all = False )
623
+ if traverse_obj (initial_format_data , ('boss_ts' , 'data' , 'prv' ), expected_type = int_or_none ):
624
+ self .report_warning ('This preview video is limited%s' % format_field (preview_time , template = 'to %s seconds' ))
596
625
597
626
# TODO: Extract audio-only formats
598
627
for bid in set (traverse_obj (initial_format_data , ('program' , 'video' , ..., 'bid' ), expected_type = str_or_none , default = [])):
0 commit comments