152 lines
4.8 KiB
Python
152 lines
4.8 KiB
Python
"""Endpoint for splitting with a tracklist file upload."""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
from fastapi import APIRouter, UploadFile, File, Form, HTTPException, BackgroundTasks
|
|
|
|
from backend.config import settings
|
|
from backend.services.task_manager import task_manager
|
|
from backend.services.splitter import run_split_task
|
|
from backend.models.request import TracklistEntry
|
|
from backend.models.response import SplitResponse, TaskStatus
|
|
|
|
router = APIRouter(prefix="/api", tags=["split"])
|
|
|
|
from audio_splitter.tracklist import parse_format, read_tracklist
|
|
|
|
|
|
@router.post("/split-file", response_model=SplitResponse)
|
|
async def split_from_file(
|
|
background_tasks: BackgroundTasks,
|
|
task_id: str = Form(...),
|
|
tracklist_file: UploadFile = File(...),
|
|
# New fields
|
|
container: Optional[str] = Form(None),
|
|
audio_codec: str = Form("copy"),
|
|
video_codec: str = Form("copy"),
|
|
subtitle_codec: str = Form("copy"),
|
|
video_quality: Optional[int] = Form(None),
|
|
drop_video: bool = Form(False),
|
|
drop_subs: bool = Form(False),
|
|
number_tracks: bool = Form(False),
|
|
replace_bad_chars: bool = Form(False),
|
|
replacement_char: str = Form("_"),
|
|
bad_chars: str = Form(r'!@#№$;:%^&?*(){}[]\/<>+=~`\' '),
|
|
skip_existing: bool = Form(False),
|
|
output_template: str = Form("%an-%tn.%ext"),
|
|
album: Optional[str] = Form(None),
|
|
comment: Optional[str] = Form(None),
|
|
no_comment: bool = Form(False),
|
|
comment_stream: Optional[int] = Form(None),
|
|
merge_comments: bool = Form(False),
|
|
comment_separator: str = Form("; "),
|
|
options: str = Form("{}"), # backward-compatible, but we now use explicit fields
|
|
tracklist_format: str = Form("%ts %tn - %an"),
|
|
):
|
|
# Validate task exists
|
|
if not task_manager.has_task(task_id):
|
|
raise HTTPException(status_code=404, detail=f"Task {task_id} not found")
|
|
|
|
status = task_manager.get_status(task_id)
|
|
if status and status["status"] in (TaskStatus.PROCESSING, TaskStatus.DONE):
|
|
raise HTTPException(
|
|
status_code=409,
|
|
detail=f"Task {task_id} is already {status['status']}"
|
|
)
|
|
|
|
if not tracklist_file.filename.endswith(('.txt', '.text')):
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail="Tracklist file must be a text file (.txt or .text)"
|
|
)
|
|
|
|
try:
|
|
content = await tracklist_file.read()
|
|
text = content.decode('utf-8')
|
|
except UnicodeDecodeError:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail="Tracklist file must be UTF-8 encoded"
|
|
)
|
|
|
|
if not text.strip():
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail="Tracklist file is empty"
|
|
)
|
|
|
|
# Parse tracklist using CLI logic
|
|
try:
|
|
tokens = parse_format(tracklist_format)
|
|
temp_tracklist_path = settings.temp_dir / task_id / "tracklist.txt"
|
|
temp_tracklist_path.parent.mkdir(parents=True, exist_ok=True)
|
|
temp_tracklist_path.write_text(text, encoding='utf-8')
|
|
|
|
tracklist_dicts = read_tracklist(str(temp_tracklist_path), tokens)
|
|
|
|
except Exception as e:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail=f"Failed to parse tracklist: {str(e)}"
|
|
)
|
|
|
|
if not tracklist_dicts:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail="No valid tracks found in tracklist file"
|
|
)
|
|
|
|
# Convert dicts to TracklistEntry objects
|
|
try:
|
|
tracklist_entries = [TracklistEntry(**entry) for entry in tracklist_dicts]
|
|
except Exception as e:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail=f"Invalid tracklist data: {str(e)}"
|
|
)
|
|
|
|
# Build options dict from explicit fields (ignore `options` parameter)
|
|
options = {
|
|
"container": container,
|
|
"audio_codec": audio_codec,
|
|
"video_codec": video_codec,
|
|
"subtitle_codec": subtitle_codec,
|
|
"video_quality": video_quality,
|
|
"drop_video": drop_video,
|
|
"drop_subs": drop_subs,
|
|
"number_tracks": number_tracks,
|
|
"replace_bad_chars": replace_bad_chars,
|
|
"replacement_char": replacement_char,
|
|
"bad_chars": bad_chars,
|
|
"skip_existing": skip_existing,
|
|
"output_template": output_template,
|
|
"album": album,
|
|
"comment": comment,
|
|
"no_comment": no_comment,
|
|
"comment_stream": comment_stream,
|
|
"merge_comments": merge_comments,
|
|
"comment_separator": comment_separator,
|
|
}
|
|
|
|
# Update task status
|
|
task_manager.update_task(
|
|
task_id,
|
|
status=TaskStatus.PROCESSING,
|
|
progress=0,
|
|
message="Preparing to split..."
|
|
)
|
|
|
|
background_tasks.add_task(
|
|
run_split_task,
|
|
task_id,
|
|
tracklist_entries,
|
|
options
|
|
)
|
|
|
|
return SplitResponse(
|
|
task_id=task_id,
|
|
status=TaskStatus.PROCESSING
|
|
)
|