diff --git a/packages/cli/src/studio-server.ts b/packages/cli/src/studio-server.ts index 1ba43ae..cb22e72 100644 --- a/packages/cli/src/studio-server.ts +++ b/packages/cli/src/studio-server.ts @@ -1388,7 +1388,7 @@ export async function startStudioServer(ctx: CliContext, port: number): Promise< return res.end('missing ?path'); } const safe = resolve(p); - if (!safe.includes('/.html-video/projects/')) { + if (!safe.replace(/\\/g, '/').includes('/.html-video/projects/')) { res.writeHead(403); return res.end('forbidden'); } diff --git a/packages/project-studio/public/app.js b/packages/project-studio/public/app.js index 4f43bcf..89115b5 100644 --- a/packages/project-studio/public/app.js +++ b/packages/project-studio/public/app.js @@ -801,6 +801,7 @@ function renderMain() { +
@@ -842,13 +843,13 @@ function renderMain() { +
-
@@ -925,7 +926,8 @@ function wireSoundtrackPanel() { const clearBtn = document.getElementById('btn-st-clear'); const musicStatusEl = document.getElementById('st-music-status'); const narrationStatusEl = document.getElementById('st-narration-status'); - const previewEl = document.getElementById('st-preview'); + const musicPreviewEl = document.getElementById('st-music-preview'); + const narrationPreviewEl = document.getElementById('st-narration-preview'); const draftFrameBtn = document.getElementById('btn-st-draft-frame'); const draftAllBtn = document.getElementById('btn-st-draft-all'); const whichEl = document.getElementById('st-narration-which'); @@ -1079,7 +1081,8 @@ function wireSoundtrackPanel() { await fetch(`/api/projects/${state.selected.id}/soundtrack`, { method: 'DELETE' }); musicPrompt.value = ''; narrationText.value = ''; - previewEl.innerHTML = ''; + if (musicPreviewEl) musicPreviewEl.innerHTML = ''; + if (narrationPreviewEl) narrationPreviewEl.innerHTML = ''; if (musicStatusEl) musicStatusEl.textContent = ''; if (narrationStatusEl) narrationStatusEl.textContent = ''; if (state.selected) delete state.selected.soundtrack; @@ -1165,19 +1168,34 @@ function wireSoundtrackPanel() { } function renderSoundtrackPreview(soundtrack) { - const previewEl = document.getElementById('st-preview'); - if (!previewEl || !soundtrack || !state.selected) return; + if (!soundtrack || !state.selected) return; const assets = state.selected.assets || []; const srcFor = (id) => { const a = assets.find((x) => x.id === id); return a?.path ? `/asset?path=${encodeURIComponent(a.path)}` : null; }; - const blocks = []; + const musicPreviewEl = document.getElementById('st-music-preview'); + const narrationPreviewEl = document.getElementById('st-narration-preview'); + const legacyPreviewEl = document.getElementById('st-preview'); const musicSrc = soundtrack.musicAssetId && srcFor(soundtrack.musicAssetId); const narrSrc = soundtrack.narrationAssetId && srcFor(soundtrack.narrationAssetId); - if (musicSrc) blocks.push(`
${t('soundtrack.music_ready')}
`); - if (narrSrc) blocks.push(`
${t('soundtrack.narration_ready')}
`); - previewEl.innerHTML = blocks.join(''); + if (musicPreviewEl) { + musicPreviewEl.innerHTML = musicSrc + ? `
${t('soundtrack.music_ready')}
` + : ''; + } + if (narrationPreviewEl) { + narrationPreviewEl.innerHTML = narrSrc + ? `
${t('soundtrack.narration_ready')}
` + : ''; + } + // Compatibility: if the old single preview container still exists, render both. + if (legacyPreviewEl) { + const blocks = []; + if (musicSrc) blocks.push(`
${t('soundtrack.music_ready')}
`); + if (narrSrc) blocks.push(`
${t('soundtrack.narration_ready')}
`); + legacyPreviewEl.innerHTML = blocks.join(''); + } } // ============== composer attachments ==============