diff --git a/.cspell/custom-words.txt b/.cspell/custom-words.txt index f53e0ba5..b242b722 100644 --- a/.cspell/custom-words.txt +++ b/.cspell/custom-words.txt @@ -36,3 +36,4 @@ acodec KHTML svgz stylelint +consola diff --git a/.env b/.env index 54688b7d..65ea5f5f 100644 --- a/.env +++ b/.env @@ -2,5 +2,3 @@ APP_NAME=mediago APP_ID=mediago.ziying.site APP_COPYRIGHT=caorushizi APP_VERSION=2.2.0-beta.3 - -APP_SERVER_PORT=8433 diff --git a/packages/main/package.json b/packages/main/package.json index 29ab35cc..d6784ce8 100644 --- a/packages/main/package.json +++ b/packages/main/package.json @@ -30,6 +30,7 @@ "@typescript-eslint/eslint-plugin": "6.21.0", "@typescript-eslint/parser": "6.21.0", "chokidar": "^3.5.3", + "consola": "^3.2.3", "cross-env": "^7.0.3", "dotenv": "^16.3.2", "electron": "^28.2.6", diff --git a/packages/main/scripts/dev.ts b/packages/main/scripts/dev.ts index 1db07321..8e112289 100644 --- a/packages/main/scripts/dev.ts +++ b/packages/main/scripts/dev.ts @@ -2,8 +2,9 @@ import { ChildProcessWithoutNullStreams, spawn } from "child_process"; import electron from "electron"; import * as esbuild from "esbuild"; import chokidar from "chokidar"; -import { loadDotEnvRuntime, mainResolve, log, copyResource } from "./utils"; +import { loadDotEnvRuntime, mainResolve, copyResource } from "./utils"; import { external } from "./config"; +import consola from "consola"; let electronProcess: ChildProcessWithoutNullStreams | null = null; @@ -46,11 +47,11 @@ function startElectron() { electronProcess = spawn(String(electron), args); electronProcess.stdout.on("data", (data) => { - log(String(data)); + consola.log(String(data)); }); electronProcess.stderr.on("data", (data) => { - log(String(data)); + consola.log(String(data)); }); } @@ -82,7 +83,7 @@ async function start() { watcher.on("change", async () => { await mainContext.rebuild(); await preloadContext.rebuild(); - log("watch build succeed."); + consola.log("watch build succeed."); restartElectron(); }); diff --git a/packages/main/scripts/utils.ts b/packages/main/scripts/utils.ts index 339d1929..70dc6722 100644 --- a/packages/main/scripts/utils.ts +++ b/packages/main/scripts/utils.ts @@ -1,37 +1,29 @@ import { existsSync, cpSync, rmSync } from "fs"; import dotenv from "dotenv"; import { resolve } from "path"; +import consola from "consola"; -// FIXME: 有没有什么办法可以不用这么写? -const con = console; -export const log = con.log; - -export const mainResolve = (...r: any[]) => resolve(__dirname, "..", ...r); -export const rootResolve = (...r: any[]) => +export const mainResolve = (...r: string[]) => resolve(__dirname, "..", ...r); +export const rootResolve = (...r: string[]) => resolve(__dirname, "../../..", ...r); const nodeEnv = process.env.NODE_ENV; -log("当前的环境是: ", nodeEnv); +consola.log("当前的环境是: ", nodeEnv); function loadEnv(path: string) { const result: Record = {}; - const _loadEnv = (path: string) => { - if (!existsSync(path)) { - return null; - } - - const { error, parsed } = dotenv.config({ path }); - if (error != null || !parsed) { - return null; - } + if (!existsSync(path)) { + return null; + } - Object.keys(parsed).forEach((key) => { - result[key] = parsed[key]; - }); - }; + const { error, parsed } = dotenv.config({ path, override: true }); + if (error != null || !parsed) { + return null; + } - _loadEnv(path); - _loadEnv(`${path}.local`); + Object.keys(parsed).forEach((key) => { + result[key] = parsed[key]; + }); return result; } @@ -39,18 +31,13 @@ function loadEnv(path: string) { function loadDotEnv() { const env = loadEnv(rootResolve(".env")); const envMode = loadEnv(rootResolve(`.env.${nodeEnv}`)); + const envModeLocal = loadEnv(rootResolve(`.env.${nodeEnv}.local`)); - return { ...env, ...envMode }; + return { ...env, ...envMode, ...envModeLocal }; } export function loadDotEnvRuntime() { - const env = loadDotEnv(); - - Object.keys(env).forEach((key) => { - if (!process.env[key]) { - process.env[key] = env[key]; - } - }); + loadDotEnv(); } export function loadDotEnvDefined() { diff --git a/packages/main/src/controller/DownloadController.ts b/packages/main/src/controller/DownloadController.ts index 3c3b9547..97ffc6c0 100644 --- a/packages/main/src/controller/DownloadController.ts +++ b/packages/main/src/controller/DownloadController.ts @@ -77,9 +77,6 @@ export default class DownloadController implements Controller { async startDownload(e: IpcMainEvent, vid: number) { // 查找将要下载的视频 const video = await this.videoRepository.findVideo(vid); - if (!video) { - return Promise.reject("没有找到该视频"); - } const { name, url, headers, type } = video; const local = this.store.get("local"); diff --git a/packages/main/src/controller/HomeController.ts b/packages/main/src/controller/HomeController.ts index 1ebfae85..417f9d1c 100644 --- a/packages/main/src/controller/HomeController.ts +++ b/packages/main/src/controller/HomeController.ts @@ -170,7 +170,7 @@ export default class HomeController implements Controller { { label: "拷贝链接地址", click: () => { - clipboard.writeText(item?.url || ""); + clipboard.writeText(item.url || ""); }, }, { @@ -208,8 +208,8 @@ export default class HomeController implements Controller { async convertToAudio(e: IpcMainEvent, id: number) { const video = await this.videoRepository.findVideo(id); const local = this.store.get("local"); - const input = path.join(local, `${video?.name}.mp4`); - const output = path.join(local, `${video?.name}.mp3`); + const input = path.join(local, `${video.name}.mp4`); + const output = path.join(local, `${video.name}.mp3`); const exist = await fs.exists(input); if (exist) { @@ -250,6 +250,6 @@ export default class HomeController implements Controller { @handle("get-download-log") async getDownloadLog(event: IpcMainEvent, id: number) { const video = await this.videoRepository.findVideo(id); - return video?.log || ""; + return video.log || ""; } } diff --git a/packages/main/src/repository/VideoRepository.ts b/packages/main/src/repository/VideoRepository.ts index 9aeabdd7..a337c445 100644 --- a/packages/main/src/repository/VideoRepository.ts +++ b/packages/main/src/repository/VideoRepository.ts @@ -96,9 +96,14 @@ export default class VideoRepository { } async findVideo(id: number) { - return this.db.appDataSource.getRepository(Video).findOneBy({ - id, - }); + const repository = this.db.appDataSource.getRepository(Video); + const video = await repository.findOneBy({ id }); + + if (!video) { + throw new Error("没有找到该视频"); + } + + return video; } async findVideoByName(name: string) { @@ -117,14 +122,10 @@ export default class VideoRepository { .execute(); } - async changeVideoIsLive(id: number | number[], isLive: boolean) { - const ids = !Array.isArray(id) ? [id] : id; - return this.db.appDataSource - .createQueryBuilder() - .update(Video) - .set({ isLive }) - .where({ id: In(ids) }) - .execute(); + async changeVideoIsLive(id: number) { + const video = await this.findVideo(id); + video.isLive = true; + return this.db.manager.save(video); } async findWattingAndDownloadingVideos() { @@ -147,18 +148,12 @@ export default class VideoRepository { async appendDownloadLog(id: number, message: string) { const video = await this.findVideo(id); - if (!video) { - throw new Error("视频不存在"); - } video.log = video.log ? `${video.log}\n${message}` : message; return await this.db.manager.save(video); } async getDownloadLog(id: number) { const video = await this.findVideo(id); - if (!video) { - throw new Error("视频不存在"); - } return video.log; } } diff --git a/packages/main/src/services/DownloadService.ts b/packages/main/src/services/DownloadService.ts index a3ee26d6..55af1cd7 100644 --- a/packages/main/src/services/DownloadService.ts +++ b/packages/main/src/services/DownloadService.ts @@ -14,10 +14,21 @@ import { biliDownloaderBin, m3u8DownloaderBin } from "../helper"; import * as pty from "node-pty"; import stripAnsi from "strip-ansi"; +interface DownloadContext { + // 是否为直播 + isLive: boolean; + // 下载进度 + percent: string; + // 下载速度 + speed: string; + // 是否已经 ready + ready: boolean; +} + export interface DownloadOptions { abortSignal: AbortController; encoding?: string; - onMessage?: (ctx: any, message: string) => void; + onMessage?: (ctx: DownloadContext, message: string) => void; id: number; } @@ -64,7 +75,7 @@ const processList: Schema[] = [ percent: "([\\d.]+)%", speed: "([\\d.]+\\s[GMK]B/s)", error: "ERROR", - start: "开始下载文件", + start: "开始下载文件|开始录制", isLive: "识别为直播流, 开始录制", }, }, @@ -269,7 +280,12 @@ export default class DownloadService extends EventEmitter { }); if (onMessage) { - const ctx = {}; + const ctx: DownloadContext = { + ready: false, + isLive: false, + percent: "", + speed: "", + }; ptyProcess.onData((data) => { try { this.emit("download-message", id, data); @@ -347,7 +363,7 @@ export default class DownloadService extends EventEmitter { const speedReg = RegExp(consoleReg.speed, "g"); const percentReg = RegExp(consoleReg.percent, "g"); - const onMessage = (ctx: any, message: string) => { + const onMessage = (ctx: DownloadContext, message: string) => { // 解析是否为直播资源 if (isLiveReg.test(message)) { ctx.isLive = true; @@ -367,10 +383,11 @@ export default class DownloadService extends EventEmitter { callback({ id, type: "ready", - isLive: !!ctx.isLive, + isLive: ctx.isLive, speed: "", percent: "", }); + ctx.ready = true; return; } @@ -378,14 +395,15 @@ export default class DownloadService extends EventEmitter { throw new Error(message); } - // FIXME: 无法获取是否为直播流 - callback({ - id, - type: "progress", - percent: ctx.percent || "", - speed: ctx.speed || "", - isLive: !!ctx.isLive, - }); + if (ctx.ready && (ctx.percent || ctx.speed)) { + callback({ + id, + type: "progress", + percent: ctx.percent || "", + speed: ctx.speed || "", + isLive: ctx.isLive, + }); + } }; this.logger.debug("download params: ", spawnParams); diff --git a/packages/main/src/windows/MainWindow.ts b/packages/main/src/windows/MainWindow.ts index a0db401a..db07c8f3 100644 --- a/packages/main/src/windows/MainWindow.ts +++ b/packages/main/src/windows/MainWindow.ts @@ -48,9 +48,11 @@ export default class MainWindow extends Window { app.on("second-instance", this.secondInstance); } - onDownloadReadyStart = ({ id, isLive }: { id: number; isLive: boolean }) => { - this.videoRepository.changeVideoIsLive(id, isLive); - this.send("change-video-is-live", { id, isLive }); + onDownloadReadyStart = async ({ id, isLive }: DownloadProgress) => { + if (isLive) { + await this.videoRepository.changeVideoIsLive(id); + this.send("change-video-is-live", { id }); + } }; init(): void { @@ -112,7 +114,7 @@ export default class MainWindow extends Window { new Notification({ title: "下载成功", - body: `${video?.name} 下载成功`, + body: `${video.name} 下载成功`, }).show(); } @@ -126,7 +128,7 @@ export default class MainWindow extends Window { new Notification({ title: "下载失败", - body: `${video?.name} 下载失败`, + body: `${video.name} 下载失败`, }).show(); } this.logger.error("下载失败:", err); diff --git a/packages/renderer/src/components/DownloadForm/index.scss b/packages/renderer/src/components/DownloadForm/index.scss index e69de29b..8b1a3937 100644 --- a/packages/renderer/src/components/DownloadForm/index.scss +++ b/packages/renderer/src/components/DownloadForm/index.scss @@ -0,0 +1 @@ +// empty diff --git a/packages/renderer/src/components/PageContainer/index.scss b/packages/renderer/src/components/PageContainer/index.scss index fc152ea8..17ecaa69 100644 --- a/packages/renderer/src/components/PageContainer/index.scss +++ b/packages/renderer/src/components/PageContainer/index.scss @@ -13,18 +13,21 @@ border-bottom: #f0f0f0 solid 1px; background: #fff; } + @media (prefers-color-scheme: dark) { .page-container-header { background: #141414; border-bottom: #313131 solid 1px; } } + .page-container-inner { overflow: auto; flex: 1; padding: 15px; background: #fff; } + @media (prefers-color-scheme: dark) { .page-container-inner { background: #141414; diff --git a/packages/renderer/src/components/WebView/index.scss b/packages/renderer/src/components/WebView/index.scss index e69de29b..8b1a3937 100644 --- a/packages/renderer/src/components/WebView/index.scss +++ b/packages/renderer/src/components/WebView/index.scss @@ -0,0 +1 @@ +// empty diff --git a/packages/renderer/src/nodes/HomePage/index.scss b/packages/renderer/src/nodes/HomePage/index.scss index 1b8ae051..572102d3 100644 --- a/packages/renderer/src/nodes/HomePage/index.scss +++ b/packages/renderer/src/nodes/HomePage/index.scss @@ -3,23 +3,29 @@ padding-bottom: 10px; display: flex; flex-direction: column; + .download-list { height: 100%; overflow: hidden; + .ant-pro-card { height: 100%; + .ant-pro-card-body { padding: 0; display: flex; flex-direction: column; + .ant-list { flex: 1; overflow: hidden; display: flex; flex-direction: column; + .ant-spin-nested-loading { flex: 1; overflow: auto; + .ant-list-item { padding-left: 10px; } @@ -27,24 +33,29 @@ } } } + .description { text-overflow: ellipsis; white-space: nowrap; overflow: hidden; cursor: default; } + .download-progress { .ant-progress { align-items: center; - margin-bottom: 0px; + margin-bottom: 0; } + .progress-speed { line-height: 25px; min-width: max-content; } } + .ant-pro-list-row-title { cursor: default; + .title-disabled { opacity: 0.5; } diff --git a/packages/renderer/src/nodes/SettingPage/index.scss b/packages/renderer/src/nodes/SettingPage/index.scss index 70e73b76..a771232f 100644 --- a/packages/renderer/src/nodes/SettingPage/index.scss +++ b/packages/renderer/src/nodes/SettingPage/index.scss @@ -3,6 +3,7 @@ display: flex; flex-direction: row; align-items: center; + &-text { margin-right: 5px; } diff --git a/packages/renderer/src/nodes/SourceExtract/index.scss b/packages/renderer/src/nodes/SourceExtract/index.scss index 02666ca1..663aca72 100644 --- a/packages/renderer/src/nodes/SourceExtract/index.scss +++ b/packages/renderer/src/nodes/SourceExtract/index.scss @@ -3,16 +3,20 @@ height: 100vh; width: 100vw; } + .source-extract-inner { padding: 0; display: flex; flex-direction: column; + .action-bar { padding: 10px 5px; } + .source-extract-content { flex: 1; overflow: auto; + .webview-container { height: 100%; width: 100%; @@ -20,23 +24,28 @@ flex-direction: row; align-items: center; justify-content: center; + .webview-inner { height: 100%; width: 100%; } + .webview-sider { height: 100%; padding: 0 10px 10px 5px; overflow: auto; + .webview-sider-inner { .ant-collapse-header { align-items: center; + .ant-collapse-header-text { text-overflow: ellipsis; overflow: hidden; white-space: nowrap; } } + .sider-list-container { .sider-list { .sider-item { @@ -44,6 +53,7 @@ color: #666; word-break: break-all; margin-top: 5px; + &:first-child { margin-top: -5px; } @@ -52,11 +62,13 @@ } } } + .divider { position: relative; width: 6px; background-color: #ddd; cursor: ew-resize; + .handle { position: absolute; top: 50%; @@ -73,32 +85,37 @@ } } } + .list-container { padding: 30px; flex: 1; + .list-item { display: flex; flex-direction: column; align-items: center; + .list-tem-card { position: relative; height: 80px; - width: 80px; - padding: 10px; + width: 70px; cursor: pointer; display: flex; flex-direction: column; align-items: center; justify-content: center; border-radius: 5px; + &:hover { background: #f2f6fc; } + @media (prefers-color-scheme: dark) { &:hover { background: #595959; } } + .card-text { width: 100%; margin-top: 6px; diff --git a/packages/renderer/src/nodes/SourceExtract/index.tsx b/packages/renderer/src/nodes/SourceExtract/index.tsx index b02a0d2f..63b123e1 100644 --- a/packages/renderer/src/nodes/SourceExtract/index.tsx +++ b/packages/renderer/src/nodes/SourceExtract/index.tsx @@ -270,8 +270,7 @@ const SourceExtract: React.FC = ({ page = false }) => { setModalShow(true); }; - const onShowDownloadDialog = async (e: any, data: DownloadForm[]) => { - console.log(data); + const onShowDownloadDialog = async (e: unknown, data: DownloadForm[]) => { setDownloadItems(data); setCurrentDownloadForm(data[0]); }; @@ -555,12 +554,10 @@ const SourceExtract: React.FC = ({ page = false }) => { const data = form.getFieldsValue(); const { numberOfEpisodes, teleplay, ...item } = data; - if (teleplay) { - await localforage.setItem("numberOfEpisodes", { - numberOfEpisodes, - teleplay, - }); - } + await localforage.setItem("numberOfEpisodes", { + numberOfEpisodes, + teleplay, + }); if (teleplay) { item.name = `${item.name}——第${numberOfEpisodes}集`; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4dd8f1ea..4e6e5652 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -75,10 +75,10 @@ importers: dependencies: '@cliqz/adblocker-electron': specifier: ^1.27.3 - version: 1.27.3(electron@28.2.6) + version: 1.27.3(electron@28.3.1) '@cliqz/adblocker-electron-preload': specifier: ^1.27.3 - version: 1.27.3(electron@28.2.6) + version: 1.27.3(electron@28.3.1) axios: specifier: ^1.6.5 version: 1.6.5 @@ -170,6 +170,9 @@ importers: chokidar: specifier: ^3.5.3 version: 3.5.3 + consola: + specifier: ^3.2.3 + version: 3.2.3 cross-env: specifier: ^7.0.3 version: 7.0.3 @@ -178,7 +181,7 @@ importers: version: 16.3.2 electron: specifier: ^28.2.6 - version: 28.2.6 + version: 28.3.1 electron-builder: specifier: ^24.9.1 version: 24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)) @@ -232,17 +235,17 @@ importers: dependencies: '@cliqz/adblocker-electron': specifier: ^1.27.3 - version: 1.27.3(electron@28.2.6) + version: 1.27.3(electron@28.3.1) '@cliqz/adblocker-electron-preload': specifier: ^1.27.3 - version: 1.27.3(electron@28.2.6) + version: 1.27.3(electron@28.3.1) node-pty: specifier: ^1.0.0 version: 1.0.0 devDependencies: electron: specifier: ^28.2.6 - version: 28.2.6 + version: 28.3.1 packages/plugin: dependencies: @@ -2669,6 +2672,10 @@ packages: resolution: {integrity: sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==} engines: {node: '>=12'} + consola@3.2.3: + resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==} + engines: {node: ^14.18.0 || >=16.10.0} + console-control-strings@1.1.0: resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} @@ -3014,8 +3021,8 @@ packages: electron-updater@6.1.7: resolution: {integrity: sha512-SNOhYizjkm4ET+Y8ilJyUzcVsFJDtINzVN1TyHnZeMidZEG3YoBebMyXc/J6WSiXdUaOjC7ngekN6rNp6ardHA==} - electron@28.2.6: - resolution: {integrity: sha512-RuhbW+ifvh3DqnVlHCcCKhKIFOxTktq1GN1gkIkEZ8y5LEZfcjOkxB2s6Fd1S6MzsMZbiJti+ZJG5hXS4SDVLQ==} + electron@28.3.1: + resolution: {integrity: sha512-aF9fONuhVDJlctJS7YOw76ynxVAQdfIWmlhRMKits24tDcdSL0eMHUS0wWYiRfGWbQnUKB6V49Rf17o32f4/fg==} engines: {node: '>= 12.20.55'} hasBin: true @@ -6531,16 +6538,16 @@ snapshots: dependencies: '@cliqz/adblocker-extended-selectors': 1.27.3 - '@cliqz/adblocker-electron-preload@1.27.3(electron@28.2.6)': + '@cliqz/adblocker-electron-preload@1.27.3(electron@28.3.1)': dependencies: '@cliqz/adblocker-content': 1.27.3 - electron: 28.2.6 + electron: 28.3.1 - '@cliqz/adblocker-electron@1.27.3(electron@28.2.6)': + '@cliqz/adblocker-electron@1.27.3(electron@28.3.1)': dependencies: '@cliqz/adblocker': 1.27.3(patch_hash=ehnwxuhizcxatborac3eqflbk4) - '@cliqz/adblocker-electron-preload': 1.27.3(electron@28.2.6) - electron: 28.2.6 + '@cliqz/adblocker-electron-preload': 1.27.3(electron@28.3.1) + electron: 28.3.1 tldts-experimental: 6.1.2 '@cliqz/adblocker-extended-selectors@1.27.3': {} @@ -8750,6 +8757,8 @@ snapshots: write-file-atomic: 3.0.3 xdg-basedir: 5.1.0 + consola@3.2.3: {} + console-control-strings@1.1.0: {} conventional-changelog-angular@7.0.0: @@ -9180,7 +9189,7 @@ snapshots: transitivePeerDependencies: - supports-color - electron@28.2.6: + electron@28.3.1: dependencies: '@electron/get': 2.0.3 '@types/node': 18.19.6