music-lab: 가사 저장/수정/삭제 CRUD API 추가
- saved_lyrics 테이블 (id, title, text, prompt, created_at, updated_at) - GET /api/music/lyrics/library — 저장된 가사 목록 조회 - POST /api/music/lyrics/library — 가사 저장 - PUT /api/music/lyrics/library/:id — 가사 수정 - DELETE /api/music/lyrics/library/:id — 가사 삭제 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -56,6 +56,18 @@ def init_db() -> None:
|
||||
""")
|
||||
conn.execute("CREATE INDEX IF NOT EXISTS idx_library_created ON music_library(created_at DESC)")
|
||||
|
||||
conn.execute("""
|
||||
CREATE TABLE IF NOT EXISTS saved_lyrics (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
title TEXT NOT NULL DEFAULT '',
|
||||
text TEXT NOT NULL DEFAULT '',
|
||||
prompt TEXT NOT NULL DEFAULT '',
|
||||
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
|
||||
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
|
||||
)
|
||||
""")
|
||||
conn.execute("CREATE INDEX IF NOT EXISTS idx_lyrics_created ON saved_lyrics(created_at DESC)")
|
||||
|
||||
# 기존 테이블 마이그레이션 (컬럼 없으면 추가)
|
||||
for col, default in [
|
||||
("provider", "'local'"), ("lyrics", "''"),
|
||||
@@ -219,3 +231,58 @@ def get_track_file_path(track_id: int) -> Optional[str]:
|
||||
with _conn() as conn:
|
||||
row = conn.execute("SELECT file_path FROM music_library WHERE id = ?", (track_id,)).fetchone()
|
||||
return row["file_path"] if row else None
|
||||
|
||||
|
||||
# ── saved_lyrics CRUD ────────────────────────────────────────────────────────
|
||||
|
||||
def _lyrics_row_to_dict(r) -> Dict[str, Any]:
|
||||
return {
|
||||
"id": r["id"],
|
||||
"title": r["title"],
|
||||
"text": r["text"],
|
||||
"prompt": r["prompt"],
|
||||
"created_at": r["created_at"],
|
||||
"updated_at": r["updated_at"],
|
||||
}
|
||||
|
||||
|
||||
def get_all_lyrics() -> List[Dict[str, Any]]:
|
||||
with _conn() as conn:
|
||||
rows = conn.execute("SELECT * FROM saved_lyrics ORDER BY created_at DESC").fetchall()
|
||||
return [_lyrics_row_to_dict(r) for r in rows]
|
||||
|
||||
|
||||
def add_lyrics(data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
with _conn() as conn:
|
||||
conn.execute(
|
||||
"INSERT INTO saved_lyrics (title, text, prompt) VALUES (?, ?, ?)",
|
||||
(data.get("title", ""), data.get("text", ""), data.get("prompt", "")),
|
||||
)
|
||||
row = conn.execute("SELECT * FROM saved_lyrics WHERE rowid = last_insert_rowid()").fetchone()
|
||||
return _lyrics_row_to_dict(row)
|
||||
|
||||
|
||||
def update_lyrics(lyrics_id: int, data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
||||
with _conn() as conn:
|
||||
fields = []
|
||||
values = []
|
||||
for k in ("title", "text", "prompt"):
|
||||
if k in data:
|
||||
fields.append(f"{k} = ?")
|
||||
values.append(data[k])
|
||||
if not fields:
|
||||
return None
|
||||
fields.append("updated_at = strftime('%Y-%m-%dT%H:%M:%fZ','now')")
|
||||
values.append(lyrics_id)
|
||||
conn.execute(f"UPDATE saved_lyrics SET {', '.join(fields)} WHERE id = ?", values)
|
||||
row = conn.execute("SELECT * FROM saved_lyrics WHERE id = ?", (lyrics_id,)).fetchone()
|
||||
return _lyrics_row_to_dict(row) if row else None
|
||||
|
||||
|
||||
def delete_lyrics(lyrics_id: int) -> bool:
|
||||
with _conn() as conn:
|
||||
row = conn.execute("SELECT id FROM saved_lyrics WHERE id = ?", (lyrics_id,)).fetchone()
|
||||
if not row:
|
||||
return False
|
||||
conn.execute("DELETE FROM saved_lyrics WHERE id = ?", (lyrics_id,))
|
||||
return True
|
||||
|
||||
Reference in New Issue
Block a user