Корректное расширение файлов

This commit is contained in:
Lev Plyusnin 2025-05-03 11:59:47 +07:00
parent 57e6e3bae4
commit 659d7e5cf9
No known key found for this signature in database
GPG key ID: 21C6C2C9C0A4460D
4 changed files with 38 additions and 27 deletions

View file

@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "yandex-music-downloader" name = "yandex-music-downloader"
version = "3.4.5b0" version = "3.4.5b1"
description = "Загрузчик музыки с сервиса Яндекс.Музыка" description = "Загрузчик музыки с сервиса Яндекс.Музыка"
requires-python = ">=3.9" requires-python = ">=3.9"
readme = "README.md" readme = "README.md"

View file

@ -1,13 +1,11 @@
import base64 import base64
import hashlib import hashlib
import hmac import hmac
import itertools
import random import random
import time import time
import typing import typing
from collections.abc import Iterable
from dataclasses import dataclass from dataclasses import dataclass
from enum import Enum from enum import Enum, auto
from Crypto.Cipher import AES from Crypto.Cipher import AES
from strenum import StrEnum from strenum import StrEnum
@ -15,20 +13,33 @@ from yandex_music import Client, Track
from yandex_music.utils.sign_request import DEFAULT_SIGN_KEY from yandex_music.utils.sign_request import DEFAULT_SIGN_KEY
class Container(Enum):
FLAC = auto()
MP3 = auto()
MP4 = auto()
class Codec(Enum): class Codec(Enum):
FLAC = ["flac", "flac-mp4"] FLAC = auto()
MP3 = ["mp3"] MP3 = auto()
AAC = ["aac", "he-aac", "aac-mp4", "he-aac-mp4"] AAC = auto()
@classmethod
def get_all_codecs(cls) -> Iterable[str]:
return itertools.chain.from_iterable(e.value for e in cls)
@classmethod @dataclass
def from_codec_str(cls, codec_str: str) -> typing.Optional["Codec"]: class FileFormat:
for codec in cls: container: Container
if any(e == codec_str for e in codec.value): codec: Codec
return codec
FILE_FORMAT_MAPPING = {
"flac": FileFormat(Container.FLAC, Codec.FLAC),
"flac-mp4": FileFormat(Container.MP4, Codec.FLAC),
"mp3": FileFormat(Container.MP3, Codec.MP3),
"aac": FileFormat(Container.MP4, Codec.AAC),
"he-aac": FileFormat(Container.MP4, Codec.AAC),
"aac-mp4": FileFormat(Container.MP4, Codec.AAC),
"he-aac-mp4": FileFormat(Container.MP4, Codec.AAC),
}
class ApiTrackQuality(StrEnum): class ApiTrackQuality(StrEnum):
@ -40,7 +51,7 @@ class ApiTrackQuality(StrEnum):
@dataclass @dataclass
class CustomDownloadInfo: class CustomDownloadInfo:
quality: str quality: str
codec: Codec file_format: FileFormat
urls: list[str] urls: list[str]
decryption_key: str decryption_key: str
bitrate: int bitrate: int
@ -54,7 +65,7 @@ def get_download_info(track: Track, quality: ApiTrackQuality) -> CustomDownloadI
"ts": timestamp, "ts": timestamp,
"trackId": track.id, "trackId": track.id,
"quality": quality, "quality": quality,
"codecs": ",".join(Codec.get_all_codecs()), "codecs": ",".join(FILE_FORMAT_MAPPING.keys()),
"transports": "encraw", "transports": "encraw",
} }
hmac_sign = hmac.new( hmac_sign = hmac.new(
@ -71,12 +82,12 @@ def get_download_info(track: Track, quality: ApiTrackQuality) -> CustomDownloadI
resp = typing.cast(dict, resp) resp = typing.cast(dict, resp)
e = resp["download_info"] e = resp["download_info"]
raw_codec = e["codec"] raw_codec = e["codec"]
codec = Codec.from_codec_str(raw_codec) file_format = FILE_FORMAT_MAPPING.get(raw_codec)
if codec is None: if file_format is None:
raise ValueError(f"Unknown codec: {raw_codec}") raise ValueError(f"Unknown codec: {raw_codec}")
return CustomDownloadInfo( return CustomDownloadInfo(
quality=e["quality"], quality=e["quality"],
codec=codec, file_format=file_format,
urls=e["urls"], urls=e["urls"],
bitrate=e["bitrate"], bitrate=e["bitrate"],
decryption_key=e.get("key"), decryption_key=e.get("key"),

View file

@ -302,7 +302,7 @@ def main():
downloadable = core.to_downloadable_track(track, args.quality, save_path) downloadable = core.to_downloadable_track(track, args.quality, save_path)
bitrate = downloadable.download_info.bitrate bitrate = downloadable.download_info.bitrate
format_info = "[" + downloadable.download_info.codec.name format_info = "[" + downloadable.download_info.file_format.codec.name
if bitrate > 0: if bitrate > 0:
format_info += f" {bitrate}kbps" format_info += f" {bitrate}kbps"
format_info += "]" format_info += "]"

View file

@ -26,16 +26,16 @@ from mutagen.mp3 import MP3
from mutagen.mp4 import MP4, MP4Cover from mutagen.mp4 import MP4, MP4Cover
from strenum import LowercaseStrEnum from strenum import LowercaseStrEnum
from yandex_music import ( from yandex_music import (
Album,
Client, Client,
Track, Track,
YandexMusicModel, YandexMusicModel,
Album,
) )
from ymd import api from ymd import api
from ymd.api import ( from ymd.api import (
ApiTrackQuality, ApiTrackQuality,
Codec, Container,
CustomDownloadInfo, CustomDownloadInfo,
get_download_info, get_download_info,
) )
@ -330,13 +330,13 @@ def to_downloadable_track(
api_quality = ApiTrackQuality.LOSSLESS api_quality = ApiTrackQuality.LOSSLESS
download_info = get_download_info(track, api_quality) download_info = get_download_info(track, api_quality)
codec = download_info.codec container = download_info.file_format.container
if codec == Codec.MP3: if container == Container.MP3:
suffix = ".mp3" suffix = ".mp3"
elif codec == Codec.AAC: elif container == Container.MP4:
suffix = ".m4a" suffix = ".m4a"
elif codec == Codec.FLAC: elif container == Container.FLAC:
suffix = ".flac" suffix = ".flac"
else: else:
raise RuntimeError("Unknown codec") raise RuntimeError("Unknown codec")