From 9c12de459386a3309e106e4ec6d85b688411a92f Mon Sep 17 00:00:00 2001 From: gahusb Date: Sat, 9 May 2026 13:30:31 +0900 Subject: [PATCH] =?UTF-8?q?feat(web-ui):=20CompileTab=20'=EC=98=81?= =?UTF-8?q?=EC=83=81=20=EB=A7=8C=EB=93=A4=EA=B8=B0'=20=EB=B2=84=ED=8A=BC?= =?UTF-8?q?=20+=20createPipeline=20payload=20=EC=8B=9C=EA=B7=B8=EB=8B=88?= =?UTF-8?q?=EC=B2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api.js | 6 +++++- src/pages/music/MusicStudio.css | 13 +++++++++++++ src/pages/music/components/CompileTab.jsx | 22 +++++++++++++++++++++- src/pages/music/components/YoutubeTab.jsx | 7 ++++++- 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/api.js b/src/api.js index a3de257..d0a2645 100644 --- a/src/api.js +++ b/src/api.js @@ -656,7 +656,11 @@ export const exportCompileJob = (id) => apiGet(`/api/music/compile/${id}/expo // --- Music Pipeline --- export const listPipelines = (status='all') => apiGet(`/api/music/pipeline?status=${status}`); export const getPipeline = (id) => apiGet(`/api/music/pipeline/${id}`); -export const createPipeline = (track_id) => apiPost('/api/music/pipeline', { track_id }); +export const createPipeline = (payload) => { + // 옛 호출 호환: createPipeline(13) → { track_id: 13 } + if (typeof payload === 'number') payload = { track_id: payload }; + return apiPost('/api/music/pipeline', payload); +}; export const startPipeline = (id) => apiPost(`/api/music/pipeline/${id}/start`); export const cancelPipeline = (id) => apiPost(`/api/music/pipeline/${id}/cancel`); export const publishPipeline = (id) => apiPost(`/api/music/pipeline/${id}/publish`); diff --git a/src/pages/music/MusicStudio.css b/src/pages/music/MusicStudio.css index b709d2c..eae6235 100644 --- a/src/pages/music/MusicStudio.css +++ b/src/pages/music/MusicStudio.css @@ -3317,3 +3317,16 @@ .modal-actions button { padding:6px 14px; background:rgba(255,255,255,.05); color:var(--ms-text, #f0f0f5); border:1px solid var(--ms-line, #2a2a3a); border-radius:8px; cursor:pointer; font-size:13px; } .modal-actions .button.primary { background:rgba(56,189,248,.2); color:#bae6fd; border-color:rgba(56,189,248,.4); } + +/* ── CompileTab → Pipeline 영상 만들기 버튼 ─────────────────────── */ +.cmp-btn-video { + padding: 6px 12px; + background: rgba(56, 189, 248, 0.15); + color: #bae6fd; + border: 1px solid rgba(56, 189, 248, 0.4); + border-radius: 6px; + cursor: pointer; + font-size: 12px; + margin-left: 6px; +} +.cmp-btn-video:hover { background: rgba(56, 189, 248, 0.25); } diff --git a/src/pages/music/components/CompileTab.jsx b/src/pages/music/components/CompileTab.jsx index d709d12..3e54d3c 100644 --- a/src/pages/music/components/CompileTab.jsx +++ b/src/pages/music/components/CompileTab.jsx @@ -1,6 +1,7 @@ import { useState, useEffect, useRef, useCallback } from 'react'; import { createCompileJob, getCompileJobs, deleteCompileJob, exportCompileJob, + createPipeline, startPipeline, } from '../../../api'; const fmtDuration = (sec) => { @@ -10,7 +11,7 @@ const fmtDuration = (sec) => { return `${m}분 ${s}초`; }; -export default function CompileTab({ library }) { +export default function CompileTab({ library, onSwitchToPipeline }) { const [jobs, setJobs] = useState([]); const [selected, setSelected] = useState([]); // [{id, title, audio_url}] in order const [crossfade, setCrossfade] = useState(3); @@ -89,6 +90,19 @@ export default function CompileTab({ library }) { if (exportData && exportData.id === jobId) setExportData(null); }; + const handleVideoFromCompile = async (jobId) => { + if (!window.confirm('이 mix로 영상 파이프라인을 시작할까요?')) return; + try { + const p = await createPipeline({ compile_job_id: jobId }); + await startPipeline(p.id); + if (onSwitchToPipeline) { + onSwitchToPipeline(p.id); + } + } catch (e) { + alert(`파이프라인 시작 실패: ${e.message || e}`); + } + }; + const totalMin = selected.length > 0 ? Math.round(selected.reduce((acc, t) => { const match = library.find(l => l.id === t.id); @@ -215,6 +229,12 @@ export default function CompileTab({ library }) { > {exportingId === j.id ? '...' : '↓ 내보내기'} + )} {j.status === 'failed' && ( diff --git a/src/pages/music/components/YoutubeTab.jsx b/src/pages/music/components/YoutubeTab.jsx index 9aa8f46..44d5d61 100644 --- a/src/pages/music/components/YoutubeTab.jsx +++ b/src/pages/music/components/YoutubeTab.jsx @@ -49,7 +49,12 @@ export default function YoutubeTab({ library, initialTrackId, onClearInitialTrac onClearInitialTrack={onClearInitialTrack} /> )} - {subtab === 'compile' && } + {subtab === 'compile' && ( + setSubtab('pipeline')} + /> + )} {subtab === 'trends' && } {subtab === 'revenue' && } {subtab === 'setup' && }