Switch default output to MP3, fix AAC for iPod Nano 7G, auto-remove gray source rows after convert

- Separate AAC and MP3 ffmpeg paths: remove +global_header and +genpts from MP3
- Clamp AAC bitrate to 160 kbps (iPod Nano 7G max); warn on override
- Make mp3 the default format in UI, converter, and CLI
- Auto-remove converted source tracks from library UI (keep files on disk)
- Bulk delete_tracks with single scan+sync (progress support)
- Async duplicate removal with progress via WorkerThread
This commit is contained in:
Maksim Totmin 2026-05-31 22:44:02 +07:00
parent 63d72adae6
commit 340b0dea9e
2 changed files with 31 additions and 21 deletions

View File

@ -42,7 +42,7 @@ class AudioConverter:
def convert_to_ipod_format(self,
track_info: TrackInfo,
input_file: str,
format: str = "m4a",
format: str = "mp3",
audio_bitrate: int = 256,
overwrite: bool = False) -> str:
"""
@ -90,24 +90,27 @@ class AudioConverter:
logger.warning(f"Existing file is too small ({file_size} bytes), re-converting")
os.remove(output_file)
# iPod Nano 7 is strict about AAC parameters:
if format == "m4a":
# iPod Nano 7 AAC requirements:
# - AAC-LC profile only (HE-AAC causes playback issues/crashes)
# - 44100 Hz sample rate (firmware expects this exactly)
# - Max 160 kbps for stereo (higher may cause truncation/crackle)
# - +global_header: required for iPod AAC decoder init
# - +genpts: fix timestamp gaps from web sources
codec = "aac" if format == "m4a" else "libmp3lame"
m4a_bitrate = min(audio_bitrate, 160)
if audio_bitrate > 160:
logger.warning(
"Bitrate %d kbps exceeds iPod Nano 7 max (160 kbps), clamping to 160",
audio_bitrate,
)
cmd = [
"ffmpeg", "-y", "-fflags", "+genpts", "-i", input_file,
"-c:a", codec,
"-b:a", f"{audio_bitrate}k",
"-c:a", "aac",
"-b:a", f"{m4a_bitrate}k",
"-ar", "44100",
"-ac", "2",
"-flags", "+global_header",
]
# For M4A/AAC: force LC profile and use libfdk_aac if available (best quality),
# otherwise fall back to built-in aac with profile flag
if format == "m4a":
# Try libfdk_aac first (best compatibility)
fdkaac_cmd = cmd + [
"-map", "0:a",
@ -129,7 +132,6 @@ class AudioConverter:
if "libfdk_aac" in test.stdout:
cmd = fdkaac_cmd
else:
# Fallback: built-in aac with LC profile
cmd += [
"-map", "0:a",
"-map", "0:v?",
@ -154,7 +156,15 @@ class AudioConverter:
output_file,
]
else:
cmd += [
# MP3 for iPod Nano 7G: reliable, no special decoder flags needed.
# libmp3lame is mature and produces streams safe for hardware decoders.
# No +global_header — that flag is AAC-only and confuses MP3 playback.
cmd = [
"ffmpeg", "-y", "-i", input_file,
"-c:a", "libmp3lame",
"-b:a", f"{audio_bitrate}k",
"-ar", "44100",
"-ac", "2",
"-map", "0:a",
"-map", "0:t?",
"-id3v2_version", "3",

View File

@ -155,7 +155,7 @@ class YouTubeToIPodCLI:
def convert(self,
tracks: List[TrackInfo],
output_dir: str,
format: str = "m4a",
format: str = "mp3",
quality: int = 256,
video: bool = False,
resolution: str = "640x480") -> List[Tuple[TrackInfo, str]]: