FEATURE: single source of truth for default values added

This commit is contained in:
2026-08-20 10:28:07 +05:00
parent 05fcc8ea29
commit 140a0fbc46
9 changed files with 287 additions and 220 deletions
+45 -32
View File
@@ -2,10 +2,10 @@
import os
import sys
import shutil
from pathlib import Path
from typing import List, Dict, Any
import time
from pathlib import Path
from types import SimpleNamespace
from typing import Dict, List, Any
from backend.config import settings
from backend.services.task_manager import task_manager
@@ -13,12 +13,31 @@ from backend.services.file_manager import FileManager
from backend.models.request import TracklistEntry
from backend.models.response import TaskStatus
# Import central defaults
from audio_splitter.defaults import (
DEFAULT_FORMAT,
DEFAULT_OUTPUT_TEMPLATE,
DEFAULT_REPLACEMENT_CHAR,
DEFAULT_BAD_CHARS,
DEFAULT_ALBUM,
DEFAULT_COMMENT,
DEFAULT_NO_COMMENT,
DEFAULT_COMMENT_STREAM,
DEFAULT_MERGE_COMMENTS,
DEFAULT_COMMENT_SEPARATOR,
DEFAULT_DROP_VIDEO,
DEFAULT_DROP_SUBS,
DEFAULT_NUMBER_TRACKS,
DEFAULT_REPLACE_BAD_CHARS,
DEFAULT_SKIP_EXISTING,
DEFAULT_DELETE_ORIGINAL,
DEFAULT_TRANSCODE_TO,
)
def run_split_task(task_id: str, tracklist: List[TracklistEntry], options: Dict[str, Any]) -> None:
try:
task_manager.update_task_with_progress(
task_id, progress=5, message="Initializing..."
)
task_manager.update_task_with_progress(task_id, progress=5, message="Initializing...")
input_path = FileManager.get_input_path(task_id)
if not input_path or not input_path.exists():
@@ -26,6 +45,7 @@ def run_split_task(task_id: str, tracklist: List[TracklistEntry], options: Dict[
output_dir = FileManager.ensure_output_dir(task_id)
# Convert tracklist to dicts (CLI format)
tracks = []
for entry in tracklist:
track_dict = {
@@ -38,28 +58,25 @@ def run_split_task(task_id: str, tracklist: List[TracklistEntry], options: Dict[
}
tracks.append(track_dict)
from types import SimpleNamespace
# Build args namespace from options.
# IMPORTANT: format is None if not specified -> core will auto-detect.
# Build args namespace using defaults where options not provided
args = SimpleNamespace(
format=options.get("format"),
transcode_to=options.get("transcode_to", None),
drop_video=options.get("drop_video", False),
drop_subs=options.get("drop_subs", False),
number_tracks=options.get("number_tracks", False),
replace_bad_chars=options.get("replace_bad_chars", False),
replacement_char=options.get("replacement_char", "_"),
bad_chars=options.get("bad_chars", r'!@#№$;:%^&?*(){}[]\/<>+=~`\' '),
skip_existing=options.get("skip_existing", False),
output_template=options.get("output_template", "%an-%tn.%ext"),
album=options.get("album", None),
comment=options.get("comment", None),
no_comment=options.get("no_comment", False),
comment_stream=options.get("comment_stream", None),
merge_comments=options.get("merge_comments", False),
comment_separator=options.get("comment_separator", "; "),
delete_original=False,
format=options.get("format", DEFAULT_FORMAT),
transcode_to=options.get("transcode_to", DEFAULT_TRANSCODE_TO),
drop_video=options.get("drop_video", DEFAULT_DROP_VIDEO),
drop_subs=options.get("drop_subs", DEFAULT_DROP_SUBS),
number_tracks=options.get("number_tracks", DEFAULT_NUMBER_TRACKS),
replace_bad_chars=options.get("replace_bad_chars", DEFAULT_REPLACE_BAD_CHARS),
replacement_char=options.get("replacement_char", DEFAULT_REPLACEMENT_CHAR),
bad_chars=options.get("bad_chars", DEFAULT_BAD_CHARS),
skip_existing=options.get("skip_existing", DEFAULT_SKIP_EXISTING),
output_template=options.get("output_template", DEFAULT_OUTPUT_TEMPLATE),
album=options.get("album", DEFAULT_ALBUM),
comment=options.get("comment", DEFAULT_COMMENT),
no_comment=options.get("no_comment", DEFAULT_NO_COMMENT),
comment_stream=options.get("comment_stream", DEFAULT_COMMENT_STREAM),
merge_comments=options.get("merge_comments", DEFAULT_MERGE_COMMENTS),
comment_separator=options.get("comment_separator", DEFAULT_COMMENT_SEPARATOR),
delete_original=DEFAULT_DELETE_ORIGINAL, # never delete in web
)
project_root = Path(__file__).parent.parent.parent.parent
@@ -68,9 +85,7 @@ def run_split_task(task_id: str, tracklist: List[TracklistEntry], options: Dict[
from audio_splitter.core import split_audio
task_manager.update_task_with_progress(
task_id, progress=10, message="Starting split..."
)
task_manager.update_task_with_progress(task_id, progress=10, message="Starting split...")
split_audio(str(input_path), str(output_dir), tracks, args)
@@ -83,13 +98,11 @@ def run_split_task(task_id: str, tracklist: List[TracklistEntry], options: Dict[
status=TaskStatus.DONE
)
# Add tracks to the task state (for download and status queries)
task_manager.update_task(
task_id,
tracks=output_files
)
# Give WebSocket time to send the final message
time.sleep(0.5)
except Exception as e:
+27 -12
View File
@@ -1,27 +1,42 @@
# Stage 1: Build
# web/frontend/Dockerfile
# Build context must be the project root.
FROM node:20-alpine AS builder
# Install Python for the generation script
RUN apk add --no-cache python3 py3-pip
WORKDIR /app
# Install dependencies
COPY package.json package-lock.json* ./
# Copy frontend package files and install dependencies
COPY web/frontend/package.json web/frontend/package-lock.json* ./
RUN npm install
# Copy the application code and build
COPY . .
# Copy the frontend source code
COPY web/frontend/ .
# Copy the Python defaults and the generation script into the expected location
# The generate script in package.json expects ../../scripts/generate_ts_defaults.py
# So we must place it at /app/../../scripts/ which is /scripts/
# But we can't COPY to a parent directory. Instead, we'll copy to /app/scripts/
# and adjust the package.json script to use ./scripts/generate_ts_defaults.py
# Actually, the simplest fix is to copy to /app/scripts/ and then adjust package.json.
#
# Let's use a different approach: copy to /app/scripts/ and update the generate script.
COPY audio_splitter/defaults.py /app/scripts/defaults.py
COPY scripts/generate_ts_defaults.py /app/scripts/generate_ts_defaults.py
# Run the generation script
RUN python /app/scripts/generate_ts_defaults.py
# Build the frontend
RUN npm run build
# Stage 2: Production (nginx)
FROM nginx:alpine
# Copy built assets from builder
COPY --from=builder /app/dist /usr/share/nginx/html
COPY web/frontend/nginx/nginx.conf /etc/nginx/conf.d/default.conf
# Copy nginx configuration
COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf
# Expose the port
EXPOSE 80
# Start nginx
CMD ["nginx", "-g", "daemon off;"]
+4 -1
View File
@@ -4,6 +4,9 @@
"version": "0.1.0",
"type": "module",
"scripts": {
"generate": "python scripts/generate_ts_defaults.py",
"predev": "npm run generate",
"prebuild": "npm run generate",
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
@@ -33,4 +36,4 @@
"typescript": "^5.2.2",
"vite": "^5.0.8"
}
}
}
+37 -17
View File
@@ -1,24 +1,44 @@
// web/frontend/src/stores/optionsStore.ts
import { create } from 'zustand'
import { SplitOptions } from '../types'
import {
DEFAULT_FORMAT,
DEFAULT_OUTPUT_TEMPLATE,
DEFAULT_REPLACEMENT_CHAR,
DEFAULT_BAD_CHARS,
DEFAULT_ALBUM,
DEFAULT_COMMENT,
DEFAULT_NO_COMMENT,
DEFAULT_COMMENT_STREAM,
DEFAULT_MERGE_COMMENTS,
DEFAULT_COMMENT_SEPARATOR,
DEFAULT_DROP_VIDEO,
DEFAULT_DROP_SUBS,
DEFAULT_NUMBER_TRACKS,
DEFAULT_REPLACE_BAD_CHARS,
DEFAULT_SKIP_EXISTING,
DEFAULT_TRANSCODE_TO,
DEFAULT_TRACKLIST_FORMAT,
} from '../constants/generated'
const DEFAULT_OPTIONS: SplitOptions = {
format: 'mp3',
transcode_to: '',
drop_video: false,
drop_subs: false,
number_tracks: false,
replace_bad_chars: false,
replacement_char: '_',
bad_chars: '!@#№$;:%^&?*(){}[]\\/<>+=~`\' ',
skip_existing: false,
output_template: '%an-%tn.%ext',
album: '',
comment: '',
no_comment: false,
comment_stream: null,
merge_comments: false,
comment_separator: '; ',
tracklist_format: '%ts %tn - %an', // NEW
format: DEFAULT_FORMAT,
transcode_to: DEFAULT_TRANSCODE_TO ?? '',
drop_video: DEFAULT_DROP_VIDEO,
drop_subs: DEFAULT_DROP_SUBS,
number_tracks: DEFAULT_NUMBER_TRACKS,
replace_bad_chars: DEFAULT_REPLACE_BAD_CHARS,
replacement_char: DEFAULT_REPLACEMENT_CHAR,
bad_chars: DEFAULT_BAD_CHARS,
skip_existing: DEFAULT_SKIP_EXISTING,
output_template: DEFAULT_OUTPUT_TEMPLATE,
album: DEFAULT_ALBUM ?? '',
comment: DEFAULT_COMMENT ?? '',
no_comment: DEFAULT_NO_COMMENT,
comment_stream: DEFAULT_COMMENT_STREAM,
merge_comments: DEFAULT_MERGE_COMMENTS,
comment_separator: DEFAULT_COMMENT_SEPARATOR,
tracklist_format: DEFAULT_TRACKLIST_FORMAT,
}
interface OptionsState {