feat(web-ui): CompileTab '영상 만들기' 버튼 + createPipeline payload 시그니처
This commit is contained in:
@@ -656,7 +656,11 @@ export const exportCompileJob = (id) => apiGet(`/api/music/compile/${id}/expo
|
|||||||
// --- Music Pipeline ---
|
// --- Music Pipeline ---
|
||||||
export const listPipelines = (status='all') => apiGet(`/api/music/pipeline?status=${status}`);
|
export const listPipelines = (status='all') => apiGet(`/api/music/pipeline?status=${status}`);
|
||||||
export const getPipeline = (id) => apiGet(`/api/music/pipeline/${id}`);
|
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 startPipeline = (id) => apiPost(`/api/music/pipeline/${id}/start`);
|
||||||
export const cancelPipeline = (id) => apiPost(`/api/music/pipeline/${id}/cancel`);
|
export const cancelPipeline = (id) => apiPost(`/api/music/pipeline/${id}/cancel`);
|
||||||
export const publishPipeline = (id) => apiPost(`/api/music/pipeline/${id}/publish`);
|
export const publishPipeline = (id) => apiPost(`/api/music/pipeline/${id}/publish`);
|
||||||
|
|||||||
@@ -3317,3 +3317,16 @@
|
|||||||
.modal-actions button { padding:6px 14px; background:rgba(255,255,255,.05); color:var(--ms-text, #f0f0f5);
|
.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; }
|
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); }
|
.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); }
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useState, useEffect, useRef, useCallback } from 'react';
|
import { useState, useEffect, useRef, useCallback } from 'react';
|
||||||
import {
|
import {
|
||||||
createCompileJob, getCompileJobs, deleteCompileJob, exportCompileJob,
|
createCompileJob, getCompileJobs, deleteCompileJob, exportCompileJob,
|
||||||
|
createPipeline, startPipeline,
|
||||||
} from '../../../api';
|
} from '../../../api';
|
||||||
|
|
||||||
const fmtDuration = (sec) => {
|
const fmtDuration = (sec) => {
|
||||||
@@ -10,7 +11,7 @@ const fmtDuration = (sec) => {
|
|||||||
return `${m}분 ${s}초`;
|
return `${m}분 ${s}초`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function CompileTab({ library }) {
|
export default function CompileTab({ library, onSwitchToPipeline }) {
|
||||||
const [jobs, setJobs] = useState([]);
|
const [jobs, setJobs] = useState([]);
|
||||||
const [selected, setSelected] = useState([]); // [{id, title, audio_url}] in order
|
const [selected, setSelected] = useState([]); // [{id, title, audio_url}] in order
|
||||||
const [crossfade, setCrossfade] = useState(3);
|
const [crossfade, setCrossfade] = useState(3);
|
||||||
@@ -89,6 +90,19 @@ export default function CompileTab({ library }) {
|
|||||||
if (exportData && exportData.id === jobId) setExportData(null);
|
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
|
const totalMin = selected.length > 0
|
||||||
? Math.round(selected.reduce((acc, t) => {
|
? Math.round(selected.reduce((acc, t) => {
|
||||||
const match = library.find(l => l.id === t.id);
|
const match = library.find(l => l.id === t.id);
|
||||||
@@ -215,6 +229,12 @@ export default function CompileTab({ library }) {
|
|||||||
>
|
>
|
||||||
{exportingId === j.id ? '...' : '↓ 내보내기'}
|
{exportingId === j.id ? '...' : '↓ 내보내기'}
|
||||||
</button>
|
</button>
|
||||||
|
<button type="button"
|
||||||
|
className="cmp-btn-video"
|
||||||
|
onClick={() => handleVideoFromCompile(j.id)}
|
||||||
|
>
|
||||||
|
🎬 영상 만들기
|
||||||
|
</button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{j.status === 'failed' && (
|
{j.status === 'failed' && (
|
||||||
|
|||||||
@@ -49,7 +49,12 @@ export default function YoutubeTab({ library, initialTrackId, onClearInitialTrac
|
|||||||
onClearInitialTrack={onClearInitialTrack}
|
onClearInitialTrack={onClearInitialTrack}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{subtab === 'compile' && <CompileTab library={library} />}
|
{subtab === 'compile' && (
|
||||||
|
<CompileTab
|
||||||
|
library={library}
|
||||||
|
onSwitchToPipeline={() => setSubtab('pipeline')}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{subtab === 'trends' && <TrendsTab />}
|
{subtab === 'trends' && <TrendsTab />}
|
||||||
{subtab === 'revenue' && <RevenueTab />}
|
{subtab === 'revenue' && <RevenueTab />}
|
||||||
{subtab === 'setup' && <SetupTab />}
|
{subtab === 'setup' && <SetupTab />}
|
||||||
|
|||||||
Reference in New Issue
Block a user