diff --git a/src/servers/api/file-browser/router.ts b/src/servers/api/file-browser/router.ts index 1ffd6f03..f97af2a2 100644 --- a/src/servers/api/file-browser/router.ts +++ b/src/servers/api/file-browser/router.ts @@ -849,14 +849,14 @@ router.post('/extract-audio', async (ctx) => { const s = await stat(absPath); if (s.isDirectory()) throw errors.BAD_REQUEST('Cannot extract audio from a directory'); + // No caching: the extraction is always redone and overwrites the previous result. The output still + // lives under the user's data dir because this endpoint backs the file viewer's Extract Audio + // button, which plays it rather than saving it beside the video — the Extract Audio task is what + // writes into the user's folders. const userDataDir = getUserDataDir(user.email); const { dir, name } = parsePath(filePath.replace(/^\/+/, '')); - const cacheRel = dir ? `cache/audio/${dir}/${name}.mp3` : `cache/audio/${name}.mp3`; - const cacheAbs = resolve(userDataDir, cacheRel); - - if (existsSync(cacheAbs)) { - return ctx.json({ audioPath: cacheRel, audioRoot: 'user-data', cached: true }); - } + const outRel = dir ? `cache/audio/${dir}/${name}.mp3` : `cache/audio/${name}.mp3`; + const cacheAbs = resolve(userDataDir, outRel); await mkdir(dirname(cacheAbs), { recursive: true }); @@ -871,7 +871,7 @@ router.post('/extract-audio', async (ctx) => { throw errors.BAD_REQUEST(stderr.trim() || 'Audio extraction failed'); } - return ctx.json({ audioPath: cacheRel, audioRoot: 'user-data', cached: false }); + return ctx.json({ audioPath: outRel, audioRoot: 'user-data', cached: false }); }); // Extract archive (zip, tar, 7z, rar) into a sibling folder diff --git a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/FileGrid.tsx b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/FileGrid.tsx index cf1855aa..6d95ca2d 100644 --- a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/FileGrid.tsx +++ b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/FileGrid.tsx @@ -62,7 +62,6 @@ export const FileGrid = ({ fileBrowserManager }: FileGridProps) => { setRenamingName, handleReadAloud, handleOcr, - handleExtractAudio, handleExtract, handlePlay, getMatchingTaskGroups, @@ -180,7 +179,6 @@ export const FileGrid = ({ fileBrowserManager }: FileGridProps) => { onRenamingChange={setRenamingName} onReadAloud={handleReadAloud} onOcr={handleOcr} - onExtractAudio={handleExtractAudio} onExtract={handleExtract} onPlay={handlePlay} taskGroups={getMatchingTaskGroups(entry.name, entry.type)} diff --git a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/FileItem.tsx b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/FileItem.tsx index e1bcfdc5..96ac5892 100644 --- a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/FileItem.tsx +++ b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/FileItem.tsx @@ -13,7 +13,6 @@ import { LayoutGrid, Volume2, ScanText, - AudioLines, FolderArchive, ClipboardCopy, Music, @@ -64,7 +63,6 @@ export type FileItemProps = { onRenamingChange: (name: string | null) => void; onReadAloud: (entry: DirEntry) => void; onOcr: (entry: DirEntry) => void; - onExtractAudio: (entry: DirEntry) => void; onExtract: (entry: DirEntry) => void; onPlay: (entry: DirEntry) => void; taskGroups: TaskGroup[]; @@ -96,7 +94,6 @@ type MenuItemsProps = { onDownload: (e: DirEntry) => void; onReadAloud: (e: DirEntry) => void; onOcr: (e: DirEntry) => void; - onExtractAudio: (e: DirEntry) => void; onExtract: (e: DirEntry) => void; onPlay: (e: DirEntry) => void; onCut: () => void; @@ -116,7 +113,6 @@ const DropdownMenuItems = ({ onDownload, onReadAloud, onOcr, - onExtractAudio, onExtract, onPlay, onCut, @@ -128,12 +124,11 @@ const DropdownMenuItems = ({ const fileType = entry.type === 'file' ? getFileType(entry.name) : null; const showReadAloud = fileType === 'markdown' || fileType === 'code' || fileType === 'text'; const showOcr = fileType === 'image'; - const showExtractAudio = fileType === 'video'; const showExtract = fileType === 'archive'; const showPlay = fileType === 'audio' || entry.type === 'directory'; const hasTasks = taskGroups.length > 0; - const hasActions = showPlay || showReadAloud || showOcr || showExtractAudio || showExtract || hasTasks; + const hasActions = showPlay || showReadAloud || showOcr || showExtract || hasTasks; // Only nest when more than one category matched — a file usually matches a single category, and // Run Task > Video > Convert would just add a hop. const nestTasks = taskGroups.length > 1; @@ -159,12 +154,6 @@ const DropdownMenuItems = ({ Extract Text (OCR) )} - {showExtractAudio && ( - onExtractAudio(entry)} className="cursor-pointer"> - - Extract Audio - - )} {showExtract && ( onExtract(entry)} className="cursor-pointer"> @@ -260,7 +249,6 @@ const ContextMenuItems = ({ onDownload, onReadAloud, onOcr, - onExtractAudio, onExtract, onPlay, onCut, @@ -272,12 +260,11 @@ const ContextMenuItems = ({ const fileType = entry.type === 'file' ? getFileType(entry.name) : null; const showReadAloud = fileType === 'markdown' || fileType === 'code' || fileType === 'text'; const showOcr = fileType === 'image'; - const showExtractAudio = fileType === 'video'; const showExtract = fileType === 'archive'; const showPlay = fileType === 'audio' || entry.type === 'directory'; const hasTasks = taskGroups.length > 0; - const hasActions = showPlay || showReadAloud || showOcr || showExtractAudio || showExtract || hasTasks; + const hasActions = showPlay || showReadAloud || showOcr || showExtract || hasTasks; // Only nest when more than one category matched — a file usually matches a single category, and // Run Task > Video > Convert would just add a hop. const nestTasks = taskGroups.length > 1; @@ -303,12 +290,6 @@ const ContextMenuItems = ({ Extract Text (OCR) )} - {showExtractAudio && ( - onExtractAudio(entry)} className="cursor-pointer"> - - Extract Audio - - )} {showExtract && ( onExtract(entry)} className="cursor-pointer"> @@ -513,7 +494,6 @@ export const FileItem = ({ onRenamingChange, onReadAloud, onOcr, - onExtractAudio, onExtract, onPlay, taskGroups, @@ -595,7 +575,6 @@ export const FileItem = ({ onDownload, onReadAloud, onOcr, - onExtractAudio, onExtract, onPlay, onCut, diff --git a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/useFileBrowserApp.ts b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/useFileBrowserApp.ts index 9203de99..dc9f17b5 100644 --- a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/useFileBrowserApp.ts +++ b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/useFileBrowserApp.ts @@ -457,18 +457,6 @@ export const useFileBrowserApp = ( } }; - const handleExtractAudio = async (entry: DirEntry) => { - const filePath = entryPath(entry.name); - const toastId = toast.loading('Extracting audio from video...'); - try { - const { audioPath, audioRoot } = await files.extractAudio(filePath); - toast.dismiss(toastId); - setSearchParams({ view: filePath, ephemeral: audioPath, ephemeralRoot: audioRoot }); - } catch { - toast.error('Failed to extract audio from video', { id: toastId }); - } - }; - const handlePlay = (entry: DirEntry) => { const filePath = entryPath(entry.name); setSearchParams({ play: filePath }); @@ -765,7 +753,6 @@ export const useFileBrowserApp = ( handleCreateDashboardHere, handleReadAloud, handleOcr, - handleExtractAudio, handleExtract, handlePlay, handleGitClone,