refact (core): split large code blocks, remove useless files/code #12
+21
-36
@@ -11,34 +11,36 @@ This file serves as the single source of truth for:
|
|||||||
Codec != Container != File Extension.
|
Codec != Container != File Extension.
|
||||||
Example: Opus (codec) → Ogg (container) → .opus (extension)
|
Example: Opus (codec) → Ogg (container) → .opus (extension)
|
||||||
"""
|
"""
|
||||||
|
from typing import Dict, Optional
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Container information
|
# Container information
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
CONTAINER_INFO = [
|
CONTAINER_INFO = [
|
||||||
# Audio-only containers
|
# Audio-only containers
|
||||||
{'name': 'mp3', 'ffmpeg': 'mp3', 'extension': '.mp3', 'audio_only': False, 'supports_video': True, 'supports_subs': False},
|
{'name': 'mp3', 'ffmpeg': 'mp3', 'extension': '.mp3', 'supports_video': True, 'supports_subs': False},
|
||||||
{'name': 'm4a', 'ffmpeg': 'mp4', 'extension': '.m4a', 'audio_only': True, 'supports_video': False, 'supports_subs': False},
|
{'name': 'm4a', 'ffmpeg': 'mp4', 'extension': '.m4a', 'supports_video': False, 'supports_subs': False},
|
||||||
{'name': 'flac', 'ffmpeg': 'flac', 'extension': '.flac', 'audio_only': True, 'supports_video': False, 'supports_subs': False},
|
{'name': 'flac', 'ffmpeg': 'flac', 'extension': '.flac', 'supports_video': False, 'supports_subs': False},
|
||||||
{'name': 'wav', 'ffmpeg': 'wav', 'extension': '.wav', 'audio_only': True, 'supports_video': False, 'supports_subs': False},
|
{'name': 'wav', 'ffmpeg': 'wav', 'extension': '.wav', 'supports_video': False, 'supports_subs': False},
|
||||||
{'name': 'aac', 'ffmpeg': 'adts', 'extension': '.aac', 'audio_only': True, 'supports_video': False, 'supports_subs': False},
|
{'name': 'aac', 'ffmpeg': 'adts', 'extension': '.aac', 'supports_video': False, 'supports_subs': False},
|
||||||
# Containers that support video and subtitles
|
# Containers that support video and subtitles
|
||||||
{'name': 'mp4', 'ffmpeg': 'mp4', 'extension': '.mp4', 'audio_only': False, 'supports_video': True, 'supports_subs': True},
|
{'name': 'mp4', 'ffmpeg': 'mp4', 'extension': '.mp4', 'supports_video': True, 'supports_subs': True},
|
||||||
{'name': 'mkv', 'ffmpeg': 'matroska', 'extension': '.mkv', 'audio_only': False, 'supports_video': True, 'supports_subs': True},
|
{'name': 'mkv', 'ffmpeg': 'matroska', 'extension': '.mkv', 'supports_video': True, 'supports_subs': True},
|
||||||
{'name': 'matroska', 'ffmpeg': 'matroska', 'extension': '.mkv', 'audio_only': False, 'supports_video': True, 'supports_subs': True},
|
{'name': 'ogg', 'ffmpeg': 'ogg', 'extension': '.ogg', 'supports_video': True, 'supports_subs': True},
|
||||||
{'name': 'ogg', 'ffmpeg': 'ogg', 'extension': '.ogg', 'audio_only': False, 'supports_video': True, 'supports_subs': True},
|
{'name': 'webm', 'ffmpeg': 'webm', 'extension': '.webm', 'supports_video': True, 'supports_subs': False},
|
||||||
{'name': 'webm', 'ffmpeg': 'webm', 'extension': '.webm', 'audio_only': False, 'supports_video': True, 'supports_subs': False},
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# Legacy FORMAT_INFO for backward compatibility
|
# Container name lookup set for fast membership checks
|
||||||
FORMAT_INFO = {
|
CONTAINER_NAMES = {container['name'] for container in CONTAINER_INFO}
|
||||||
container['name']: {
|
|
||||||
'ffmpeg': container['ffmpeg'],
|
|
||||||
'ext': container['extension'],
|
def get_container_info(container_name: str) -> Optional[Dict]:
|
||||||
'audio_only': container['audio_only'],
|
"""Return container info dict or None if not found."""
|
||||||
}
|
for container in CONTAINER_INFO:
|
||||||
for container in CONTAINER_INFO
|
if container['name'] == container_name:
|
||||||
}
|
return container
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Codec information
|
# Codec information
|
||||||
@@ -70,22 +72,6 @@ CODEC_TO_EXTENSION_MAP = {codec['name']: codec['recommended_extension'] for code
|
|||||||
# Map codec name → FFmpeg encoder name
|
# Map codec name → FFmpeg encoder name
|
||||||
CODEC_NAME_TO_FFMPEG = {codec['name']: codec['ffmpeg'] for codec in CODEC_INFO}
|
CODEC_NAME_TO_FFMPEG = {codec['name']: codec['ffmpeg'] for codec in CODEC_INFO}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
# Video codec support per container (legacy, will be superseded by compatibility matrix)
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
CONTAINER_VIDEO_CODEC_SUPPORT = {
|
|
||||||
'mp4': ['h264', 'h265', 'vp9', 'av1', 'mpeg4', 'hevc'],
|
|
||||||
'mkv': ['*'],
|
|
||||||
'matroska': ['*'],
|
|
||||||
'ogg': ['theora', 'dirac', 'vp8', 'png', 'mjpeg'],
|
|
||||||
'webm': ['vp8', 'vp9', 'av1'],
|
|
||||||
'mp3': [],
|
|
||||||
'm4a': [],
|
|
||||||
'flac': [],
|
|
||||||
'wav': [],
|
|
||||||
'aac': [],
|
|
||||||
}
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Compatibility matrix: container → supported audio and video codecs
|
# Compatibility matrix: container → supported audio and video codecs
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
@@ -100,7 +86,6 @@ COMPATIBILITY_MATRIX = {
|
|||||||
'm4a': {'audio': ['aac', 'alac', 'opus', 'flac'], 'video': []},
|
'm4a': {'audio': ['aac', 'alac', 'opus', 'flac'], 'video': []},
|
||||||
'mp4': {'audio': ['aac', 'alac', 'opus', 'flac', 'mp3'], 'video': ['h264', 'h265', 'vp9', 'av1']},
|
'mp4': {'audio': ['aac', 'alac', 'opus', 'flac', 'mp3'], 'video': ['h264', 'h265', 'vp9', 'av1']},
|
||||||
'mkv': {'audio': None, 'video': None},
|
'mkv': {'audio': None, 'video': None},
|
||||||
'matroska': {'audio': None, 'video': None},
|
|
||||||
'ogg': {'audio': ['opus', 'vorbis', 'flac'], 'video': ['theora', 'vp8', 'png']},
|
'ogg': {'audio': ['opus', 'vorbis', 'flac'], 'video': ['theora', 'vp8', 'png']},
|
||||||
'webm': {'audio': ['opus', 'vorbis'], 'video': ['vp8', 'vp9', 'av1']},
|
'webm': {'audio': ['opus', 'vorbis'], 'video': ['vp8', 'vp9', 'av1']},
|
||||||
'flac': {'audio': ['flac'], 'video': []},
|
'flac': {'audio': ['flac'], 'video': []},
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import sys
|
|||||||
from typing import List, Dict, Any
|
from typing import List, Dict, Any
|
||||||
|
|
||||||
from .constants import (
|
from .constants import (
|
||||||
FORMAT_INFO,
|
CONTAINER_NAMES,
|
||||||
CODEC_TO_EXTENSION_MAP,
|
CODEC_TO_EXTENSION_MAP,
|
||||||
CODEC_NAME_TO_FFMPEG, # <-- Add this
|
CODEC_NAME_TO_FFMPEG,
|
||||||
)
|
)
|
||||||
from .ffmpeg import (
|
from .ffmpeg import (
|
||||||
get_audio_duration,
|
get_audio_duration,
|
||||||
@@ -121,7 +121,8 @@ def split_audio(input_file: str, output_directory: str, tracks: List[Dict[str, A
|
|||||||
if output_audio_codec in CODEC_TO_EXTENSION_MAP:
|
if output_audio_codec in CODEC_TO_EXTENSION_MAP:
|
||||||
extension = CODEC_TO_EXTENSION_MAP[output_audio_codec]
|
extension = CODEC_TO_EXTENSION_MAP[output_audio_codec]
|
||||||
else:
|
else:
|
||||||
extension = FORMAT_INFO.get(output_container, {}).get('ext', '.mkv')
|
container_info = next((c for c in CONTAINER_INFO if c['name'] == output_container), None)
|
||||||
|
extension = container_info['extension'] if container_info else '.mkv'
|
||||||
|
|
||||||
print(f"Output extension: {extension}")
|
print(f"Output extension: {extension}")
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import json
|
|||||||
import subprocess
|
import subprocess
|
||||||
from typing import Dict, List, Optional, Tuple
|
from typing import Dict, List, Optional, Tuple
|
||||||
|
|
||||||
from .constants import FORMAT_INFO
|
from .constants import CONTAINER_INFO
|
||||||
from .utils import format_time
|
from .utils import format_time
|
||||||
|
|
||||||
|
|
||||||
@@ -159,7 +159,7 @@ def get_metadata(input_file: str) -> Dict[str, any]:
|
|||||||
|
|
||||||
def get_container_format(input_file: str) -> Optional[str]:
|
def get_container_format(input_file: str) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
Retrieve the container format name (e.g., 'mp4', 'mp3', 'matroska') from the input file.
|
Retrieve the container format name (e.g., 'mp4', 'mp3', 'mkv') from the input file.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
input_file: Path to the media file.
|
input_file: Path to the media file.
|
||||||
@@ -179,7 +179,7 @@ def get_container_format(input_file: str) -> Optional[str]:
|
|||||||
format_name = result.stdout.strip().split(',')[0] # take first if multiple
|
format_name = result.stdout.strip().split(',')[0] # take first if multiple
|
||||||
if not format_name:
|
if not format_name:
|
||||||
return None
|
return None
|
||||||
# Normalize common aliases to names used in FORMAT_INFO
|
# Normalize common aliases to names used in CONTAINER_INFO
|
||||||
mapping = {
|
mapping = {
|
||||||
'mpeg': 'mp3',
|
'mpeg': 'mp3',
|
||||||
'mp2': 'mp3',
|
'mp2': 'mp3',
|
||||||
@@ -187,8 +187,8 @@ def get_container_format(input_file: str) -> Optional[str]:
|
|||||||
'm4a': 'mp4',
|
'm4a': 'mp4',
|
||||||
'mov': 'mp4',
|
'mov': 'mp4',
|
||||||
'3gp': 'mp4',
|
'3gp': 'mp4',
|
||||||
'matroska': 'matroska',
|
'matroska': 'mkv',
|
||||||
'webm': 'matroska',
|
'webm': 'mkv',
|
||||||
'ogg': 'ogg',
|
'ogg': 'ogg',
|
||||||
'flac': 'flac',
|
'flac': 'flac',
|
||||||
'wav': 'wav',
|
'wav': 'wav',
|
||||||
@@ -366,7 +366,7 @@ def _build_standard_mapping(
|
|||||||
def _build_format(cmd: List[str], format_opt: Optional[str]) -> None:
|
def _build_format(cmd: List[str], format_opt: Optional[str]) -> None:
|
||||||
"""Add output format option if specified."""
|
"""Add output format option if specified."""
|
||||||
if format_opt:
|
if format_opt:
|
||||||
ffmpeg_format = FORMAT_INFO.get(format_opt, {}).get('ffmpeg', format_opt)
|
ffmpeg_format = next((c['ffmpeg'] for c in CONTAINER_INFO if c['name'] == format_opt), format_opt)
|
||||||
cmd.extend(['-f', ffmpeg_format])
|
cmd.extend(['-f', ffmpeg_format])
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
from typing import Dict, Optional
|
from typing import Dict, Optional
|
||||||
|
|
||||||
from .constants import (
|
from .constants import (
|
||||||
FORMAT_INFO,
|
CONTAINER_NAMES,
|
||||||
CONTAINER_INFO,
|
CONTAINER_INFO,
|
||||||
CODEC_TO_CONTAINER_MAP,
|
CODEC_TO_CONTAINER_MAP,
|
||||||
COMPATIBILITY_MATRIX,
|
COMPATIBILITY_MATRIX,
|
||||||
@@ -22,7 +22,7 @@ def determine_default_format(container: Optional[str], codec: Optional[str]) ->
|
|||||||
If the codec is not found, it falls back to the container.
|
If the codec is not found, it falls back to the container.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
container: Container name (e.g., 'ogg', 'mp4', 'matroska') as returned by get_container_format().
|
container: Container name (e.g., 'ogg', 'mp4', 'mkv') as returned by get_container_format().
|
||||||
codec: Audio codec name (e.g., 'opus', 'aac', 'mp3') as returned by get_audio_codec().
|
codec: Audio codec name (e.g., 'opus', 'aac', 'mp3') as returned by get_audio_codec().
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -33,10 +33,10 @@ def determine_default_format(container: Optional[str], codec: Optional[str]) ->
|
|||||||
|
|
||||||
if codec and codec in CODEC_TO_CONTAINER_MAP:
|
if codec and codec in CODEC_TO_CONTAINER_MAP:
|
||||||
fmt = CODEC_TO_CONTAINER_MAP[codec]
|
fmt = CODEC_TO_CONTAINER_MAP[codec]
|
||||||
if fmt in FORMAT_INFO:
|
if fmt in CONTAINER_NAMES:
|
||||||
return fmt
|
return fmt
|
||||||
|
|
||||||
if container in FORMAT_INFO:
|
if container in CONTAINER_NAMES:
|
||||||
return container
|
return container
|
||||||
|
|
||||||
return None
|
return None
|
||||||
@@ -67,14 +67,14 @@ def determine_output_format(stream_info: Dict, user_format: Optional[str],
|
|||||||
container = get_container_format(input_file)
|
container = get_container_format(input_file)
|
||||||
audio_codec = get_audio_codec(input_file)
|
audio_codec = get_audio_codec(input_file)
|
||||||
fmt = determine_default_format(container, audio_codec)
|
fmt = determine_default_format(container, audio_codec)
|
||||||
if fmt in FORMAT_INFO:
|
if fmt in CONTAINER_NAMES:
|
||||||
return fmt
|
return fmt
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Fallback
|
# Fallback
|
||||||
if stream_info.get('has_video') or stream_info.get('has_subtitle'):
|
if stream_info.get('has_video') or stream_info.get('has_subtitle'):
|
||||||
return 'matroska'
|
return 'mkv'
|
||||||
audio_codec = stream_info.get('audio_codec', '')
|
audio_codec = stream_info.get('audio_codec', '')
|
||||||
if audio_codec == 'mp3':
|
if audio_codec == 'mp3':
|
||||||
return 'mp3'
|
return 'mp3'
|
||||||
@@ -97,13 +97,13 @@ def validate_format_compatibility(
|
|||||||
Raises:
|
Raises:
|
||||||
ValueError: If the combination is incompatible.
|
ValueError: If the combination is incompatible.
|
||||||
"""
|
"""
|
||||||
info = FORMAT_INFO.get(container)
|
info = next((c for c in CONTAINER_INFO if c['name'] == container), None)
|
||||||
if not info:
|
if not info:
|
||||||
print(f"Warning: Unknown container '{container}'. Proceeding, but may fail.")
|
print(f"Warning: Unknown container '{container}'. Proceeding, but may fail.")
|
||||||
return
|
return
|
||||||
|
|
||||||
# Check if container is audio-only and video is present (unless dropped)
|
# Check if container is audio-only and video is present (unless dropped)
|
||||||
if info['audio_only'] and stream_info.get('has_video') and not drop_video:
|
if not info['supports_video'] and stream_info.get('has_video') and not drop_video:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"Container '{container}' does not support video streams. "
|
f"Container '{container}' does not support video streams. "
|
||||||
"Please use --drop-video or choose a container that supports video (e.g., MKV, MP4)."
|
"Please use --drop-video or choose a container that supports video (e.g., MKV, MP4)."
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from backend.services.task_manager import task_manager
|
|||||||
# Import core functions
|
# Import core functions
|
||||||
from audio_splitter.ffmpeg import get_stream_info, get_container_format, get_audio_codec
|
from audio_splitter.ffmpeg import get_stream_info, get_container_format, get_audio_codec
|
||||||
from audio_splitter.formats import determine_default_format
|
from audio_splitter.formats import determine_default_format
|
||||||
from audio_splitter.constants import FORMAT_INFO
|
from audio_splitter.constants import CONTAINER_NAMES
|
||||||
from audio_splitter.defaults import DEFAULT_FORMAT
|
from audio_splitter.defaults import DEFAULT_FORMAT
|
||||||
|
|
||||||
router = APIRouter(prefix="/api", tags=["info"])
|
router = APIRouter(prefix="/api", tags=["info"])
|
||||||
@@ -63,7 +63,7 @@ async def get_recommended_format(task_id: str):
|
|||||||
# Fallback if detection fails or format is unsupported
|
# Fallback if detection fails or format is unsupported
|
||||||
if fmt is None:
|
if fmt is None:
|
||||||
fmt = DEFAULT_FORMAT
|
fmt = DEFAULT_FORMAT
|
||||||
if fmt not in FORMAT_INFO:
|
if fmt not in CONTAINER_NAMES:
|
||||||
fmt = "mp3" # ultimate fallback
|
fmt = "mp3" # ultimate fallback
|
||||||
|
|
||||||
return {"format": fmt}
|
return {"format": fmt}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export function useFormatValidation(
|
|||||||
) {
|
) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const selectedContainer = containers.find(c => c.name === options.container)
|
const selectedContainer = containers.find(c => c.name === options.container)
|
||||||
if (selectedContainer?.audio_only && hasVideo && !options.drop_video) {
|
if (!selectedContainer?.supports_video && hasVideo && !options.drop_video) {
|
||||||
setFormatError(
|
setFormatError(
|
||||||
`Container '${options.container}' does not support video streams. Please enable "Drop video" or choose a container that supports video.`
|
`Container '${options.container}' does not support video streams. Please enable "Drop video" or choose a container that supports video.`
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ export interface ContainerInfo {
|
|||||||
name: string
|
name: string
|
||||||
ffmpeg: string
|
ffmpeg: string
|
||||||
extension: string
|
extension: string
|
||||||
audio_only: boolean
|
|
||||||
supports_video: boolean
|
supports_video: boolean
|
||||||
supports_subs: boolean
|
supports_subs: boolean
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user