FEATURE: propogate improvements from CLI version to web-backend
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
"""API route handlers."""
|
||||
|
||||
from . import upload, split, split_file, status, download, formats, info
|
||||
from . import upload, split, split_file, status, download, websocket, formats, info
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Split task endpoint."""
|
||||
"""Split task endpoint (JSON tracklist)."""
|
||||
|
||||
from fastapi import APIRouter, HTTPException, BackgroundTasks
|
||||
|
||||
@@ -24,6 +24,29 @@ async def start_split(request: SplitRequest, background_tasks: BackgroundTasks):
|
||||
detail=f"Task {task_id} is already {status['status']}"
|
||||
)
|
||||
|
||||
# Build options dict from request
|
||||
options = {
|
||||
"container": request.container,
|
||||
"audio_codec": request.audio_codec,
|
||||
"video_codec": request.video_codec,
|
||||
"subtitle_codec": request.subtitle_codec,
|
||||
"video_quality": request.video_quality,
|
||||
"drop_video": request.drop_video,
|
||||
"drop_subs": request.drop_subs,
|
||||
"number_tracks": request.number_tracks,
|
||||
"replace_bad_chars": request.replace_bad_chars,
|
||||
"replacement_char": request.replacement_char,
|
||||
"bad_chars": request.bad_chars,
|
||||
"skip_existing": request.skip_existing,
|
||||
"output_template": request.output_template,
|
||||
"album": request.album,
|
||||
"comment": request.comment,
|
||||
"no_comment": request.no_comment,
|
||||
"comment_stream": request.comment_stream,
|
||||
"merge_comments": request.merge_comments,
|
||||
"comment_separator": request.comment_separator,
|
||||
}
|
||||
|
||||
task_manager.update_task(
|
||||
task_id,
|
||||
status=TaskStatus.PROCESSING,
|
||||
@@ -31,9 +54,14 @@ async def start_split(request: SplitRequest, background_tasks: BackgroundTasks):
|
||||
message="Preparing to split..."
|
||||
)
|
||||
|
||||
background_tasks.add_task(run_split_task, task_id, request.tracklist, request.options)
|
||||
background_tasks.add_task(
|
||||
run_split_task,
|
||||
task_id,
|
||||
request.tracklist,
|
||||
options
|
||||
)
|
||||
|
||||
return SplitResponse(
|
||||
task_id=task_id,
|
||||
status=TaskStatus.PROCESSING
|
||||
)
|
||||
)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, UploadFile, File, Form, HTTPException, BackgroundTasks
|
||||
|
||||
@@ -13,7 +14,6 @@ from backend.models.response import SplitResponse, TaskStatus
|
||||
|
||||
router = APIRouter(prefix="/api", tags=["split"])
|
||||
|
||||
# Import CLI tracklist parsing functions
|
||||
from audio_splitter.tracklist import parse_format, read_tracklist
|
||||
|
||||
|
||||
@@ -22,29 +22,33 @@ async def split_from_file(
|
||||
background_tasks: BackgroundTasks,
|
||||
task_id: str = Form(...),
|
||||
tracklist_file: UploadFile = File(...),
|
||||
options: str = Form("{}"),
|
||||
# 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"),
|
||||
):
|
||||
"""
|
||||
Start a splitting task using a tracklist file.
|
||||
|
||||
This endpoint accepts a plain text tracklist file (like the CLI does)
|
||||
and parses it using the same logic.
|
||||
|
||||
Args:
|
||||
task_id: Task ID from upload.
|
||||
tracklist_file: Tracklist file (text/plain).
|
||||
options: JSON string of all CLI options.
|
||||
tracklist_format: Format string for parsing (default: "%ts %tn - %an").
|
||||
|
||||
Returns:
|
||||
SplitResponse with task_id and status.
|
||||
"""
|
||||
# Validate task exists
|
||||
if not task_manager.has_task(task_id):
|
||||
raise HTTPException(status_code=404, detail=f"Task {task_id} not found")
|
||||
|
||||
# Check if task is already processing
|
||||
status = task_manager.get_status(task_id)
|
||||
if status and status["status"] in (TaskStatus.PROCESSING, TaskStatus.DONE):
|
||||
raise HTTPException(
|
||||
@@ -52,14 +56,12 @@ async def split_from_file(
|
||||
detail=f"Task {task_id} is already {status['status']}"
|
||||
)
|
||||
|
||||
# Validate file type
|
||||
if not tracklist_file.filename.endswith(('.txt', '.text')):
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Tracklist file must be a text file (.txt or .text)"
|
||||
)
|
||||
|
||||
# Read and parse the tracklist file
|
||||
try:
|
||||
content = await tracklist_file.read()
|
||||
text = content.decode('utf-8')
|
||||
@@ -75,17 +77,13 @@ async def split_from_file(
|
||||
detail="Tracklist file is empty"
|
||||
)
|
||||
|
||||
# Parse the tracklist using CLI logic
|
||||
# Parse tracklist using CLI logic
|
||||
try:
|
||||
# Parse the format string into tokens
|
||||
tokens = parse_format(tracklist_format)
|
||||
|
||||
# Write the content to a temporary file (read_tracklist expects a file path)
|
||||
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')
|
||||
|
||||
# Parse the tracklist file using CLI logic
|
||||
tracklist_dicts = read_tracklist(str(temp_tracklist_path), tokens)
|
||||
|
||||
except Exception as e:
|
||||
@@ -100,7 +98,7 @@ async def split_from_file(
|
||||
detail="No valid tracks found in tracklist file"
|
||||
)
|
||||
|
||||
# Convert dicts to TracklistEntry objects (same as JSON endpoint)
|
||||
# Convert dicts to TracklistEntry objects
|
||||
try:
|
||||
tracklist_entries = [TracklistEntry(**entry) for entry in tracklist_dicts]
|
||||
except Exception as e:
|
||||
@@ -109,14 +107,28 @@ async def split_from_file(
|
||||
detail=f"Invalid tracklist data: {str(e)}"
|
||||
)
|
||||
|
||||
# Parse options JSON
|
||||
try:
|
||||
options_dict = json.loads(options)
|
||||
except json.JSONDecodeError:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Invalid JSON in options field"
|
||||
)
|
||||
# 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(
|
||||
@@ -126,12 +138,11 @@ async def split_from_file(
|
||||
message="Preparing to split..."
|
||||
)
|
||||
|
||||
# Start background task
|
||||
background_tasks.add_task(
|
||||
run_split_task,
|
||||
task_id,
|
||||
tracklist_entries, # now TracklistEntry objects
|
||||
options_dict
|
||||
tracklist_entries,
|
||||
options
|
||||
)
|
||||
|
||||
return SplitResponse(
|
||||
|
||||
Reference in New Issue
Block a user