feat: 영상 ID 를 폴더 안에서만 유일하게 (UNIQUE(folder_id, id))
폴더가 다르면 같은 영상 ID(예: 1,2,3,4)를 재사용할 수 있도록 변경. ID 가 더 이상 전역 PK 가 아니므로 모든 영상 조회를 폴더 스코프로 전환: - db: videos PK→UNIQUE(folder_id,id) + 기존 DB 자동 마이그레이션 - storeDb: getVideo→getVideoInFolder(folderId,id) + getVideoByIdGlobal 폴백 - public/op/editor/youtube: 재생·썸네일·편집·삭제·rename 모두 폴더 스코프 - 썸네일을 경로기반 URL(/file/video/<폴더>/<id>/thumb)로 전환 - 클라이언트 mutation 요청에 folderId 동봉 Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { spawn, spawnSync } from 'node:child_process'
|
||||
import { promises as fs, existsSync } from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { getVideo, updateVideo, videoDiskDir, type VideoTrim } from './storeDb.js'
|
||||
import { getVideoInFolder, updateVideo, videoDiskDir, type VideoTrim } from './storeDb.js'
|
||||
import { binDir } from './paths.js'
|
||||
|
||||
export class FfmpegUnavailableError extends Error {
|
||||
@@ -408,13 +408,14 @@ export async function upscaleOriginalTo60Fps(
|
||||
* stream copy 를 우선 시도해 빠르게 자르고, 실패하면 재인코딩.
|
||||
*/
|
||||
export async function applyTrimToVideo(
|
||||
folderId: number,
|
||||
videoId: string,
|
||||
trim: VideoTrim
|
||||
): Promise<string> {
|
||||
const bin = getFfmpegPath()
|
||||
const meta = getVideo(videoId)
|
||||
const meta = getVideoInFolder(folderId, videoId)
|
||||
if (!meta) throw new Error('비디오를 찾을 수 없습니다.')
|
||||
const dir = videoDiskDir(videoId)
|
||||
const dir = videoDiskDir(folderId, videoId)
|
||||
const inputPath = path.join(dir, meta.originalFile)
|
||||
await fs.access(inputPath)
|
||||
|
||||
@@ -476,7 +477,7 @@ export async function applyTrimToVideo(
|
||||
}
|
||||
await fs.rename(tmpPath, outPath)
|
||||
|
||||
updateVideo(videoId, {
|
||||
updateVideo(folderId, videoId, {
|
||||
editedFile: outName,
|
||||
trim: { startSec, endSec }
|
||||
})
|
||||
@@ -496,10 +497,10 @@ const THUMB_NAME = 'thumb.jpg'
|
||||
* 카드에서는 ▶ placeholder 로 폴백.
|
||||
* 한 번 만들면 파일로 캐시되어 다음 요청부터는 즉시 응답.
|
||||
*/
|
||||
export async function ensureThumbnail(videoId: string): Promise<string | null> {
|
||||
const meta = getVideo(videoId)
|
||||
export async function ensureThumbnail(folderId: number, videoId: string): Promise<string | null> {
|
||||
const meta = getVideoInFolder(folderId, videoId)
|
||||
if (!meta) return null
|
||||
const dir = videoDiskDir(videoId)
|
||||
const dir = videoDiskDir(folderId, videoId)
|
||||
const thumbPath = path.join(dir, THUMB_NAME)
|
||||
try {
|
||||
await fs.access(thumbPath)
|
||||
|
||||
Reference in New Issue
Block a user