Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@radix-ui/react-tabs": "^1.1.4",
"@radix-ui/react-tooltip": "^1.0.7",
"@volcengine/openapi": "^1.18.3",
"ahooks": "^3.8.4",
"axios": "^1.6.8",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
Expand Down
95 changes: 71 additions & 24 deletions renderer/components/TaskControls.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
import { useEffect, useState } from 'react';
import {
useEffect,
useState,
type Dispatch,
type FC,
type SetStateAction,
} from 'react';
import { Button } from './ui/button';
import { toast } from 'sonner';
import { isSubtitleFile, needsCoreML } from 'lib/utils';
import { getNewTaskFiles, needsCoreML } from 'lib/utils';
import { useTranslation } from 'next-i18next';
import type { IFiles } from '../../types';
import { Switch } from './ui/switch';
import useLocalStorageState from 'hooks/useLocalStorageState';
import { useUpdateEffect } from 'ahooks';

const TaskControls = ({ files, formData }) => {
const [taskStatus, setTaskStatus] = useState('idle');
type TaskStatus = 'idle' | 'running' | 'paused' | 'cancelled' | 'completed';

const TaskControls: FC<{
files: IFiles[];
setFiles: Dispatch<SetStateAction<IFiles[]>>;
formData: any;
}> = ({ files, setFiles, formData }) => {
const [taskStatus, setTaskStatus] = useState<TaskStatus>('idle');
const { t } = useTranslation(['home', 'common']);
const [autoStartNewTaskWhenRunning, setAutoStartNewTaskWhenRunning] =
useLocalStorageState<boolean>('auto-start-new-task-when-running', false);

useEffect(() => {
// 获取当前任务状态
Expand All @@ -17,7 +35,7 @@ const TaskControls = ({ files, formData }) => {
getCurrentTaskStatus();

// 监听任务状态变化
const cleanup = window?.ipc?.on('taskComplete', (status: string) => {
const cleanup = window?.ipc?.on('taskComplete', (status: TaskStatus) => {
setTaskStatus(status);
});

Expand All @@ -28,30 +46,27 @@ const TaskControls = ({ files, formData }) => {

const handleTask = async () => {
if (!files?.length) {
toast(t('common:notification'), {
description: t('home:noTask'),
});
return;
return toast(t('common:notification'), { description: t('home:noTask') });
}
const isAllFilesProcessed = files.every((item) => {
const basicProcessingDone = item.extractAudio && item.extractSubtitle;

if (formData.translateProvider === '-1') {
return basicProcessingDone;
}
if (isSubtitleFile(item?.filePath)) {
return item.translateSubtitle;
}

return basicProcessingDone && item.translateSubtitle;
});
// when start task button pressed, persist taskType to IFiles
const needPersist = files.some((f) => !f.taskType);
let updatedFiles = files;
if (needPersist) {
updatedFiles = files.map((f) => {
if (f.taskType) return f;
return { ...f, taskType: formData.taskType };
});
setFiles(updatedFiles);
}

if (isAllFilesProcessed) {
toast(t('common:notification'), {
const newTaskFiles = getNewTaskFiles(updatedFiles);
if (!newTaskFiles.length) {
return toast(t('common:notification'), {
description: t('home:allFilesProcessed'),
});
return;
}

// if(formData.model && needsCoreML(formData.model)){
// const checkMlmodel = await window.ipc.invoke('checkMlmodel', formData.model);
// if(!checkMlmodel){
Expand All @@ -61,8 +76,15 @@ const TaskControls = ({ files, formData }) => {
// return;
// }
// }

setTaskStatus('running');
window?.ipc?.send('handleTask', { files, formData });
setFiles((files) =>
files.map((f) => {
if (f.sent) return f;
return { ...f, sent: true };
}),
);
window?.ipc?.send('handleTask', { files: newTaskFiles, formData });
};
const handlePause = () => {
window?.ipc?.send('pauseTask', null);
Expand All @@ -78,6 +100,18 @@ const TaskControls = ({ files, formData }) => {
window?.ipc?.send('cancelTask', null);
setTaskStatus('cancelled');
};

useUpdateEffect(() => {
if (
taskStatus === 'running' &&
autoStartNewTaskWhenRunning &&
files.length &&
files.some((f) => !f.sent)
) {
handleTask();
}
}, [files.length]);

return (
<div className="flex gap-2 ml-auto">
{(taskStatus === 'idle' || taskStatus === 'completed') && (
Expand All @@ -87,6 +121,19 @@ const TaskControls = ({ files, formData }) => {
)}
{taskStatus === 'running' && (
<>
<span className="inline-flex items-center justify-center gap-x-1 mr-1">
<Switch
id="auto-start-new-task-when-running"
checked={autoStartNewTaskWhenRunning}
onCheckedChange={setAutoStartNewTaskWhenRunning}
/>
<label
htmlFor="auto-start-new-task-when-running"
className="cursor-pointer select-none"
>
{t('home:autoStartNewTaskWhenRunning')}
</label>
</span>
<Button onClick={handlePause}>{t('home:pauseTask')}</Button>
<Button onClick={handleCancel}>{t('home:cancelTask')}</Button>
</>
Expand Down
8 changes: 5 additions & 3 deletions renderer/hooks/useIpcCommunication.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { useEffect } from 'react';
import { IFiles } from '../../types';
import { useEffect, type Dispatch, type SetStateAction } from 'react';
import type { IFiles } from '../../types';

export default function useIpcCommunication(setFiles) {
export default function useIpcCommunication(
setFiles: Dispatch<SetStateAction<IFiles[]>>,
) {
useEffect(() => {
window?.ipc?.on('file-selected', (res: IFiles[]) => {
setFiles((prevFiles) => [...prevFiles, ...res]);
Expand Down
58 changes: 58 additions & 0 deletions renderer/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { type ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
import type { IFiles } from '../../types';

export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
Expand Down Expand Up @@ -323,3 +324,60 @@ export const filterSupportedFiles = (files: File[]) => {
);
});
};

function fileStatusGetters(file: IFiles) {
const { taskType, extractAudio, extractSubtitle, translateSubtitle } = file;

function running(): boolean {
return !ended() && !!(extractAudio || extractSubtitle || translateSubtitle);
}

function ended(): boolean {
return succeed() || failed();
}

function succeed(): boolean {
if (taskType === 'generateOnly')
return extractAudio === 'done' && extractSubtitle === 'done';
if (taskType === 'translateOnly') return translateSubtitle === 'done';
if (taskType === 'generateAndTranslate')
return (
extractAudio === 'done' &&
extractSubtitle === 'done' &&
translateSubtitle === 'done'
);
}

function failed(): boolean {
return (
extractAudio === 'error' ||
extractSubtitle === 'error' ||
translateSubtitle === 'error'
);
}

return {
get running() {
return running();
},
get ended() {
return ended();
},
get succeed() {
return succeed();
},
get failed() {
return failed();
},
};
}

export function getNewTaskFiles(files: IFiles[]) {
return files.filter((file) => {
if (!file.sent) return true; // not sent yet
const { running, succeed } = fileStatusGetters(file);
if (running) return false;
if (succeed) return false;
return true; // rest are un-started | failed
});
}
5 changes: 3 additions & 2 deletions renderer/pages/[locale]/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ import TaskConfigForm from '@/components/TaskConfigForm';
import TaskListControl from '@/components/TaskListControl';
import { getStaticPaths, makeStaticProperties } from '../../lib/get-static';
import { filterSupportedFiles } from 'lib/utils';
import type { IFiles } from '../../../types';

export default function Component() {
const [files, setFiles] = useState([]);
const [files, setFiles] = useState<IFiles[]>([]);
const { systemInfo } = useSystemInfo();
const { form, formData } = useFormConfig();
useIpcCommunication(setFiles);
Expand Down Expand Up @@ -119,7 +120,7 @@ export default function Component() {
<TaskList files={files} formData={formData} />
</ScrollArea>
<div className="flex-1" />
<TaskControls formData={formData} files={files} />
<TaskControls formData={formData} files={files} setFiles={setFiles} />
</div>
{/* <Guide systemInfo={systemInfo} updateSystemInfo={updateSystemInfo} /> */}
</div>
Expand Down
3 changes: 2 additions & 1 deletion renderer/public/locales/en/home.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,5 +106,6 @@
"total": "Total",
"translated": "Translated",
"completionRate": "Completion rate",
"originalSubtitle": "Original subtitle"
"originalSubtitle": "Original subtitle",
"autoStartNewTaskWhenRunning": "Auto tart new tasks"
}
3 changes: 2 additions & 1 deletion renderer/public/locales/zh/home.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,5 +112,6 @@
"total": "总数",
"translated": "已翻译",
"completionRate": "完成率",
"originalSubtitle": "原文字幕"
"originalSubtitle": "原文字幕",
"autoStartNewTaskWhenRunning": "自动开始新任务"
}
Loading