Skip to content

Commit

Permalink
Merge pull request #7 from baizeteam/dev
Browse files Browse the repository at this point in the history
完成压缩功能模块的开发(视频)
  • Loading branch information
sulgweb authored Apr 20, 2024
2 parents 3b81e93 + 9a2446e commit 6adeceb
Show file tree
Hide file tree
Showing 15 changed files with 442 additions and 41 deletions.
6 changes: 6 additions & 0 deletions electron-builder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ files:
- "!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}"
- "!resources/win/*"
- "!resources/mac/*"
- "!resources/linux/*"
asarUnpack:
- resources/**
win:
Expand Down Expand Up @@ -51,6 +52,11 @@ linux:
- AppImage
- snap
- deb
files:
- from: "resources/linux"
to: "resources/linux"
filter:
- "**/*"
maintainer: electronjs.org
category: Utility
appImage:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "baize-toolbox",
"version": "1.0.0",
"version": "0.0.1",
"description": "An Electron application with React and TypeScript",
"main": "./out/main/index.js",
"author": "[email protected]",
Expand Down
52 changes: 30 additions & 22 deletions src/main/plugin/modules/ffmpeg.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { execFile, spawn } from "child_process";
import { app, ipcMain, BrowserWindow, dialog } from "electron";
import path, { resolve } from "path";
import { checkFolderExists } from "../../utils/fileHelper";
import { checkFolderExists, getFileSize } from "../../utils/fileHelper";
import { queueStoreAdd, queueStoreUpdate } from "../../utils/storeHelper";
import { mainWinStartProxy, START_STATUS } from "../../helper";
// import { mainLogSend } from "../../helper";
Expand Down Expand Up @@ -45,7 +45,6 @@ app.on("ready", () => {
ipcMain.on("FFMPEG_COMMAND", async (e, params) => {
console.log("FFMPEG_COMMAND", params);
const videoInfo = await getVideoInfo(params.inputFilePath);
console.log("videoInfo", videoInfo);
const videoDuration = videoInfo.duration;
checkFolderExists(params.outputFloaderPath);
const outputFilePath = path.join(
Expand Down Expand Up @@ -93,7 +92,9 @@ app.on("ready", () => {
});
} else {
console.log("FFmpeg 进程正常关闭");
const outputFileSize = getFileSize(outputFilePath);
sendFunc({
outputFileSize,
progress: 100,
});
}
Expand All @@ -119,7 +120,6 @@ app.on("ready", () => {
const getVideoInfo = async (filePath): Promise<VideoInfo> => {
return new Promise((resolve, reject) => {
const command = ["-i", filePath, "-f", null, "-"];
console.log(command);
const ffmpegProcess = spawn(ffmpegPath, command);
let output = "";

Expand All @@ -142,33 +142,41 @@ app.on("ready", () => {
function parseVideoInfo(info) {
const lines = info.split("\n");
const videoInfo: VideoInfo = {};
// console.log(lines);
lines.forEach((line) => {
if (line.indexOf("Video") !== -1) {
console.log(line);

const bitrateMatch = line.match(/(\d+\.?\d*) kb/);
const codecMatch = line.match(/Stream.*Video: ([^,]+)/);
const resolutionMatch = line.match(/(\d{2,4})x(\d{2,4})/);
const frameRateMatch = line.match(/(\d+\.?\d*) fps/);

if (bitrateMatch && !videoInfo.bitrate) {
console;
videoInfo.bitrate = parseInt(bitrateMatch[1]);
}
if (codecMatch) {
videoInfo.codec = codecMatch[1].trim();
}
if (resolutionMatch) {
videoInfo.resolution = {
width: parseInt(resolutionMatch[1]),
height: parseInt(resolutionMatch[2]),
};
}
if (frameRateMatch && !videoInfo.frameRate) {
videoInfo.frameRate = parseFloat(frameRateMatch[1]);
}
}
const durationMatch = line.match(/Duration: (\d{2}):(\d{2}):(\d{2})/);
const bitrateMatch = line.match(/bitrate: (\d+) kb\/s/);
const codecMatch = line.match(/Stream.*Video: ([^,]+)/);
const resolutionMatch = line.match(/(\d{2,4})x(\d{2,4})/);
const frameRateMatch = line.match(/(\d+\.?\d*) fps/);
if (durationMatch) {
videoInfo.duration = convertTimeToSeconds(
`${durationMatch[1]}:${durationMatch[2]}:${durationMatch[3]}`,
);
}
if (bitrateMatch) {
videoInfo.bitrate = parseInt(bitrateMatch[1]);
}
if (codecMatch) {
videoInfo.codec = codecMatch[1].trim();
}
if (resolutionMatch) {
videoInfo.resolution = {
width: parseInt(resolutionMatch[1]),
height: parseInt(resolutionMatch[2]),
};
}
if (frameRateMatch) {
videoInfo.frameRate = parseFloat(frameRateMatch[1]);
}
});

return videoInfo;
}

Expand Down
7 changes: 6 additions & 1 deletion src/main/plugin/modules/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import { queueStoreDelete } from "../../utils/storeHelper";
import { electronReload, electronRestart } from "../../utils/reload";

export const store = new ElectronStore();
const configIgnoreKeys = ["ttsList", "transcodeList", "extractList"];
const configIgnoreKeys = [
"ttsList",
"transcodeList",
"extractList",
"compressList",
];

// 设置 store
ipcMain.handle("SET_STORE", (_, key, value) => {
Expand Down
6 changes: 6 additions & 0 deletions src/main/utils/fileHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,9 @@ export const deleteFile = (filePath: string) => {
});
});
};

// 获取文件大小
export function getFileSize(filePath) {
const stats = fs.statSync(filePath);
return stats.size;
}
14 changes: 14 additions & 0 deletions src/renderer/i18n/modules/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
"file": "File",
"folder": "Folder",
"fps": "FPS",
"bitrate": "Bitrate",
"duration": "Duration",
"resolution": "Resolution",
"action": "Action",
"progress": "Progress",
"loading": "Loading...",
Expand Down Expand Up @@ -114,6 +117,17 @@
"createType": "Create Type",
"tableTitle": "Screen Record History",
"createBtn": "Start Recording"
},
"compress": {
"tableTitle": "Compress History",
"originFileSize": "Origin Size",
"compressFileSize": "Compress Size",
"compressRate": "Compress Rate",
"typeModal": {
"title": "Please select compression settings",
"infoTitle": "File Info",
"compressSetting": "Compression Setting"
}
}
},
"components": {
Expand Down
14 changes: 14 additions & 0 deletions src/renderer/i18n/modules/zh_CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
"file": "文件",
"folder": "文件夹",
"fps": "帧率",
"bitrate": "比特率",
"duration": "时长",
"resolution": "分辨率",
"action": "操作",
"progress": "进度",
"loading": "加载中...",
Expand Down Expand Up @@ -114,6 +117,17 @@
"createType": "录屏类型",
"tableTitle": "录屏记录",
"createBtn": "开始录屏"
},
"compress": {
"tableTitle": "压缩记录",
"originFileSize": "原文件大小",
"compressFileSize": "压缩后大小",
"compressRate": "压缩率",
"typeModal": {
"title": "请选择压缩设置",
"infoTitle": "文件信息",
"compressSetting": "压缩参数设置"
}
}
}
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.video-info {
.info {
}
.setting {
}

.title {
font-size: 16px;
font-weight: bold;
}
.content {
padding: 12px;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import React, { useState, useEffect, useRef } from "react";
import { Modal, ModalProps, Radio, Select, Slider } from "antd";
import "./index.module.less";
import { useTranslation } from "react-i18next";
import { fileSelectAccetps, fpsList } from "@renderer/utils/fileHelper";
import AppLoading from "@renderer/components/AppLoading";

interface ITypeModalProps extends Omit<ModalProps, "onOk"> {
filePath: string;
onOk: (value: string) => void;
}

export default function TypeModal(props: ITypeModalProps) {
const { filePath, onOk, open } = props;
const [loading, setLoading] = useState<boolean>(false);
const [fileInfo, setFileInfo] = useState<any>();
const [settingInfo, setSettingInfo] = useState<any>();

const settingInfoRef = useRef(settingInfo);

const { t } = useTranslation();

useEffect(() => {
init();
}, [open]);

// 初始化,获取视频信息
const init = async () => {
if (filePath && open) {
setLoading(true);
const res = await window.electron.ipcRenderer.invoke(
"FFMPEG_GET_VIDEO_INFO",
{ filePath },
);
console.log(res);
setFileInfo(res);
changeSettingInfo({ frameRate: res.frameRate, bitrate: res.bitrate });
setLoading(false);
}
};

// 改变设置信息
const changeSettingInfo = (obj) => {
const params = { ...settingInfoRef.current, ...obj };
settingInfoRef.current = params;
setSettingInfo(params);
};

// 确定
const _handleOk = () => {
onOk(settingInfo);
};

const fpsOptions = fpsList.map((item) => {
return {
label: item + "fps",
value: item,
disabled: item > fileInfo?.frameRate,
};
});

return (
<Modal
title={t("siteMain.pages.compress.typeModal.title")}
{...props}
onOk={_handleOk}
okButtonProps={{ disabled: loading || !settingInfo }}
>
<div>
{loading ? (
<AppLoading />
) : (
<>
{fileSelectAccetps?.video.includes(filePath?.split(".").pop()) && (
<div styleName="video-info">
<div styleName="info">
<div styleName="title">
{t("siteMain.pages.compress.typeModal.infoTitle")}
</div>
<div styleName="content">
<div>
{t("commonText.bitrate")}:{fileInfo?.bitrate}
</div>
<div>
{t("commonText.duration")}:{fileInfo?.duration}
</div>
<div>
{t("commonText.fps")}:{fileInfo?.frameRate}
</div>
<div>
{t("commonText.resolution")}:{fileInfo?.resolution?.width}
x{fileInfo?.resolution?.height}
</div>
</div>
</div>

<div styleName="setting">
<div styleName="title">
{t("siteMain.pages.compress.typeModal.compressSetting")}
</div>
<div styleName="content">
<div>
{t("commonText.fps")}:
<Select
options={fpsOptions}
defaultValue={fileInfo?.frameRate}
onChange={(e) => {
changeSettingInfo({ frameRate: e });
}}
size="small"
/>
</div>
<div>
{t("commonText.bitrate")}:
<div style={{ padding: "0 16px" }}>
<Slider
defaultValue={fileInfo?.bitrate}
marks={{
128: "128kbps",
256: "256kbps",
512: "512kbps",
1024: "1Mbps",
2048: "2Mbps",
4096: "4Mbps",
}}
max={fileInfo?.bitrate}
min={128}
onChange={(e) => {
changeSettingInfo({ bitrate: e });
}}
/>
</div>
</div>
</div>
</div>
</div>
)}
</>
)}
</div>
</Modal>
);
}
10 changes: 10 additions & 0 deletions src/renderer/siteMain/src/pages/Compress/index.module.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.compress {
.action {
display: flex;
justify-content: space-between;
align-items: center;
}
.table {
margin-top: 16px;
}
}
Loading

0 comments on commit 6adeceb

Please sign in to comment.