mirror of
https://github.com/zhaarey/AppleMusicDecrypt.git
synced 2025-10-23 15:11:06 +00:00
fix: incomplete audio
This commit is contained in:
@@ -30,4 +30,7 @@ class RetryableDecryptException(Exception):
|
|||||||
...
|
...
|
||||||
|
|
||||||
class FailedGetM3U8FromDeviceException(Exception):
|
class FailedGetM3U8FromDeviceException(Exception):
|
||||||
|
...
|
||||||
|
|
||||||
|
class SongNotPassIntegrityCheckException(Exception):
|
||||||
...
|
...
|
||||||
11
src/mp4.py
11
src/mp4.py
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user