1. 程式人生 > 其它 >記載一次實現超星視訊倍速播放的艱苦奮鬥歷程

記載一次實現超星視訊倍速播放的艱苦奮鬥歷程

警告:該隨筆內容僅用於幫助超星學習通內部人員完善其程式碼,不得被超星學習通內部人員以外的任何個人和機構使用,不得用於非法用途,不得轉載,否則後果自負,我一定會用我折騰js的精力向你索賠到底!!!

最近在超星視訊觀看網課,突然發現教師設定了不能倍速播放視訊。這樣會讓我感到很痛苦,沒有倍速的網課是沒有靈魂的!!!此外視訊還有失焦後,就會自動暫停播放的操作,導致我一進入控制檯就給我暫停視訊,這增加了我的不適感。於是,平素就熱愛折騰js的我,投入了大把時間研究這個問題,並最終幸運的實現了目標。感謝強大的TamperMonkey外掛,感謝cnblogs、StackOverflow、SegmentFault、CSDN,以及其他各網站上曾幫助過我的的一切技術大佬們(排名不分先後)。

以下的所有步驟是憑藉我的記憶來的,大體上靠譜,可能會缺少很多內容,順序上也不準確,但無傷大雅。

  • 超星的視訊很變態,在video外面套了兩層iframe,會增加對定位元素的阻力。好在基於強大的TamperMonkey外掛,可以直接把指令碼匹配網站設為巢狀視訊的那層iframe的src連結。問題解決。
  • 想過偷懶,找一個現成的油猴指令碼。很遺憾暫時沒有找到一個能夠在現有的超星平臺上,喚回倍速播放功能的指令碼。估計是超星更新太頻繁了。於是決定自己寫一個指令碼湊活著用。
  • 首先需要取消蛋疼的視訊自動暫停功能。基於我當時的技術水平,我是這麼做的
v.addEventListener("pause",e=>{
    e.target.play()
})
//雖然這麼是不會自動暫停了,可也造成了視訊無法暫停,難受啊。先不管了,因為這個只是小菜,重頭戲是倍速播放。
  • 繼續研究,發現超星給視訊添加了很多事件的監聽器,其中就有個匿名函式繫結在ratechange事件上。藉助它,超星可以攔截所有修改倍速的操作,直接使用document.querySelector("video").playbackRate = 2;是無效的,他會馬上給你改回來(題外話,發現如果把倍速設定為1以下,就不會被攔截,這是什麼惡趣味?)。常規的話,想要移除這種綁定了匿名回撥函式的監聽器,只能移除有名字的函式的監聽器,移除匿名函式的監聽器是不可能的。此外,超星還對其部分js原始碼進行了加密,比如video.js,放眼望去幾萬行程式碼,各種混淆後的識別符號名字,我擷取一行你們體會下function a0_0x3ffc(_0xf3628b,_0x19b3a9){var _0x53fe0f=a0_0x53fe();return a0_0x3ffc=function(_0x3ffc55,_0x4f6c6f){_0x3ffc55=_0x3ffc55-0xfd;var _0x1795ee=

  • 首先,利用新版的Chrome瀏覽器,可以移除事件監聽器!怎麼樣是不是很意外?我也很意外,但就是這樣,不得不說Chrome太強大了,也是最近一兩年才推出的這個操作(題外話:新版的Chrome瀏覽器也終於漢化了控制檯,算是解決了一大歷史遺留問題,是我們的福音啊)。我現在雖然還是以使用Firefox瀏覽器為主,但能明顯地感受到,Chrome比Firefox的手感實在是絲滑太多了,比如搜尋原始碼,我的Firefox比Chrome總是更容易卡死,而且搜尋出的結果也有經常是後者多。強大的Chrome甚至比Firefox還多一個getEventlisteners的函式。感覺Firefox在走下坡路啊,悲傷ing,Firefox你要振作起來啊

  • 雖然利用新版的Chrome瀏覽器,可以移除事件監聽器,但這有個問題,就算操作太麻煩,每次都要手動開啟控制檯,找到iframe裡面的video,然後找到ratechenge事件,然後手動移除之。這個操作是不能用js完成的,沒有自動化就沒有靈魂啊!不能滿足我的需求,我要繼續折騰,而且我要找到一種能夠在Firefox上使用的方法。轉變思路:不再嘗試移除匿名的Eventlistener

  • 在StackOverflow看到過一個移除dom上所有Eventlisteners的方式:dom.outerHTML=dom.outerHTML;這種方法雖然有效,但會造成所有Eventlisteners的移除,比如視訊載入事件,移除了就無法載入視訊,更不用說播放了!轉變思路:不再嘗試移除Eventlisteners

  • 想過解密混淆後的js原始碼。很可惜,這個工作量實在是太大了,而且以我的能力估計也會卡住。後來很幸運的在思否上找到一個大佬的文章,Javascript混淆與解混淆的那些事兒 - SegmentFault 思否 ,驚喜的發現,超星的加密方式,似乎就是該文章中提到的"javascript-obfuscator混淆後生成的程式碼"的方式(題外話:感覺思否的社群質量一直都很高啊!不知道是怎麼做到的,可能因為太小眾了吧)。然後順藤摸瓜,在本文中找到其對應的解密工具crack.js。過程中也嘗試過其他的各種解密方式,比如jsnice,,然而最後都失敗了,要麼原始碼太長,要麼網站連線失敗,要麼就是我現在看不懂的操作。其實我也不是很想解密,因為這個過程註定了對超星api的依賴,萬一它每隔10分鐘就換一套程式碼,又要重新開始折騰,時間成本太大了。以前解密過某其他的網站的js,使用的是該文章中提到的第一種加密法——by eval(),不得不說這種加密方式屬實ez,最後我甚至能還原出其原本的函式名。而超星就直接把所有函式名進行了不可逆的改名,我覺得她根本就沒想過給我提供一個把名字還原的操作api!轉變思路:不再嘗試揭祕原始碼

  • 經過長久的網路衝浪,最後在StackOverflow發現某提問者給了我一個思路,那就是直接重置addEventListener這個東東(我之前使用eval方式解密某網站的那次操作,跟這個很像,也是重置了網頁原本的eval函式)。說實話,現在我還不是很懂addEventListener這個函式,為什麼window.addEventListener==Element.prototype.addEventListener是真,而document.ddEventListener==Element.prototype.addEventListener有時候真,有時候假。難道是每個dom的addEventListener都不一樣嗎?存疑。

const oldAddEventListener = Element.prototype.addEventListener;
const EventListener = function(type,listener) {
    //do something
    oldAddEventListener.call(this, type, listener);
};
Element.prototype.addEventListener = EventListener;
/*
    * 通過這種操作,可以人為的控制網頁的原始addEventListener!
    * 這樣我就可以按我的意願,去過濾我想要新增的EventListener了
    * 我就可以控制不讓ratechange事件,pause事件等有關的函式繫結在video上,從而達到人為過濾
    * 當然這麼做的前提是,必須搶在超星使用原始的addEventListener之前,就改寫它!
    * 如果只憑我的手速,這是不可能的吧。
    * 很可惜,基於強大的TamperMonkey外掛,通過把指令碼設定為run-at document-start的方法,就可以做到!
    * (再一次感謝TamperMonkey給我的幫助)
    */
  • 現在釋放一下我的效果圖並作出解說:
    • 我在左上角添加了一組按鈕,通過點選就可以設定為我想要的播放速度。不過能夠這些按鈕成功,其靈魂還是在於上面的一堆操作
    • 再一次衷心感謝自己能夠幸運的被身邊這麼多大佬和強大的技術所啟發和支援!

    • 不要試圖問我要程式碼,我也不會迴應你的需求。這些成功只屬於那些願意為他付出時間,去折騰的人們。

再次警告:該隨筆內容僅用於幫助超星學習通內部人員完善其程式碼,不得被超星學習通內部人員以外的任何個人和機構使用,不得用於非法用途,不得轉載,否則後果自負,我一定會用我折騰js的精力向你索賠到底!!!