Skip to content

Commit

Permalink
feat(app): 新增资源加载器,优化各种资源加载问题,移除原有的OCR模块打包方式。
Browse files Browse the repository at this point in the history
  • Loading branch information
enncy committed Mar 29, 2023
1 parent 6aececb commit 1b83d8a
Show file tree
Hide file tree
Showing 20 changed files with 506 additions and 306 deletions.
2 changes: 0 additions & 2 deletions packages/app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { task } from './src/utils';
import { handleError } from './src/tasks/error.handler';
import { updater } from './src/tasks/updater';
import { startupServer } from './src/tasks/startup.server';
import { ocrUnzip } from './src/tasks/ocr.unzip';

app.setName('ocs');

Expand Down Expand Up @@ -42,7 +41,6 @@ function bootstrap() {
task('启动接口服务', () => startupServer());
}),
task('初始化自动启动', () => autoLaunch()),
task('OCR模块解压', () => ocrUnzip()),
task('启动渲染进程', async () => {
await app.whenReady();
const window = createWindow();
Expand Down
11 changes: 8 additions & 3 deletions packages/app/src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ export const appStore = {
'exe-path': app.getPath('exe'),
'logs-path': app.getPath('logs'),
'config-path': path.resolve(app.getPath('userData'), './config.json'),
/** 加载拓展路径 */
extensionsFolder: path.resolve(app.getPath('userData'), './extensions'),
/** 浏览器用户数据文件夹 */
userDataDirsFolder: path.resolve(app.getPath('userData'), './userDataDirs'),
/** 浏览器下载文件夹 */
downloadFolder: path.resolve(app.getPath('userData'), './downloads')
downloadFolder: path.resolve(app.getPath('userData'), './downloads'),
/** 加载拓展路径 */
extensionsFolder: path.resolve(app.getPath('userData'), './downloads/extensions')
},
/** 窗口设置 */
window: {
Expand All @@ -35,4 +35,9 @@ export const appStore = {
render: {} as { [x: string]: any }
};

/**
* - electron 本地存储对象
* - 可以使用 store.store 访问
* - 设置数据请使用 store.set('key', value)
*/
export const store = new Store<typeof appStore>();
6 changes: 3 additions & 3 deletions packages/app/src/tasks/init.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const logger = Logger('store-init');
/**
* 初始化配置
*/
export async function initStore() {
export function initStore() {
const version = store.store.version;
logger.log('version', version);

Expand All @@ -35,8 +35,8 @@ export async function initStore() {
logger.log('store', store.store);
}

// 强制更新 exe-path
store.store.paths['exe-path'] = app.getPath('exe');
// 强制更新路径
store.set('paths', appStore.paths);

if (!existsSync(store.store.paths.userDataDirsFolder)) {
mkdirSync(store.store.paths.userDataDirsFolder, { recursive: true });
Expand Down
25 changes: 0 additions & 25 deletions packages/app/src/tasks/ocr.unzip.ts

This file was deleted.

7 changes: 3 additions & 4 deletions packages/app/src/tasks/remote.register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ import fs from 'fs';
import path from 'path';
import os from 'os';
import crypto from 'crypto';
import ElectronStore from 'electron-store';
import { OCSApi, getValidBrowsers } from '@ocsjs/common';
import si from 'systeminformation';

import { store } from '../store';

/**
* 注册主进程远程通信事件
Expand Down Expand Up @@ -70,7 +69,7 @@ function registerRemoteEvent(name: string, target: any) {
}
});
} catch (err) {
logger.error(err)
logger.error(err);
}
}

Expand Down Expand Up @@ -98,7 +97,7 @@ const methods = {
*/
export function remoteRegister(_win: BrowserWindow) {
win = _win;
registerRemoteEvent('electron-store', new ElectronStore());
registerRemoteEvent('electron-store', store);
registerRemoteEvent('fs', fs);
registerRemoteEvent('os', os);
registerRemoteEvent('path', path);
Expand Down
7 changes: 6 additions & 1 deletion packages/app/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { app } from 'electron';
import path from 'path';
import AdmZip from 'adm-zip';
import axios from 'axios';
import { createWriteStream } from 'fs';
import { createWriteStream, existsSync, mkdirSync } from 'fs';
import { finished } from 'stream/promises';
import { Logger } from '../logger';

Expand Down Expand Up @@ -34,6 +34,11 @@ export async function downloadFile(fileURL: string, outputURL: string, rateHandl
rateHandler(parseFloat(rate), totalLength, chunkLength);
});

// 创建文件夹
if (existsSync(path.dirname(outputURL)) === false) {
mkdirSync(path.dirname(outputURL), { recursive: true });
}

const writer = createWriteStream(outputURL);
data.pipe(writer);
await finished(writer);
Expand Down
14 changes: 8 additions & 6 deletions packages/app/src/utils/ocr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { writeFile, mkdirSync, existsSync, rmSync, writeFileSync } from 'fs';
import path from 'path';
import { randomUUID } from 'crypto';
import child_process from 'child_process';
import { ocr_path } from '../tasks/ocr.unzip';
import { Logger } from '../logger';
import { store } from '../store';

const ocr_folder = path.join(store.store.paths.downloadFolder, './apps/ocr');

const logger = Logger('ocr');

Expand All @@ -14,14 +16,14 @@ const logger = Logger('ocr');
export function ocr(base64: string) {
return new Promise<string>((resolve, reject) => {
const uuid = randomUUID();
const img_cache = path.join(ocr_path, './img_cache');
const img_cache = path.join(ocr_folder, './img_cache');
if (!existsSync(img_cache)) {
mkdirSync(img_cache, { recursive: true });
}
const img = path.join(img_cache, uuid + '.png');
writeFile(img, base64, 'base64', () => {
// 要使用 "" 去包裹路径,防止出现空格
const cmd = [`"${path.join(ocr_path, './ocr.exe')}"`, '--ocr', `"${img}"`].join(' ');
const cmd = [`"${path.join(ocr_folder, './ocr.exe')}"`, '--ocr', `"${img}"`].join(' ');
logger.log('cmd', cmd);

child_process.exec(cmd, (err, stdout, stderr) => {
Expand Down Expand Up @@ -53,7 +55,7 @@ export function det(det_target_base64: string, det_bg_base64: string) {
target_y: number;
target: [number, number, number, number];
}>((resolve, reject) => {
const img_cache = path.join(ocr_path, './img_cache');
const img_cache = path.join(ocr_folder, './img_cache');
if (!existsSync(img_cache)) {
mkdirSync(img_cache, { recursive: true });
}
Expand All @@ -62,7 +64,7 @@ export function det(det_target_base64: string, det_bg_base64: string) {
writeFileSync(img1, det_target_base64, 'base64');
writeFileSync(img2, det_bg_base64, 'base64');

const cmd = [`"${path.join(ocr_path, './ocr.exe')}"`, '--det-target', `"${img1}"`, '--det-bg', `"${img2}"`].join(
const cmd = [`"${path.join(ocr_folder, './ocr.exe')}"`, '--det-target', `"${img1}"`, '--det-bg', `"${img2}"`].join(
' '
);

Expand All @@ -85,5 +87,5 @@ export function det(det_target_base64: string, det_bg_base64: string) {

/** 判断是否能够进行验证码识别 */
export function canOCR() {
return existsSync(path.join(ocr_path, './ocr.exe'));
return existsSync(path.join(ocr_folder, './ocr.exe'));
}
101 changes: 75 additions & 26 deletions packages/web/src/components/Setup.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
<template>
<a-row :gutter="[24, 24]">
<template v-if="state.finish">
<a-result
status="success"
title="初始化完成"
>
<template #subtitle> 软件初始化已完成,您可以点击右上方的新建浏览器,进行浏览器多开(分身)体验。 </template>
<template #extra>
<a-button
type="primary"
@click="confirm"
>
确定
</a-button>
</template>
</a-result>
</template>

<a-row
v-else
:gutter="[24, 24]"
>
<a-col
class="text-secondary"
style="font-size: 12px"
Expand Down Expand Up @@ -63,7 +83,7 @@
<span> 脚本管理器 </span>
</a-col>
<a-col flex="auto">
<a-select v-model="state.extension">
<a-select v-model="state.selectedExtension">
<a-option
v-for="extension of state.resource.extensions"
:key="extension.name"
Expand All @@ -82,7 +102,13 @@
<span> 网课脚本 </span>
</a-col>
<a-col flex="auto">
<a-select default-value="OCS 网课助手"> </a-select>
<a-select v-model="state.selectedUserScript">
<a-option
v-for="userScript of state.resource.userScripts"
:key="userScript.name"
:label="userScript.name"
></a-option>
</a-select>
</a-col>
</a-row>
</a-col>
Expand Down Expand Up @@ -117,46 +143,61 @@ import { remote } from '../utils/remote';
import { onMounted, reactive } from 'vue';
import Icon from './Icon.vue';
import { Message } from '@arco-design/web-vue';
import { installExtension } from '../utils/extension';
import { installExtensions } from '../utils/extension';
import { addScriptFromUrl } from '../utils/user-scripts';
import { ExtensionResource } from '@ocsjs/common';
import { ValidBrowser } from '@ocsjs/common/lib/src/interface';
import { ResourceLoader } from '../utils/resources.loader';
import { ResourceFile } from '../utils/apis';
type Extensions = ExtensionResource & { installed?: boolean };
type Extension = ResourceFile & { installed?: boolean };
const state = reactive({
resource: {
browsers: [] as ValidBrowser[],
extensions: [] as Extensions[],
ocsjs: ''
extensions: [] as Extension[],
userScripts: [] as ResourceFile[]
},
browser: '',
downloadPath: '',
extension: '',
// 选中的拓展
selectedExtension: '',
// 选中的脚本
selectedUserScript: '',
loading: false,
error: false,
downloading: ''
downloading: '',
// 初始化完成
finish: false
});
/** 资源加载器 */
const resourceLoader = new ResourceLoader({
resourceRootPath: store.paths.downloadFolder
});
onMounted(async () => {
state.loading = true;
try {
const infos = await getRemoteInfos();
state.downloadPath = await remote.path.call('join', store.paths.downloadFolder);
// 检测有效的浏览器路径
state.resource.browsers = await remote.methods.call('getValidBrowsers');
if (state.resource.browsers.length) {
state.browser = state.resource.browsers[0].name;
}
state.resource.extensions = infos.extensions;
state.resource.ocsjs = infos.resource.userjs;
state.downloadPath = await remote.path.call('join', store.paths.downloadFolder);
// 获取最新的拓展和用户脚本信息
state.resource.extensions = infos.resourceGroups.find((group) => group.name === 'extensions')?.files || [];
state.resource.userScripts = infos.resourceGroups.find((group) => group.name === 'userjs')?.files || [];
for (const extension of state.resource.extensions) {
extension.installed = await remote.fs.call('existsSync', `${store.paths.extensionsFolder}/${extension.name}`);
extension.installed = await resourceLoader.isZipFileExists('extensions', extension);
}
state.extension = state.resource.extensions[0].name;
// 初始选中的信息
state.selectedExtension = state.resource.extensions[0].name;
state.selectedUserScript = state.resource.userScripts[0].name;
} catch (err) {
state.error = true;
console.error(err);
Expand All @@ -166,15 +207,14 @@ onMounted(async () => {
}
});
async function downloadExtension(extension: ExtensionResource) {
async function downloadExtension(extension: Extension) {
state.downloading = `正在下载脚本管理器 : ${extension.name} ...`;
await installExtension(state.resource.extensions, extension);
await installExtensions(state.resource.extensions, extension);
}
async function downloadScript() {
const name = 'OCS 网课助手';
state.downloading = `正在下载脚本 : ${name} ...`;
await addScriptFromUrl(state.resource.ocsjs);
async function downloadScript(userScript: ResourceFile) {
state.downloading = `正在下载脚本 : ${userScript.name} ...`;
await addScriptFromUrl(userScript.url);
}
function notNow() {
Expand All @@ -183,22 +223,31 @@ function notNow() {
async function setup() {
const browser = state.resource.browsers.find((e) => e.name === state.browser);
const extension = state.resource.extensions.find((e) => e.name === state.extension);
const extension = state.resource.extensions.find((e) => e.name === state.selectedExtension);
const userScript = state.resource.userScripts.find((e) => e.name === state.selectedUserScript);
if (browser && extension) {
if (browser && extension && userScript) {
try {
store.render.setting.launchOptions.executablePath = browser.path;
await downloadScript();
await downloadScript(userScript);
await downloadExtension(extension);
state.finish = true;
} catch (err) {
Message.error('安装失败,请稍后重试,或者手动设置 : ' + err);
}
} else {
Message.error('参数错误');
}
state.downloading = '';
store.render.state.setup = false;
setTimeout(() => {
confirm();
}, 10 * 1000);
}
function confirm() {
state.downloading = '';
}
</script>

Expand Down
Loading

0 comments on commit 1b83d8a

Please sign in to comment.