diff --git a/README.md b/README.md index 2c9011c0..4ee62350 100644 --- a/README.md +++ b/README.md @@ -37,10 +37,9 @@ ## Installation -``` -gitee: https://gitee.com/xiguapi027/pear-rec -github: https://github.com/027xiguapi/pear-rec -``` +> gitee: https://gitee.com/xiguapi027/pear-rec +> +> github: https://github.com/027xiguapi/pear-rec ## Usage diff --git a/README.zh-CN.md b/README.zh-CN.md index cc2986c8..9291c9c8 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -25,9 +25,9 @@ ## 简介 -> pear-rec(梨子 rec) 是一个跨平台的截图、录屏、录音、录像软件。 +> pear-rec(梨子 rec) 是一个跨平台的截图、录屏、录音、录像、录制(动图)gif、查看图片、查看视频、查看音频和修改图片的软件。 > -> pear-rec(pear rec) 是基于 react + electron + vite + viewerjs + plyr + aplayer + react-screenshots 的一个项目。 +> pear-rec(pear rec) 是基于 react + electron + vite + viewerjs + plyr + aplayer + react-screenshots + tui-image-editor + gif.js 的一个项目。 > > 更多功能和 api 可以查看[官网(https://027xiguapi.github.io/pear-rec)](https://027xiguapi.github.io/pear-rec) 或 [https://xiguapi027.gitee.io/pear-rec](https://xiguapi027.gitee.io/pear-rec) @@ -37,10 +37,9 @@ ## 下载地址 -``` -gitee: https://gitee.com/xiguapi027/pear-rec -github: https://github.com/027xiguapi/pear-rec -``` +> gitee: https://gitee.com/xiguapi027/pear-rec +> +> github: https://github.com/027xiguapi/pear-rec ## 源码运行&编译 @@ -129,6 +128,7 @@ pnpm run build:desktop - [x] 图片编辑(tui-image-editor) - [x] 视频预览(plyr) - [x] 音频预览(aplayer) +- [x] 动图(gif)编辑(gif.js) - [x] 基本设置 - [x] 用户 uuid - [x] 保存地址 diff --git a/package.json b/package.json index 54fed347..f72cf4f0 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "only-build:web": "pnpm run -C packages/web build", "watch:web": "pnpm run -C packages/web watch", "project:web": "pnpm run -C packages/web build && node tools/copy-files-web2server.js", - "dev:server": "pnpm run -C packages/server start:dev", + "dev:server": "pnpm run -C packages/server dev", "build:server": "pnpm run -C packages/server build", "dev:docs": "pnpm run -C packages/docs dev", "build:docs": "pnpm run -C packages/docs build", diff --git a/packages/desktop/CHANGELOG.md b/packages/desktop/CHANGELOG.md index a66dc99d..bede3b23 100644 --- a/packages/desktop/CHANGELOG.md +++ b/packages/desktop/CHANGELOG.md @@ -1,5 +1,9 @@ # @pear-rec/desktop +## 1.3.6 + +feat: 修改GIF + ## 1.3.5 feat: 增加服务子进程 diff --git a/packages/desktop/electron/main/ipcMain.ts b/packages/desktop/electron/main/ipcMain.ts index eef4b371..6d9c437e 100644 --- a/packages/desktop/electron/main/ipcMain.ts +++ b/packages/desktop/electron/main/ipcMain.ts @@ -13,6 +13,7 @@ import * as settingWin from '../win/settingWin'; import * as recordsWin from '../win/recordsWin'; import * as pinImageWin from '../win/pinImageWin'; import * as recorderFullScreenWin from '../win/recorderFullScreenWin'; +import * as editGifWin from '../win/editGifWin'; import * as utils from './utils'; import { editConfig } from '@pear-rec/server/src/config'; @@ -102,9 +103,9 @@ function initIpcMain() { recorderScreenWin.focusRecorderScreenWin(); }); // 录屏截图 - ipcMain.on('cs:open-win', () => { + ipcMain.on('cs:open-win', (e, search) => { clipScreenWin.closeClipScreenWin(); - clipScreenWin.openClipScreenWin(); + clipScreenWin.openClipScreenWin(search); }); ipcMain.on('cs:close-win', () => { clipScreenWin.closeClipScreenWin(); @@ -196,8 +197,16 @@ function initIpcMain() { ipcMain.on('ei:open-win', (e, search) => { editImageWin.openEditImageWin(search); }); + // 动图编辑 + ipcMain.on('eg:close-win', () => { + editGifWin.closeEditGifWin(); + }); + ipcMain.on('eg:open-win', (e, search) => { + editGifWin.openEditGifWin(search); + }); // 视频音频展示; ipcMain.on('vv:open-win', (e, search) => { + viewVideoWin.closeViewVideoWin(); viewVideoWin.openViewVideoWin(search); }); ipcMain.on('vv:close-win', () => { diff --git a/packages/desktop/electron/preload/electronAPI.ts b/packages/desktop/electron/preload/electronAPI.ts index 72395f6e..7be4cef8 100644 --- a/packages/desktop/electron/preload/electronAPI.ts +++ b/packages/desktop/electron/preload/electronAPI.ts @@ -35,7 +35,7 @@ contextBridge.exposeInMainWorld('electronAPI', { handleRsGetEndRecord: (callback: any) => ipcRenderer.on('rs:get-end-record', callback), //csWin - sendCsOpenWin: () => ipcRenderer.send('cs:open-win'), + sendCsOpenWin: (search?: any) => ipcRenderer.send('cs:open-win', search), sendCsCloseWin: () => ipcRenderer.send('cs:close-win'), sendCsHideWin: () => ipcRenderer.send('cs:hide-win'), sendCsMinimizeWin: () => ipcRenderer.send('cs:minimize-win'), @@ -47,6 +47,7 @@ contextBridge.exposeInMainWorld('electronAPI', { sendCsSetBounds: (bounds: any) => { ipcRenderer.send('cs:set-bounds', bounds); }, + //rvWin sendRvCloseWin: () => ipcRenderer.send('rv:close-win'), sendRvOpenWin: () => ipcRenderer.send('rv:open-win'), @@ -74,7 +75,10 @@ contextBridge.exposeInMainWorld('electronAPI', { //eiWin sendEiCloseWin: () => ipcRenderer.send('ei:close-win'), sendEiOpenWin: (search?: string) => ipcRenderer.send('ei:open-win', search), - sendEiSaveImg: (imgUrl: string) => ipcRenderer.send('ei:save-img', imgUrl), + + //egWin + sendEgCloseWin: () => ipcRenderer.send('eg:close-win'), + sendEgOpenWin: (search?: string) => ipcRenderer.send('eg:open-win', search), //vvWin sendVvOpenWin: (search?: string) => ipcRenderer.send('vv:open-win', search), diff --git a/packages/desktop/electron/win/clipScreenWin.ts b/packages/desktop/electron/win/clipScreenWin.ts index 5aebb140..4f12f5a6 100644 --- a/packages/desktop/electron/win/clipScreenWin.ts +++ b/packages/desktop/electron/win/clipScreenWin.ts @@ -64,13 +64,13 @@ function showClipScreenWin() { clipScreenWin?.show(); } -function openClipScreenWin() { +function openClipScreenWin(search?: any) { if (!clipScreenWin || clipScreenWin?.isDestroyed()) { clipScreenWin = createClipScreenWin(); } clipScreenWin?.show(); - openRecorderScreenWin(); + openRecorderScreenWin(search); } function getBoundsClipScreenWin() { diff --git a/packages/desktop/electron/win/editGifWin.ts b/packages/desktop/electron/win/editGifWin.ts new file mode 100644 index 00000000..1b815567 --- /dev/null +++ b/packages/desktop/electron/win/editGifWin.ts @@ -0,0 +1,45 @@ +import { BrowserWindow, dialog, shell, DownloadItem, WebContents } from 'electron'; +import { join, dirname } from 'node:path'; +import { ICON, DIST, preload, url, WEB_URL } from '../main/contract'; + +const editGifHtml = join(DIST, './editGif.html'); +let editGifWin: BrowserWindow | null = null; + +function createEditGifWin(search?: any): BrowserWindow { + editGifWin = new BrowserWindow({ + title: 'pear-rec 动图编辑', + icon: ICON, + height: 768, + width: 1024, + autoHideMenuBar: true, // 自动隐藏菜单栏 + webPreferences: { + preload, + }, + }); + + const videoUrl = search?.videoUrl || ''; + + // editGifWin.webContents.openDevTools(); + if (url) { + editGifWin.loadURL(WEB_URL + `editGif.html?videoUrl=${videoUrl}`); + } else { + editGifWin.loadFile(editGifHtml, { + search: `?videoUrl=${videoUrl}`, + }); + } + + return editGifWin; +} + +function openEditGifWin(search?: any) { + if (!editGifWin || editGifWin?.isDestroyed()) { + editGifWin = createEditGifWin(search); + } + editGifWin.show(); +} + +function closeEditGifWin() { + editGifWin?.close(); +} + +export { createEditGifWin, openEditGifWin, closeEditGifWin }; diff --git a/packages/desktop/electron/win/recorderScreenWin.ts b/packages/desktop/electron/win/recorderScreenWin.ts index 0413b76a..3426c17a 100644 --- a/packages/desktop/electron/win/recorderScreenWin.ts +++ b/packages/desktop/electron/win/recorderScreenWin.ts @@ -34,10 +34,12 @@ function createRecorderScreenWin(search?: any): BrowserWindow { }); recorderScreenWin?.setResizable(false); if (url) { - recorderScreenWin.loadURL(WEB_URL + `recorderScreen.html`); + recorderScreenWin.loadURL(WEB_URL + `recorderScreen.html?type=${search?.type || ''}`); // recorderScreenWin.webContents.openDevTools(); } else { - recorderScreenWin.loadFile(recorderScreenHtml); + recorderScreenWin.loadFile(recorderScreenHtml, { + search: `?type=${search?.type || ''}`, + }); } recorderScreenWin.on('move', () => { @@ -54,12 +56,6 @@ function createRecorderScreenWin(search?: any): BrowserWindow { return recorderScreenWin; } -async function recorderScreen(rsFilePath: string) { - // closeRecorderScreenWin(); - // setHistoryVideo(rsFilePath); - shell.showItemInFolder(rsFilePath); -} - // 打开关闭录屏窗口 function closeRecorderScreenWin() { recorderScreenWin?.isDestroyed() || recorderScreenWin?.close(); diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 98bc5d25..02484481 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@pear-rec/desktop", - "version": "1.3.4", + "version": "1.3.6", "main": "dist-electron/main/index.js", "description": "pear-rec", "author": "027xiguapi", diff --git a/packages/server/package.json b/packages/server/package.json index 729084ac..36a74f09 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -6,7 +6,7 @@ "webpack": "nest build", "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", "start": "nest start", - "start:dev": "nest start --watch", + "dev": "nest start --watch", "start:debug": "nest start --debug --watch", "start:prod": "node dist/main" }, diff --git a/packages/server/src/util/upload.middleware.ts b/packages/server/src/util/upload.middleware.ts index 1aca13a1..12f691be 100644 --- a/packages/server/src/util/upload.middleware.ts +++ b/packages/server/src/util/upload.middleware.ts @@ -30,7 +30,7 @@ export class UploadMiddleware implements MulterOptionsFactory { rs: 'webm', ra: 'webm', ei: 'png', - gif: 'gif', + eg: 'gif', }; const type = req.body.type; const fileType = fileTypeMap[type] || 'webm'; diff --git a/packages/web/CHANGELOG.md b/packages/web/CHANGELOG.md index a16b2079..c4ff3cc5 100644 --- a/packages/web/CHANGELOG.md +++ b/packages/web/CHANGELOG.md @@ -1,5 +1,9 @@ # @pear-rec/web +## 1.3.9 + +feat: 修改GIF + ## 1.3.8 fix: 修改图片和钉图打不开bug diff --git a/packages/web/src/components/card/recordScreenCard.tsx b/packages/web/src/components/card/recordScreenCard.tsx index 123f2af7..2b2737a8 100644 --- a/packages/web/src/components/card/recordScreenCard.tsx +++ b/packages/web/src/components/card/recordScreenCard.tsx @@ -1,18 +1,34 @@ import React, { useImperativeHandle, forwardRef } from 'react'; import { useTranslation } from 'react-i18next'; import { CameraOutlined, DownOutlined } from '@ant-design/icons'; -import { Card, Space, Button } from 'antd'; +import type { MenuProps } from 'antd'; +import { Card, Space, Button, Dropdown } from 'antd'; const RecordScreenCard = forwardRef((props: any, ref: any) => { useImperativeHandle(ref, () => ({})); const { t } = useTranslation(); - function handleClipScreen() { + const items: MenuProps['items'] = [ + { + label: '录屏', + key: 'video', + }, + { + label: 'GIF', + key: 'gif', + }, + ]; + + const onClick: MenuProps['onClick'] = ({ key }) => { + handleClipScreenClick(key); + }; + + function handleClipScreenClick(type) { if (window.isElectron) { - window.electronAPI.sendCsOpenWin(); + window.electronAPI.sendCsOpenWin({ type }); window.electronAPI.sendMaCloseWin(); } else { - location.href = '/recorderScreen.html'; + location.href = `/recorderScreen.html?type=${type}`; } } @@ -31,9 +47,12 @@ const RecordScreenCard = forwardRef((props: any, ref: any) => { {t('home.fullScreen')}
- - - + + + handleClipScreenClick('video')} /> + + +
{t('home.screenRecording')}
diff --git a/packages/web/src/components/videoToGif/VideoToGifConverter.tsx b/packages/web/src/components/editGif/VideoToGifConverter.tsx similarity index 96% rename from packages/web/src/components/videoToGif/VideoToGifConverter.tsx rename to packages/web/src/components/editGif/VideoToGifConverter.tsx index fa1d82bd..067c48d3 100644 --- a/packages/web/src/components/videoToGif/VideoToGifConverter.tsx +++ b/packages/web/src/components/editGif/VideoToGifConverter.tsx @@ -86,7 +86,7 @@ export default function VideoToGifConverter({ videoSrc, user }) { } try { const formData = new FormData(); - formData.append('type', 'gif'); + formData.append('type', 'eg'); formData.append('userId', user.id); formData.append('file', blob); const res = (await api.saveFile(formData)) as any; @@ -117,19 +117,20 @@ export default function VideoToGifConverter({ videoSrc, user }) { return (
-
- - +
+ + GIF
); diff --git a/packages/web/src/components/videoToGif/gif.js/gif.js b/packages/web/src/components/editGif/gif.js/gif.js similarity index 100% rename from packages/web/src/components/videoToGif/gif.js/gif.js rename to packages/web/src/components/editGif/gif.js/gif.js diff --git a/packages/web/src/components/videoToGif/gif.js/gif.js.map b/packages/web/src/components/editGif/gif.js/gif.js.map similarity index 100% rename from packages/web/src/components/videoToGif/gif.js/gif.js.map rename to packages/web/src/components/editGif/gif.js/gif.js.map diff --git a/packages/web/src/components/videoToGif/gif.js/gif.worker.js b/packages/web/src/components/editGif/gif.js/gif.worker.js similarity index 100% rename from packages/web/src/components/videoToGif/gif.js/gif.worker.js rename to packages/web/src/components/editGif/gif.js/gif.worker.js diff --git a/packages/web/src/components/videoToGif/gif.js/gif.worker.js.map b/packages/web/src/components/editGif/gif.js/gif.worker.js.map similarity index 100% rename from packages/web/src/components/videoToGif/gif.js/gif.worker.js.map rename to packages/web/src/components/editGif/gif.js/gif.worker.js.map diff --git a/packages/web/src/components/recorderScreen/ScreenRecorder.tsx b/packages/web/src/components/recorderScreen/ScreenRecorder.tsx index 3c2b1a7e..8f8d1d27 100644 --- a/packages/web/src/components/recorderScreen/ScreenRecorder.tsx +++ b/packages/web/src/components/recorderScreen/ScreenRecorder.tsx @@ -202,6 +202,9 @@ const ScreenRecorder = (props) => { async function saveFile(blob) { try { + const paramsString = location.search; + const searchParams = new URLSearchParams(paramsString); + const type = searchParams.get('type'); recordedChunks.current = []; const formData = new FormData(); formData.append('type', 'rs'); @@ -211,8 +214,9 @@ const ScreenRecorder = (props) => { if (res.code == 0) { if (window.isElectron) { window.electronAPI.sendRsCloseWin(); - window.electronAPI.sendVvCloseWin(); - window.electronAPI.sendVvOpenWin({ videoUrl: res.data.filePath }); + type == 'gif' + ? window.electronAPI.sendEgOpenWin({ videoUrl: res.data.filePath }) + : window.electronAPI.sendVvOpenWin({ videoUrl: res.data.filePath }); } else { Modal.confirm({ title: '录屏已保存,是否查看?', @@ -220,7 +224,9 @@ const ScreenRecorder = (props) => { okText: t('modal.ok'), cancelText: t('modal.cancel'), onOk() { - window.open(`/viewVideo.html?videoUrl=${res.data.filePath}`); + window.open( + `/${type == 'gif' ? 'editGif' : 'viewVideo'}.html?videoUrl=${res.data.filePath}`, + ); }, }); } diff --git a/packages/web/src/components/records/RecordsContent.tsx b/packages/web/src/components/records/RecordsContent.tsx index 27074194..9a6939d6 100644 --- a/packages/web/src/components/records/RecordsContent.tsx +++ b/packages/web/src/components/records/RecordsContent.tsx @@ -126,8 +126,7 @@ const RecordAudioCard = forwardRef(() => { } function getAvatar(record: any) { - console.log(record.fileType); - if (record.fileType == 'ss' || record.fileType == 'gif') { + if (record.fileType == 'ss' || record.fileType == 'eg') { return ; } if (record.fileType == 'rs') { diff --git a/packages/web/src/pages/videoToGif.html b/packages/web/src/pages/editGif.html similarity index 82% rename from packages/web/src/pages/videoToGif.html rename to packages/web/src/pages/editGif.html index 655ac5bf..08f5307c 100644 --- a/packages/web/src/pages/videoToGif.html +++ b/packages/web/src/pages/editGif.html @@ -10,7 +10,7 @@
- + \ No newline at end of file diff --git a/packages/web/src/pages/videoToGif/index.module.scss b/packages/web/src/pages/editGif/index.module.scss similarity index 91% rename from packages/web/src/pages/videoToGif/index.module.scss rename to packages/web/src/pages/editGif/index.module.scss index d727c0f6..ecb4b16d 100644 --- a/packages/web/src/pages/videoToGif/index.module.scss +++ b/packages/web/src/pages/editGif/index.module.scss @@ -7,6 +7,7 @@ } .tool { text-align: center; + margin-top: 10px; .playBtn { margin-right: 10px; } diff --git a/packages/web/src/pages/videoToGif/index.tsx b/packages/web/src/pages/editGif/index.tsx similarity index 90% rename from packages/web/src/pages/videoToGif/index.tsx rename to packages/web/src/pages/editGif/index.tsx index 4c57063c..7cd370f9 100644 --- a/packages/web/src/pages/videoToGif/index.tsx +++ b/packages/web/src/pages/editGif/index.tsx @@ -3,10 +3,10 @@ import { useTranslation } from 'react-i18next'; import ininitApp from '../../pages/main'; import { useUserApi } from '../../api/user'; import { Local } from '../../util/storage'; -import VideoToGifConverter from '../../components/videoToGif/VideoToGifConverter'; +import VideoToGifConverter from '../../components/editGif/VideoToGifConverter'; import styles from './index.module.scss'; -const VideoToGif = () => { +const EditGif = () => { const userApi = useUserApi(); const { t } = useTranslation(); const [user, setUser] = useState(Local.get('user') || ({} as any)); @@ -51,6 +51,6 @@ const VideoToGif = () => { ); }; -ininitApp(VideoToGif); +ininitApp(EditGif); -export default VideoToGif; +export default EditGif; diff --git a/packages/web/vite.config.ts b/packages/web/vite.config.ts index 3d430dc3..420fee70 100644 --- a/packages/web/vite.config.ts +++ b/packages/web/vite.config.ts @@ -21,7 +21,7 @@ const buildOptionsProject = { editImage: resolve(__dirname, 'src/pages/editImage.html'), viewAudio: resolve(__dirname, 'src/pages/viewAudio.html'), records: resolve(__dirname, 'src/pages/records.html'), - videoToGif: resolve(__dirname, 'src/pages/videoToGif.html'), + editGif: resolve(__dirname, 'src/pages/editGif.html'), }, }, outDir: resolve(__dirname, 'dist'),