分析网络流量,发现是通过隔一段时间向服务器汇报一下进度来实现进度跟踪的。所以我们想要快速刷完课程,就要把这个数据包拦下来,修改其中的进度信息,再给服务器就好啦,服务器就会认为我们已经看完视频了。

 1     var sendLog_ = function (player, isdrag, currentTimeSec, callback) {
 2       if (!params.reportUrl) {
 3         return
 4       }
 5       var format = '[{0}][{1}][{2}][{3}][{4}][{5}][{6}][{7}]',
 6       clipTime = (params.startTime || '0') + '_' + (params.endTime || params.duration);
 7       var enc = Ext.String.format(format, params.clazzId, params.userid, params.jobid, params.objectId, currentTimeSec * 1000, '**********', params.duration * 1000, clipTime);
 8       var rurl = [
 9         params.reportUrl,
10         '/',
11         params.dtoken,
12         '?clazzId=',
13         params.clazzId,
14         '&playingTime=',
15         currentTimeSec,
16         '&duration=',
17         params.duration,
18         '&clipTime=',
19         clipTime,
20         '&objectId=',
21         params.objectId,
22         '&otherInfo=',
23         params.otherInfo,
24         '&jobid=',
25         params.jobid,
26         '&userid=',
27         params.userid,
28         '&isdrag=',
29         isdrag,
30         '&view=pc',
31         '&enc=',
32         md5(enc),
33         '&rt=',
34         params.rt,
35         '&dtype=Video',
36         '&_t=',
37         new Date().getTime()
38       ].join('');
39       logFunc(player, rurl, callback)
40     };

以上是汇报进度的js代码,可以看到是通过组装参数形成url,用get方式给服务器发消息。需要注意的是其中有一个字段是enc,是通过把一些参数按照指定格式形成一个字符串,然后md5得到的,要修改参数的话一定要把这个md5也给改了。代码中的******是服务器随机生成的一个salt。

我用firefox写了个插件,作用就是拦住进度报告数据包并修改然后发给服务器。其中background js里的关键代码如下:

 1 function getenc(para){
 2     a = []
 3     b = [para.clazzId,para.userid,para.jobid,para.objectId,para.playingTime*1000,'*******',para.duration*1000,para.clipTime];
 4     for(var i=0;i<8;i++)
 5         a [i] = '['+b[i]+']';
 6     }
 7     a = a.join('');
 8     console.log(a);
 9     console.log(md5(a));
10     return md5(a);
11 }
12 console.log('i am bg, i am do nothing');
13 pattern = "https://*.chaoxing.com/*"
14 function redirect(detail){
15     url = detail.url;
16     parameters = url.split('?');
17     if(parameters.length!=2)
18         return;
19     parameters = parameters[1];
20     parameters = parameters.split('&');
21     parameter = {};
22     for(let item of  parameters){
23         item = item.split('=');
24         parameter[item[0]] = item[1];
25     }
26     clipTime = parameter['clipTime']
27     if(!clipTime)
28         return;
29     clipTime = clipTime.split('_')
30     if(clipTime.length!=2)
31         return;
32     start = Number(clipTime[0])
33     end = Number(clipTime[1])
34     if(start!=end){
35         oldenc = getenc(parameter);
36         parameter.clipTime = clipTime[1]+'_'+clipTime[1];
37         newenc = getenc(parameter);
38         url = url.replace('clipTime='+clipTime[0],'clipTime='+clipTime[1]);
39         url = url.replace('enc='+oldenc,'enc='+newenc);
40         console.log(parameter);
41         //getenc(parameter);
42         return {redirectUrl:url};
43     }
44 
45 }
46 browser.webRequest.onBeforeRequest.addListener(
47   redirect,
48   {urls:[pattern]},
49   ["blocking"]
50 );

clip_time字段就是保存目前播放进度的字段。

写成插件以后就很方便了,直接点一下播放这个视频就自动被服务器视为已经看完了,左上角也会出现“任务点已完成”字样