Skip to content

Commit

Permalink
feat(script): change folder name, and add browser script
Browse files Browse the repository at this point in the history
  • Loading branch information
enncy committed Feb 16, 2022
1 parent 494e523 commit c540500
Show file tree
Hide file tree
Showing 37 changed files with 387 additions and 31 deletions.
6 changes: 6 additions & 0 deletions packages/scripts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# ocsjs - scripts
> ocsjs 脚本模块
## 文件目录
- `src/browser` : 浏览器js模块,使用 javascript 运行脚本,实现网课视频学习等功能。
- `scr/nodejs` : nodejs模块,使用 playwright 进行浏览器启动关闭运行等操作,配合 browser 模块的脚本进行使用。
8 changes: 8 additions & 0 deletions packages/scripts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
"description": "scripts package of ocs",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"files": [
"lib",
"dist"
],
"scripts": {
"test": "playwright test --config=playwright.config.ts",
"build": "tsc && npm run pack",
Expand All @@ -17,5 +21,9 @@
"commander": "^9.0.0",
"dotenv": "^16.0.0",
"playwright": "^1.18.1"
},
"devDependencies": {
"webpack": "^5.69.0",
"webpack-cli": "^4.9.2"
}
}
1 change: 1 addition & 0 deletions packages/scripts/src/browser/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * as ZHS from "./zhs";
20 changes: 20 additions & 0 deletions packages/scripts/src/browser/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export async function sleep(period: number) {
return new Promise((resolve) => {
setTimeout(resolve, period);
});
}

export async function logger(level: "info" | "error" | "warn" | "debug", ...msg: any[]) {
console.log(...loggerPrefix(level), ...msg);
}

function loggerPrefix(level: "info" | "error" | "warn" | "debug") {
let bgColor;
bgColor =
level === "info" ? "#2196f3a3" : level === "debug" ? "#9e9e9ec4" : level === "warn" ? "#ffc107db" : "#f36c71cc";
let extra = level === "error" ? "[错误]" : level === "warn" ? "[警告]" : undefined;
return [
`%c[OCS][${new Date().toLocaleTimeString()}]${extra || ""}`,
`background:${bgColor};color:white;padding:2px;border-radius:2px`,
];
}
1 change: 1 addition & 0 deletions packages/scripts/src/browser/zhs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./study"
153 changes: 153 additions & 0 deletions packages/scripts/src/browser/zhs/study.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import { logger, sleep } from "../util";

export type StudyOptions = VideoOptions & {
/**
* 设置观看总时长(分钟)
*
* 如果设置为0,将一直观看,不暂停
*
* @default 30
*/
watchTime?: number;

/**
* 复习模式:重复观看每个视频
*
* @default false
*/
restudy: boolean;
};

export interface VideoOptions {
/**
* 是否禁音
*
* @default true
*/
mute?: boolean;
/**
* 视频速度
*
* @default 1
*/
playbackRate?: number;
}

/**
* zhs 视频学习
* @param options {@link StudyOptions}
* @returns
*/
export async function study(options?: StudyOptions) {
const { watchTime = 30, restudy = false } = options || {};
logger("info", "zhs 学习任务开始");

await new Promise<void>(async (resolve, reject) => {
/** 查找任务 */
let list: HTMLLIElement[] = Array.from(document.querySelectorAll("li.clearfix.video"));

/** 如果不是复习模式,则排除掉已经完成的任务 */
if (!restudy) {
list = list.filter((el) => el.querySelector(".time_icofinish") === null);
}

if (list.length === 0) {
logger("warn", "视频任务数量为 0 !");
} else {
logger("info", "视频任务数量", list.length);

let stop = false;

/**
* 实时监测,关闭弹窗测验
*/
setInterval(() => {
closeTestDialog();
}, 3000);

/**
* 到达学习时间后,自动关闭
*/
if (watchTime !== 0) {
logger("info", "将在", watchTime, "分钟后自动暂停");
setTimeout(() => {
const video: HTMLVideoElement = document.querySelector("video") as any;
(video as any).stop = true;
video.pause();
stop = true;
resolve();
}, watchTime * 60 * 1000);
}

/** 遍历任务进行学习 */
for (const item of list) {
try {
if (stop) {
break;
} else {
logger(
"debug",
`即将播放 -- ${item.querySelector('[class="catalogue_title"]')?.getAttribute("title")} : ${
item.querySelector(".time")?.textContent
}`
);
item.click();
await sleep(5000);
await watch(options);
}
} catch (e) {
logger("error", e);
}
}
}

resolve();
});
logger("info", "zhs 学习任务结束");
}

/**
* 观看视频
* @param options {@link VideoOptions}
* @returns
*/
export async function watch(options?: VideoOptions) {
const { playbackRate = 1, mute = true } = options || {};
return new Promise<void>((resolve, reject) => {
try {
const video = document.querySelector("video") as HTMLVideoElement;
video.playbackRate = playbackRate;
video.muted = mute;
video.onpause = function () {
if (!video.ended) {
if ((video as any).stop) {
resolve();
} else {
video.play();
}
}
};
video.onended = function () {
resolve();
};

video.play();
} catch (e) {
reject(e);
}
});
}

/**
* 关闭zhs测验弹窗
*/
export async function closeTestDialog() {
if (document.querySelectorAll(".topic-item").length != 0) {
//选择A
(document.querySelector(".topic-item") as HTMLElement).click();
await sleep(500);
//关闭
(document.querySelector(`[aria-label="弹题测验"] .btn`) as HTMLElement).click();
await sleep(500);
}
}
3 changes: 1 addition & 2 deletions packages/scripts/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export * from "./puppeteer"

export * from "./nodejs";
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@

export * from "./login";
export { waitForLogin } from "./utils";


export const setting = {
login:{
timeout: 30 * 1000
login: {
timeout: 30 * 1000,
},
};
4 changes: 4 additions & 0 deletions packages/scripts/src/nodejs/cx/login/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { phoneCodeLogin } from "./phone.code";
export { phoneLogin } from "./phone";
export { schoolLogin } from "./school";
export { otherLogin } from "./other";
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Page } from "playwright";
import { setting } from "../";
import { setting } from "..";

export interface CXPhoneLoginOptions {
phone: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Page } from "playwright";
import { setting } from "../";
import { setting } from "..";

import { breakCode } from "../../common/break.code";
import { ocr } from "../../common/ocr";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@

import { CXPhoneLoginOptions } from "./phone";
import { CXSchoolLoginOptions } from "./school";
import { CXOtherLoginOptions } from "./other";
import { CXPhoneCodeLoginOptions } from "./phone.code";

export { phoneCodeLogin } from "./phone.code";
export { phoneLogin } from "./phone";
export { schoolLogin } from "./school";
export { otherLogin } from "./other";

export interface CXLoginOptions {
phone: CXPhoneLoginOptions;
school: CXSchoolLoginOptions;
other: CXOtherLoginOptions;
phoneCode: CXPhoneCodeLoginOptions;
}
1 change: 1 addition & 0 deletions packages/scripts/src/nodejs/cx/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./login/types";
44 changes: 44 additions & 0 deletions packages/scripts/src/nodejs/cx/utils/goto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Page } from "playwright";
import { URLSearchParams } from "url";

/**
* 进入学习页面
* @param page
* @param url 课程首页
*/
export async function gotoStudyPage(page: Page, url: string) {
const params = new URLSearchParams(url);
params.set("pageHeader", "1");
await page.goto(params.toString());
const frame = page.frame("frame_content-zj");

if (frame) {
await Promise.all([page.waitForNavigation(), frame.click("[onclick*='toOld']")]);
}

return page;
}

/**
* 进入作业页面
* @param page
* @param url 课程首页
*/
export async function gotoHomeworkPage(page: Page, url: string) {
const params = new URLSearchParams(url);
params.set("pageHeader", "8");
await page.goto(params.toString());
return page;
}

/**
* 进入考试页面
* @param page
* @param url 课程首页
*/
export async function gotoExamPage(page: Page, url: string) {
const params = new URLSearchParams(url);
params.set("pageHeader", "9");
await page.goto(params.toString());
return page;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Page } from "playwright";
import { setting } from "../";
import { setting } from "..";

export async function waitForLogin(page: Page) {
await Promise.race([page.waitForURL(/space\/index/), page.waitForTimeout(setting.login.timeout)]);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@

export * as CX from "./cx";
export * as ZHS from "./zhs";
export * from "./types";
export * from "./script";

33 changes: 33 additions & 0 deletions packages/scripts/src/nodejs/script.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { chromium, LaunchOptions, Page } from "playwright";
import { CX, ZHS } from ".";
import { ScriptFunction, ScriptOptions } from "./types";

const scripts: Record<keyof ScriptOptions, ScriptFunction> = {
"cx-login-other": CX.otherLogin,
"cx-login-phone": CX.phoneLogin,
"cx-login-phone-code": CX.phoneCodeLogin,
"cx-login-school": CX.schoolLogin,
"zhs-login-other": ZHS.otherLogin,
"zhs-login-phone": ZHS.phoneLogin,
"zhs-login-school": ZHS.schoolLogin,
};

export async function launchScripts(launchOptions: LaunchOptions, ...scripts: { (page: Page): Promise<Page> }[]) {
const browser = await chromium.launch(launchOptions);
let page = await browser.newPage();

for (const func of scripts) {
page = await func(page);
}

return {
browser,
page,
};
}

export function script<T extends keyof ScriptOptions>(name: T, opts: ScriptOptions[T]) {
return function (page: Page) {
return scripts[name](page, opts);
};
}
16 changes: 16 additions & 0 deletions packages/scripts/src/nodejs/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { LaunchOptions, Page } from "playwright";

import { CXLoginOptions } from "./cx/types";
import { ZHSLoginOptions } from "./zhs/types";

export interface ScriptOptions {
"cx-login-other": CXLoginOptions["other"];
"cx-login-phone": CXLoginOptions["phone"];
"cx-login-phone-code": CXLoginOptions["phoneCode"];
"cx-login-school": CXLoginOptions["school"];
"zhs-login-other": ZHSLoginOptions["other"];
"zhs-login-phone": ZHSLoginOptions["phone"];
"zhs-login-school": ZHSLoginOptions["school"];
}

export type ScriptFunction<Opts = any> = (page: Page, opts: Opts) => Promise<Page>;
File renamed without changes.
5 changes: 5 additions & 0 deletions packages/scripts/src/nodejs/zhs/login/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

export { phoneLogin } from "./phone";
export { schoolLogin } from "./school";
export { otherLogin } from "./other";

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Page } from "playwright";
import { setting } from "../";
import { setting } from "..";

export interface ZHSPhoneLoginOptions {
phone: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Page } from "playwright";
import { setting } from "../";
import { setting } from "..";

export interface ZHSSchoolLoginOptions {
/** 学校名 */
Expand Down

0 comments on commit c540500

Please sign in to comment.