feat(playlist): import UI with drag reorder + random/sequential ID toggle (STEP 5)
Adds /op/folder/:top/:sub/playlist/new page that lets the operator paste a YouTube playlist URL, probe entries via yt-dlp, reorder them by drag, edit title/ID per row, and choose between random IDs or zero-padded sequential IDs before registering all jobs in one batch.
This commit is contained in:
@@ -218,6 +218,34 @@ opRouter.get(
|
||||
}
|
||||
)
|
||||
|
||||
// ─── 플레이리스트 import 페이지 ─────────────────────────────────────────
|
||||
|
||||
opRouter.get(
|
||||
'/op/folder/:topName/:subName/playlist/new',
|
||||
requireAuth,
|
||||
(req, res, next) => {
|
||||
try {
|
||||
const segments = collectFolderSegments(req.params)
|
||||
const folder = getFolderByPath(segments)
|
||||
if (!folder) {
|
||||
res.status(404).send('폴더를 찾을 수 없습니다.')
|
||||
return
|
||||
}
|
||||
if (folder.parentId === null) {
|
||||
res.status(400).send('플레이리스트는 하위 폴더에서만 등록할 수 있습니다.')
|
||||
return
|
||||
}
|
||||
res.render('op/playlist', {
|
||||
userId: req.session.userId,
|
||||
folder,
|
||||
breadcrumb: folderPathNames(folder.id)
|
||||
})
|
||||
} catch (err) {
|
||||
next(err)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// ─── 영상 업로드 / 유튜브 ───────────────────────────────────────────────
|
||||
|
||||
function uploadSingle(fieldName: string) {
|
||||
|
||||
Reference in New Issue
Block a user