diff --git a/ffplay/81.ico b/ffplay/81.ico new file mode 100644 index 0000000..37dc2bd Binary files /dev/null and b/ffplay/81.ico differ diff --git a/ffplay/avcodec-60.dll b/ffplay/avcodec-60.dll new file mode 100644 index 0000000..1cdba31 Binary files /dev/null and b/ffplay/avcodec-60.dll differ diff --git a/ffplay/avdevice-60.dll b/ffplay/avdevice-60.dll new file mode 100644 index 0000000..30c2e0a Binary files /dev/null and b/ffplay/avdevice-60.dll differ diff --git a/ffplay/avfilter-9.dll b/ffplay/avfilter-9.dll new file mode 100644 index 0000000..5571ab2 Binary files /dev/null and b/ffplay/avfilter-9.dll differ diff --git a/ffplay/avformat-60.dll b/ffplay/avformat-60.dll new file mode 100644 index 0000000..413038c Binary files /dev/null and b/ffplay/avformat-60.dll differ diff --git a/ffplay/avutil-58.dll b/ffplay/avutil-58.dll new file mode 100644 index 0000000..af1419a Binary files /dev/null and b/ffplay/avutil-58.dll differ diff --git a/ffplay/earth.ico b/ffplay/earth.ico new file mode 100644 index 0000000..1610ac5 Binary files /dev/null and b/ffplay/earth.ico differ diff --git a/ffplay/ffmpeg.exe b/ffplay/ffmpeg.exe new file mode 100644 index 0000000..15dc359 Binary files /dev/null and b/ffplay/ffmpeg.exe differ diff --git a/ffplay/ffmpeg_arm b/ffplay/ffmpeg_arm new file mode 100644 index 0000000..a7452f7 Binary files /dev/null and b/ffplay/ffmpeg_arm differ diff --git a/ffplay/ffmpeg_x86 b/ffplay/ffmpeg_x86 new file mode 100644 index 0000000..da3cb34 Binary files /dev/null and b/ffplay/ffmpeg_x86 differ diff --git a/ffplay/ffplay b/ffplay/ffplay new file mode 100644 index 0000000..75177dd Binary files /dev/null and b/ffplay/ffplay differ diff --git a/ffplay/ffplay.exe b/ffplay/ffplay.exe new file mode 100644 index 0000000..8c14576 Binary files /dev/null and b/ffplay/ffplay.exe differ diff --git a/ffplay/ffprobe.exe b/ffplay/ffprobe.exe new file mode 100644 index 0000000..2b5bdbf Binary files /dev/null and b/ffplay/ffprobe.exe differ diff --git a/ffplay/jingwu.ico b/ffplay/jingwu.ico new file mode 100644 index 0000000..869db0a Binary files /dev/null and b/ffplay/jingwu.ico differ diff --git a/ffplay/postproc-57.dll b/ffplay/postproc-57.dll new file mode 100644 index 0000000..5087877 Binary files /dev/null and b/ffplay/postproc-57.dll differ diff --git a/ffplay/rcedit-x86.exe b/ffplay/rcedit-x86.exe new file mode 100644 index 0000000..779c314 Binary files /dev/null and b/ffplay/rcedit-x86.exe differ diff --git a/ffplay/rcedit-x86.txt b/ffplay/rcedit-x86.txt new file mode 100644 index 0000000..5d71973 --- /dev/null +++ b/ffplay/rcedit-x86.txt @@ -0,0 +1 @@ +$ rcedit "path-to-exe-or-dll" --set-icon "path-to-ico" \ No newline at end of file diff --git a/ffplay/swresample-4.dll b/ffplay/swresample-4.dll new file mode 100644 index 0000000..85075a8 Binary files /dev/null and b/ffplay/swresample-4.dll differ diff --git a/ffplay/swscale-7.dll b/ffplay/swscale-7.dll new file mode 100644 index 0000000..3d84c37 Binary files /dev/null and b/ffplay/swscale-7.dll differ diff --git a/package-lock.json b/package-lock.json index a773dd6..19c7745 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "electron-updater": "^6.3.9", "element-plus": "^2.10.4", "mitt": "^3.0.1", + "moment": "^2.30.1", "pinia": "^3.0.3", "pinia-plugin-persistedstate": "^4.4.1", "scss": "^0.2.4", @@ -9301,6 +9302,15 @@ "pathe": "^2.0.1" } }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmmirror.com/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", diff --git a/package.json b/package.json index 9aa2ede..16e7c91 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "electron-updater": "^6.3.9", "element-plus": "^2.10.4", "mitt": "^3.0.1", + "moment": "^2.30.1", "pinia": "^3.0.3", "pinia-plugin-persistedstate": "^4.4.1", "scss": "^0.2.4", diff --git a/src/main/index.ts b/src/main/index.ts index 557d8b1..3345285 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,8 +1,10 @@ -import { app, shell, BrowserWindow, ipcMain, globalShortcut } from 'electron' +import { app, shell, BrowserWindow, ipcMain, globalShortcut, dialog } from 'electron' import path, { join } from 'path' import { electronApp, optimizer, is } from '@electron-toolkit/utils' import icon from '../../resources/earth.png?asset' +import { Recorder } from "../preload/recorder"; import fs from 'fs' +import dayjs from 'dayjs' const { exec } = require('child_process'); @@ -126,6 +128,50 @@ function createWindow(): void { }, 200) }) }) + ipcMain.on("saveFile", (event, { title, filename, filters }) => { + dialog + .showSaveDialog({ + title, + defaultPath: filename, + filters, + }) + .then((files) => { + let path = ""; + if (!files.canceled) { + path = files.filePath.replace(/\\/g, "/"); + } + event.sender.send("selectedFileItem", path); + }); + }); + + let recorder; + ipcMain.on("startRecoder", (event) => { + console.log("开始录制"); + recorder = new Recorder(); + recorder.start(); + }); + ipcMain.on("endRecoder", (event) => { + console.log("结束录制"); + // 判断是否存在recorder,是否有recorder.end方法 + if (!recorder) { + console.log("recorder不存在"); + return; + } + recorder.end(() => { + let path = dialog.showSaveDialogSync({ + title: "保存视频文件", + defaultPath: dayjs().format("YYYYMMDDHHmmss") + "视频录制.mp4", + filters: [{ name: "文件类型", extensions: ["mp4"] }], + }); + if (path != undefined) { + recorder.move(path, () => { + recorder = null; + }); + } else { + recorder = null; + } + }); + }); // 设置窗口标题和图标 mainWindow.webContents.setWindowOpenHandler((details) => { shell.openExternal(details.url) diff --git a/src/preload/config.ts b/src/preload/config.ts new file mode 100644 index 0000000..05a7d4e --- /dev/null +++ b/src/preload/config.ts @@ -0,0 +1,22 @@ +//获取项目根目录 +function GetHomeDir() { + let HOME_DIR = process.cwd(); + console.log("process.env.NODE_ENV", process.env.NODE_ENV); + if (process.env.NODE_ENV === "production") { + let arr = process.execPath.replaceAll("\\", "/").split("/"); + arr.pop(); + HOME_DIR = arr.join("/"); + } + return HOME_DIR; +} +//获取项目根目录 +function GetAsar() { + let HOME_DIR = process.cwd(); + if (process.env.NODE_ENV === "production") { + let arr = process.execPath.replaceAll("\\", "/").split("/"); + arr.pop(); + HOME_DIR = arr.join("/"); + } + return HOME_DIR; +} +export { GetHomeDir, GetAsar }; diff --git a/src/preload/index.ts b/src/preload/index.ts index 556c4d8..5c41ea8 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -23,3 +23,4 @@ if (process.contextIsolated) { // @ts-ignore (define in dts) window.YJColorPicker = YJColorPicker } + diff --git a/src/preload/recorder.ts b/src/preload/recorder.ts new file mode 100644 index 0000000..e4972c8 --- /dev/null +++ b/src/preload/recorder.ts @@ -0,0 +1,113 @@ +import path from "path"; +import { GetHomeDir } from "./config"; +const os = require("os"); +const fs = require("fs"); +let platform = os.platform(); +const arch = os.arch(); +const moment = require("moment"); +const { spawn } = require("child_process"); +const EventEmitter = require("events"); +let ffmpegExePath = path.join(GetHomeDir(), "ffplay"); +class MyEmitter extends EventEmitter { } + +const myEmitter = new MyEmitter(); +class Recorder { + constructor(option = {}) { + this.shell = undefined; + this.filename = + moment(parseInt(new Date().getTime())).format("YYYYMMDDHHmmss") + ".mp4"; + this.exe = "ffmpeg.exe"; + if (platform === "win32") { + this.exe = "ffmpeg.exe"; + this.params = "-f gdigrab -r 30 -y -i desktop -pix_fmt yuv420p"; + } + if (platform === "linux") { + switch (arch) { + case "x64": + this.exe = "ffmpeg_x86"; + break; + case "arm": + this.exe = "ffmpeg_arm"; + break; + } + this.params = + "-v verbose -video_size 1920x1080 -framerate 25 -f x11grab -i :0.0 -c:v libx264 -preset ultrafast -crf 18"; + //-s 1920x1080 + // ffmpeg -video_size 1920x1080 -framerate 25 -f x11grab -i :0.0 -c:v libx264 -preset ultrafast -crf 18 output.mp4 + } + this.commands = path.join(GetHomeDir(), "/ffplay/" + this.exe); + } + get_path() { + return path.join(ffmpegExePath, this.filename); + } + start() { + this.exec(this.commands, this.params); + } + + exec(commands, param) { + let arr = param.split(" "); + arr.push(this.get_path()); + console.log("commands, arr", commands, arr); + this.shell = spawn(commands, arr, { + ffmpegExePath, + // stdio: "ignore", + // shell: true + }) + .on("exit", (err) => { + console.log("exit", err); + myEmitter.emit("process-exit"); + }) + .on("data", function (data) { + // console.log(typeof data); + }) + .on("data", function (data) { }); + this.shell.unref(); + } + end(cb) { + if (!this.shell.killed) { + console.log(this.shell); + this.shell.stdin.write("q"); + myEmitter.once("process-exit", () => { + cb(); + }); + } else { + cb(); + } + } + move(dst, cb) { + let readStream = fs.createReadStream(this.get_path()); + let writeStream = fs.createWriteStream(dst); + readStream.pipe(writeStream); + readStream.on("end", () => { + fs.unlinkSync(this.get_path()); + cb(); + }); + } +} +/*function start() { + config.recorder = new Recorder() + config.recorder.start() +} + +function end(cb) { + config.recorder.end(() => { + cb() + }) +} + +function getRecorder() { + return config.recorder +} + +function resetRecorder() { + config.recorder = null +} + +exports.Recorder = { + start, + end, + getRecorder, + resetRecorder, +}*/ + +export { Recorder }; diff --git a/src/renderer/src/api/setting/auth.ts b/src/renderer/src/api/setting/auth.ts new file mode 100644 index 0000000..d7981b9 --- /dev/null +++ b/src/renderer/src/api/setting/auth.ts @@ -0,0 +1,16 @@ +//授权 +import request from '@/axios/request' +export const AuthApi = { + // 查看授权信息 + showAuth: async () => { + return await request.get({ + url: `/auth/show` + }) + }, + //获取系统授权码 + authInfo: async () => { + return await request.get({ + url: `/auth/info` + }) + }, +} diff --git a/src/renderer/src/axios/index.ts b/src/renderer/src/axios/index.ts index 27644bb..34acfd1 100644 --- a/src/renderer/src/axios/index.ts +++ b/src/renderer/src/axios/index.ts @@ -10,14 +10,14 @@ import type { const pendingRequests = new Map() let baseURL: any if (window && window.process && window.process.type === 'renderer') { - baseURL = localStorage.getItem('ip') ||'http://192.168.110.25:8848'|| 'http://127.0.0.1:8808' + baseURL = localStorage.getItem('ip') || 'http://192.168.110.25:8848' || 'http://127.0.0.1:8808' } else { baseURL = '' } // 创建自定义配置的axios实例 const service: AxiosInstance = axios.create({ - baseURL:'http://192.168.110.25:8848', + baseURL: 'http://192.168.110.25:8848', timeout: 10000, headers: { 'Content-Type': 'application/json', @@ -49,10 +49,10 @@ service.interceptors.request.use( // 在这里添加认证token const token = localStorage.getItem('Authorization') -console.log("localStorage.getItem('Authorization')",token); + console.log("localStorage.getItem('Authorization')", token); if (token && config.headers) { - // Bearer + // Bearer config.headers.Authorization = `${token}` } return config @@ -67,18 +67,18 @@ service.interceptors.response.use( (response: AxiosResponse) => { const key = getRequestKey(response.config) pendingRequests.delete(key) -console.log(response); + console.log(response); // 统一处理HTTP状态码 if (response.status === 200) { - if ([0,200].includes(response.data.code)) { + if ([0, 200].includes(response.data.code)) { return response } - if (response.data.code==401) { + if (response.data.code == 401) { router.push('/') localStorage.removeItem('Authorization') } - if (![0,200].includes(response.data.code)) { + if (![0, 200].includes(response.data.code)) { ElMessage({ message: response.data.msg || response.data.message, type: 'error' diff --git a/src/renderer/src/components/upload/uploadFiles.vue b/src/renderer/src/components/upload/uploadFiles.vue index 6ab56c7..4e634aa 100644 --- a/src/renderer/src/components/upload/uploadFiles.vue +++ b/src/renderer/src/components/upload/uploadFiles.vue @@ -1,6 +1,6 @@