Files
ffmpeg-gui/frontend/src/App.vue
T

157 lines
4.3 KiB
Vue
Raw Normal View History

2026-07-29 02:17:57 +08:00
<template>
<div class="app" :data-theme="theme">
<Header
:currentView="currentView"
:theme="theme"
@navigate="navigate"
@toggleTheme="toggleTheme"
/>
<div class="main-area">
<Sidebar :currentView="currentView" @navigate="navigate" />
<div class="workspace-column">
<main class="workspace">
2026-07-29 10:46:19 +08:00
<EncodePage v-if="currentView === 'encode'" :gpuInfo="gpuInfo" @taskAdded="onTaskAdded" />
<RemuxPage v-if="currentView === 'remux'" :gpuInfo="gpuInfo" @taskAdded="onTaskAdded" />
<BurnPage v-if="currentView === 'burn'" :gpuInfo="gpuInfo" @taskAdded="onTaskAdded" />
2026-07-29 02:17:57 +08:00
<SettingsPage v-if="currentView === 'settings'" />
<LogPage v-show="currentView === 'logs'" ref="logPageRef" />
</main>
<TaskDrawer :tasks="tasks" @cancel="handleCancel" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import Header from './components/Header.vue'
import Sidebar from './components/Sidebar.vue'
import TaskDrawer from './components/TaskDrawer.vue'
import EncodePage from './views/EncodePage.vue'
import RemuxPage from './views/RemuxPage.vue'
import BurnPage from './views/BurnPage.vue'
import SettingsPage from './views/SettingsPage.vue'
import LogPage from './views/LogPage.vue'
import { api, onTaskUpdated, onTaskProgress, onTaskLog } from './api/wails'
import type { Task, Progress } from './types'
const currentView = ref('encode')
const theme = ref<'dark'|'light'>('light')
const tasks = ref<Task[]>([])
2026-07-29 10:46:19 +08:00
const gpuInfo = ref<any[]>([])
2026-07-29 02:17:57 +08:00
const logPageRef = ref<InstanceType<typeof LogPage> | null>(null)
onMounted(() => {
2026-07-29 10:46:19 +08:00
document.addEventListener('contextmenu', e => e.preventDefault())
2026-07-29 02:17:57 +08:00
document.documentElement.setAttribute('data-theme', theme.value)
loadTasks()
2026-07-29 10:46:19 +08:00
loadGPUInfo()
2026-07-29 02:17:57 +08:00
onTaskUpdated((task: Task) => {
const found = tasks.value.find(t => t.id === task.id)
if (found) {
Object.assign(found, task)
} else {
tasks.value.push(task)
}
logPageRef.value?.upsertTask({
id: task.id,
inputFile: task.inputFile,
type: task.type,
status: task.status,
args: task.args,
logs: task.logs,
})
})
onTaskProgress((data: { taskId: string; progress: Progress }) => {
const found = tasks.value.find(t => t.id === data.taskId)
if (found) {
Object.assign(found.progress, data.progress)
}
})
onTaskLog((data: { taskId: string; line: string }) => {
logPageRef.value?.appendLog(data.taskId, data.line)
})
})
function navigate(view: string) {
currentView.value = view
}
function toggleTheme() {
theme.value = theme.value === 'dark' ? 'light' : 'dark'
document.documentElement.setAttribute('data-theme', theme.value)
}
async function loadTasks() {
try { tasks.value = await api.getTasks() } catch { /* not connected */ }
}
2026-07-29 10:46:19 +08:00
async function loadGPUInfo() {
try {
const app = (window as any).go?.main?.App
if (app?.GetGPUInfo) {
gpuInfo.value = await app.GetGPUInfo() || []
} else {
const encs = await api.getHardwareEncoders()
gpuInfo.value = groupByVendor(encs)
}
} catch {
try {
const encs = await api.getHardwareEncoders()
gpuInfo.value = groupByVendor(encs)
} catch { gpuInfo.value = [] }
}
}
function groupByVendor(encs: any[]): any[] {
const groups: Record<string, any> = {}
for (const e of encs) {
if (!groups[e.type]) {
groups[e.type] = { name: e.type, vendor: e.type, encoders: [] }
}
groups[e.type].encoders.push({ name: e.name, codec: e.codec, label: e.label, available: e.available })
}
return [...Object.values(groups), { name: 'CPU', vendor: 'cpu', encoders: [{ name:'libx264',codec:'h264',label:'H.264',available:true },{ name:'libx265',codec:'hevc',label:'HEVC',available:true }]}]
}
2026-07-29 02:17:57 +08:00
function onTaskAdded() { loadTasks() }
async function handleCancel(id: string) {
try { await api.cancelTask(id); await loadTasks() } catch {}
}
</script>
<style scoped>
.app {
height: 100vh;
display: flex;
flex-direction: column;
}
.main-area {
flex: 1;
display: flex;
overflow: hidden;
}
.workspace-column {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
.workspace {
flex: 1;
overflow-y: auto;
padding: 28px 36px;
}
</style>