Fix Opus cover art and quality: map audio only, embed art via Mutagen

Opus ffmpeg command now uses -map 0:a to extract only the audio stream,
matching the user's working command and preventing picture stream
interference with the encoder. After conversion, cover art is embedded
from the source FLAC using Mutagen: Opus gets METADATA_BLOCK_PICTURE
(base64-encoded per OGG spec), AAC gets MP4Cover. Applied to both
the post-download lossy copy and the repair job fix handler.
pull/253/head
Broque Thomas 2 months ago
parent b0b1c22f80
commit aca8a8e996

@ -1928,7 +1928,7 @@ class RepairWorker:
codec_configs = {
'mp3': ('libmp3lame', '.mp3', ['-id3v2_version', '3']),
'opus': ('libopus', '.opus', ['-vbr', 'on']),
'opus': ('libopus', '.opus', ['-map', '0:a', '-vbr', 'on']),
'aac': ('aac', '.m4a', ['-movflags', '+faststart']),
}
@ -1997,6 +1997,39 @@ class RepairWorker:
except Exception:
pass
# Embed cover art from source FLAC
if codec in ('opus', 'aac'):
try:
from mutagen import File as MutagenFile
from mutagen.flac import FLAC as MutagenFLAC
source_audio = MutagenFLAC(resolved)
if source_audio and source_audio.pictures:
pic = source_audio.pictures[0]
dest_audio = MutagenFile(out_path)
if dest_audio is not None:
if codec == 'opus':
import base64, struct
from mutagen.oggopus import OggOpus
if isinstance(dest_audio, OggOpus):
picture_data = (
struct.pack('>II', pic.type, len(pic.mime.encode('utf-8')))
+ pic.mime.encode('utf-8')
+ struct.pack('>I', len(pic.desc.encode('utf-8')))
+ pic.desc.encode('utf-8')
+ struct.pack('>IIII', pic.width, pic.height, pic.depth, pic.colors)
+ struct.pack('>I', len(pic.data))
+ pic.data
)
dest_audio['METADATA_BLOCK_PICTURE'] = [base64.b64encode(picture_data).decode('ascii')]
dest_audio.save()
elif codec == 'aac':
from mutagen.mp4 import MP4Cover
fmt = MP4Cover.FORMAT_JPEG if 'jpeg' in pic.mime else MP4Cover.FORMAT_PNG
dest_audio['covr'] = [MP4Cover(pic.data, imageformat=fmt)]
dest_audio.save()
except Exception:
pass
# Blasphemy Mode — uses the job's own setting, not the global lossy_copy one
delete_original = False
if self._config_manager:

@ -14749,7 +14749,7 @@ def _create_lossy_copy(final_path):
# Codec configuration: (ffmpeg_codec, extension, quality_label, extra_args)
codec_map = {
'mp3': ('libmp3lame', '.mp3', f'MP3-{bitrate}', ['-id3v2_version', '3']),
'opus': ('libopus', '.opus', f'OPUS-{bitrate}', ['-vbr', 'on']),
'opus': ('libopus', '.opus', f'OPUS-{bitrate}', ['-map', '0:a', '-vbr', 'on']),
'aac': ('aac', '.m4a', f'AAC-{bitrate}', ['-movflags', '+faststart']),
}
@ -14808,6 +14808,45 @@ def _create_lossy_copy(final_path):
except Exception as tag_err:
print(f"⚠️ [Lossy Copy] Could not update QUALITY tag: {tag_err}")
# Embed cover art from source FLAC into the lossy copy
# Opus/OGG can't inherit FLAC cover art via ffmpeg -map_metadata alone
if codec in ('opus', 'aac'):
try:
from mutagen import File as MutagenFile
from mutagen.flac import FLAC as MutagenFLAC
source_audio = MutagenFLAC(final_path)
if source_audio and source_audio.pictures:
pic = source_audio.pictures[0]
dest_audio = MutagenFile(out_path)
if dest_audio is not None:
if codec == 'opus':
import base64
from mutagen.oggopus import OggOpus
if isinstance(dest_audio, OggOpus):
# OGG stores pictures as base64-encoded METADATA_BLOCK_PICTURE
import struct
# Build METADATA_BLOCK_PICTURE block
picture_data = (
struct.pack('>II', pic.type, len(pic.mime.encode('utf-8')))
+ pic.mime.encode('utf-8')
+ struct.pack('>I', len(pic.desc.encode('utf-8')))
+ pic.desc.encode('utf-8')
+ struct.pack('>IIII', pic.width, pic.height, pic.depth, pic.colors)
+ struct.pack('>I', len(pic.data))
+ pic.data
)
dest_audio['METADATA_BLOCK_PICTURE'] = [base64.b64encode(picture_data).decode('ascii')]
dest_audio.save()
print(f"🎨 [Lossy Copy] Embedded cover art in Opus file")
elif codec == 'aac':
from mutagen.mp4 import MP4Cover
fmt = MP4Cover.FORMAT_JPEG if 'jpeg' in pic.mime else MP4Cover.FORMAT_PNG
dest_audio['covr'] = [MP4Cover(pic.data, imageformat=fmt)]
dest_audio.save()
print(f"🎨 [Lossy Copy] Embedded cover art in M4A file")
except Exception as art_err:
print(f"⚠️ [Lossy Copy] Could not embed cover art: {art_err}")
# Blasphemy Mode: delete original FLAC if enabled and output is verified
if config_manager.get('lossy_copy.delete_original', False):
try:

Loading…
Cancel
Save