import { WaitForScript } from "@pioneerjs/core" ; import { Frame , HTTPRequest } from "puppeteer-core" ; import { ScriptSetting } from "../../../types" ; import { Course } from "../../../types/script/course" ; import { StoreGet } from "../../../types/setting" ; import { sleep } from "../../common/utils" ; import { CXRequestScriptHook } from "./utils" ; import { MediaScript } from "./utils/media.script" ; import { PPTScript } from "./utils/ppt.script" ; import { ReadBookScript } from "./utils/read.book.script" ; import { QAScript } from "./utils/qa.script" ; import { LoginScript } from "../../login/types" ; import { RunnableTask } from "../../../electron/task/runnable.task" ; import { ScriptTask } from "../../../electron/task/script.task" ; import { waitForNavigation , waitForClickAndNavigation , TimeoutTask } from "../utils" ; import { debounce } from "lodash" ; import { Logger } from "../../../electron/logger" ; const logger = Logger . of ( "cx-script" ) ; const debouncedScript = debounce ( runScript , 10000 ) ; export function CXCourseEntry ( course ) { return ScriptTask . createScript ( { name : "超星课程入口" , timeout : 60 * 1000 , target : async function ( { task , script } ) { if ( course . url ) await waitForNavigation ( script , course . url ) ; else if ( course . selector ) { await waitForClickAndNavigation ( script , course . selector ) ; } else { throw new Error ( "脚本运行失败: 课程链接或课程元素为空，请重新获取课程!" ) ; } } , } ) ; } param script returns export function CXScript ( ) { return ScriptTask . createScript ( { name : "超星刷课任务" , target : async function ( { task , script } ) { return new Promise ( async ( resolve , reject ) => { if ( ! StoreGet ( "setting" ) . script . script . cx . study . enable ) { task . process ( "刷课功能关闭，即将自动做作业" ) ; await sleep ( 3000 ) ; resolve ( ) ; return ; } const waitFor = new WaitForScript ( script ) ; task . process ( "开始刷课" ) ; CXRequestScriptHook ( script . page ) ; const chapterUrl = script . page . url ( ) . replace ( /pageHeader=\d+/ , "pageHeader=1" ) ; await script . page . goto ( chapterUrl ) ; logger . info ( "进入任务页面成功，即将开始刷课" ) ; task . process ( "进入任务页面成功，即将开始刷课" ) ; await waitFor . nextTick ( "requestfinished" ) ; await waitFor . documentReady ( ) ; await waitForNavigation ( script , script . page . frames ( ) [ 1 ] . url ( ) ) ; await script . page . evaluate ( ( ) => { ( window as any ) . open = function ( url ) { window . location . href = url ; } ; } ) ; await waitForClickAndNavigation ( script , ".chapter_item[onclick*='toOld']" ) ; await waitFor . nextTick ( "requestfinished" ) ; await waitFor . documentReady ( ) ; const jobs = await script . page . evaluate ( ( review ) => { const res = Array . from ( document . querySelectorAll ( '[onclick*="getTeacherAjax"]' ) ) . map ( ( el ) => el . parentElement ) . filter ( ( el ) => review || ! ! el ?. querySelector ( ".jobUnfinishCount" ) ) . map ( ( el ) => el ! . querySelector ( '[onclick*="getTeacherAjax"]' ) || "" ) . filter ( ( el ) => el !== "" ) . map ( ( el ) => el . getAttribute ( "onclick" ) ) ; console . log ( "res" , res ) ; return res ; } , StoreGet ( "setting" ) ?. script ?. script ?. cx ?. study ?. review ) ; logger . info ( jobs ) ; if ( jobs . length === 0 ) { task . process ( "检测不到任务点,可能因为所有任务已经完成，即将跳转下一个任务。" ) ; resolve ( ) ; } else { task . process ( "刷课中..." ) ; let queue = [ ] ; script . context . eventPool . on ( "frameattached" , ( frame ) => { frame . evaluate ( ( ) => ( window . alert = console . log ) ) ; queue . push ( frame ) ; } ) ; script . context . eventPool . on ( "framedetached" , ( frame ) => { queue = queue . filter ( ( q ) => q . _id !== frame . _id ) ; } ) ; const cxSetting = StoreGet ( "setting" ) . script . script . cx . study ; if ( cxSetting . review ) { } else { await script . page . evaluate ( jobs [ 0 ] ) ; } await waitFor . nextTick ( "requestfinished" ) ; await waitFor . documentReady ( ) ; async function callback ( f ) { await next ( queue , task , script , callback ) ; } script . context . eventPool . on ( "requestfinished" , async ( req ) => { if ( RegExp ( "/mycourse/studentstudy\\?chapterId" ) . test ( req . url ( ) ) ) { task . process ( "已切换到学习界面，即将开始自动刷课" ) ; await debouncedScript ( queue , task , script , callback ) ; } else if ( RegExp ( "/mycourse/studentstudyAjax" ) . test ( req . url ( ) ) || RegExp ( "/knowledge/cards" ) . test ( req . url ( ) ) ) { task . process ( "任务变化，重新分配任务中 " ) ; await waitFor . nextTick ( "requestfinished" ) ; await debouncedScript ( queue , task , script , callback ) ; } } ) ; task . process ( "即将开始自动刷课" ) ; await debouncedScript ( queue , task , script , callback ) ; } } ) ; } , } ) ; } async function runScript ( queue , task , script , callback ) { console . log ( "runScript " , queue . map ( ( a ) => a . _id ) ) ; queue = queue . filter ( ( q ) => ! q . isDetached ( ) ) ; const cxSetting = StoreGet ( "setting" ) . script . script . cx ; if ( cxSetting . study . queue ) { await execQueue ( queue , task , script ) ; } else { await Promise . all ( queue . map ( ( frame ) => TimeoutTask ( StoreGet ( "setting" ) . script . script . taskTimeoutPeriod * 60 * 60 * 1000 , ( ) => JobScript ( cxSetting . study , task , script , frame ) , async ( ) => { task . error ( "任务超时，即将进行下一个任务。" ) ; } ) ) ) ; } console . log ( "callback" ) ; await callback ( queue ) ; } async function next ( queue , task , script , callback ) { const onclick = await script . page . evaluate ( ( ) => ( document . querySelector ( ".next" ) as any ) ?. getAttribute ( "onclick" ) ) ; if ( onclick ) { task . process ( "正在跳转下一章" ) ; await script . page . evaluate ( ( ) => ( document . querySelector ( ".next" ) as any ) ?. click ( ) ) ; await debouncedScript ( queue , task , script , callback ) ; } else { task . process ( "刷课完成。" ) ; } } async function execQueue ( queue , task , script ) { const frame = queue . shift ( ) ; console . log ( "execQueue " , frame ?. _id ) ; if ( frame ) { const studySetting = StoreGet ( "setting" ) . script . script . cx . study ; await TimeoutTask ( StoreGet ( "setting" ) . script . script . taskTimeoutPeriod * 60 * 60 * 1000 , ( ) => JobScript ( studySetting , task , script , frame ) , async ( ) => { task . error ( "任务超时，即将进行下一个任务。" ) ; } ) ; await execQueue ( queue , task , script ) ; } } async function JobScript ( studySetting , task , script , frame ) { const waitFor = new WaitForScript ( script ) ; await waitFor . nextTick ( "requestfinished" ) ; console . log ( "JobScript " , frame . _id ) ; if ( studySetting . media . enable ) { await MediaScript ( "video" , task , frame , studySetting . media ) ; await MediaScript ( "audio" , task , frame , studySetting . media ) ; } if ( studySetting . ppt ) { await PPTScript ( task , frame , studySetting . ppt ) ; } if ( studySetting . book ) { await ReadBookScript ( task , frame , studySetting . book ) ; } if ( studySetting . qa . enable ) { await QAScript ( task , frame , studySetting . qa ) ; } }