fix: incomplete audio

master
WorldObservationLog 5 months ago
parent 2ff9dceb28
commit 954cb3c28b
  1. 3
      src/exceptions.py
  2. 11
      src/mp4.py
  3. 9
      src/rip.py

@ -31,3 +31,6 @@ class RetryableDecryptException(Exception):
class FailedGetM3U8FromDeviceException(Exception): class FailedGetM3U8FromDeviceException(Exception):
... ...
class SongNotPassIntegrityCheckException(Exception):
...

@ -265,3 +265,14 @@ async def fix_esds_box(raw_song: bytes, song: bytes) -> bytes:
final_song = f.read() final_song = f.read()
tmp_dir.cleanup() tmp_dir.cleanup()
return final_song return final_song
async def check_song_integrity(song: bytes) -> bool:
tmp_dir = TemporaryDirectory()
name = uuid.uuid4().hex
song_name = Path(tmp_dir.name) / Path(f"{name}.m4a")
with open(song_name.absolute(), "wb") as f:
f.write(song)
output = subprocess.run(f"ffmpeg -y -v error -i {song_name.absolute()} -c:a pcm_s16le -f null /dev/null", capture_output=True)
tmp_dir.cleanup()
return not bool(output.stderr)

@ -3,6 +3,7 @@ import random
import subprocess import subprocess
from loguru import logger from loguru import logger
from tenacity import retry, retry_if_exception_type, stop_after_attempt
from src.api import (get_song_info, get_song_lyrics, get_album_info, download_song, from src.api import (get_song_info, get_song_lyrics, get_album_info, download_song,
get_m3u8_from_api, get_artist_info, get_songs_from_artist, get_albums_from_artist, get_m3u8_from_api, get_artist_info, get_songs_from_artist, get_albums_from_artist,
@ -10,9 +11,11 @@ from src.api import (get_song_info, get_song_lyrics, get_album_info, download_so
from src.config import Config from src.config import Config
from src.adb import Device from src.adb import Device
from src.decrypt import decrypt from src.decrypt import decrypt
from src.exceptions import SongNotPassIntegrityCheckException
from src.metadata import SongMetadata from src.metadata import SongMetadata
from src.models import PlaylistInfo from src.models import PlaylistInfo
from src.mp4 import extract_media, extract_song, encapsulate, write_metadata, fix_encapsulate, fix_esds_box from src.mp4 import extract_media, extract_song, encapsulate, write_metadata, fix_encapsulate, fix_esds_box, \
check_song_integrity
from src.save import save from src.save import save
from src.types import GlobalAuthParams, Codec from src.types import GlobalAuthParams, Codec
from src.url import Song, Album, URLType, Artist, Playlist from src.url import Song, Album, URLType, Artist, Playlist
@ -23,6 +26,7 @@ task_lock = asyncio.Semaphore(16)
@logger.catch @logger.catch
@timeit @timeit
@retry(retry=retry_if_exception_type(SongNotPassIntegrityCheckException), stop=stop_after_attempt(1))
async def rip_song(song: Song, auth_params: GlobalAuthParams, codec: str, config: Config, device: Device, async def rip_song(song: Song, auth_params: GlobalAuthParams, codec: str, config: Config, device: Device,
force_save: bool = False, specified_m3u8: str = "", playlist: PlaylistInfo = None): force_save: bool = False, specified_m3u8: str = "", playlist: PlaylistInfo = None):
async with task_lock: async with task_lock:
@ -109,6 +113,9 @@ async def rip_song(song: Song, auth_params: GlobalAuthParams, codec: str, config
song = await fix_encapsulate(song) song = await fix_encapsulate(song)
if codec == Codec.AAC or codec == Codec.AAC_DOWNMIX or codec == Codec.AAC_BINAURAL: if codec == Codec.AAC or codec == Codec.AAC_DOWNMIX or codec == Codec.AAC_BINAURAL:
song = await fix_esds_box(song_info.raw, song) song = await fix_esds_box(song_info.raw, song)
if not await check_song_integrity(song):
logger.warning(f"Song {song_metadata.artist} - {song_metadata.title} did not pass the integrity check!")
raise SongNotPassIntegrityCheckException
filename = await save(song, codec, song_metadata, config.download, playlist) filename = await save(song, codec, song_metadata, config.download, playlist)
logger.info(f"Song {song_metadata.artist} - {song_metadata.title} saved!") logger.info(f"Song {song_metadata.artist} - {song_metadata.title} saved!")
if config.download.afterDownloaded: if config.download.afterDownloaded:

Loading…
Cancel
Save