Добавление флага --embed-cover

- Небольшое изменение паттерна очистки пути
This commit is contained in:
Lev 2022-12-12 14:55:45 +07:00
parent 32acd1400b
commit 53373e41a3
No known key found for this signature in database
GPG key ID: 21C6C2C9C0A4460D
2 changed files with 36 additions and 11 deletions

View file

@ -84,7 +84,8 @@ python3 main.py --session-id "<ID Сессии>" --url "https://music.yandex.ru/
``` ```
usage: main.py [-h] [--hq] [--skip-existing] usage: main.py [-h] [--hq] [--skip-existing]
[--cover-resolution <Разрешение обложки>] [--add-lyrics] [--cover-resolution <Разрешение обложки>] [--add-lyrics]
[--delay <Задержка>] [--add-version] [--stick-to-artist] [--delay <Задержка>] [--embed-cover] [--add-version]
[--stick-to-artist]
[--log-level {CRITICAL,FATAL,ERROR,WARN,WARNING,INFO,DEBUG,NOTSET,VERBOSE}] [--log-level {CRITICAL,FATAL,ERROR,WARN,WARNING,INFO,DEBUG,NOTSET,VERBOSE}]
(--artist-id <ID исполнителя> | --album-id <ID альбома> | --track-id <ID трека> | --playlist-id <владелец плейлиста>/<тип плейлиста> | -u URL) (--artist-id <ID исполнителя> | --album-id <ID альбома> | --track-id <ID трека> | --playlist-id <владелец плейлиста>/<тип плейлиста> | -u URL)
[--strict-path] [--dir <Папка>] [--path-pattern <Паттерн>] [--strict-path] [--dir <Папка>] [--path-pattern <Паттерн>]
@ -103,6 +104,7 @@ optional arguments:
(по умолчанию: 400) (по умолчанию: 400)
--add-lyrics Загружать тексты песен (по умолчанию: False) --add-lyrics Загружать тексты песен (по умолчанию: False)
--delay <Задержка> Задержка между запросами, в секундах (по умолчанию: 3) --delay <Задержка> Задержка между запросами, в секундах (по умолчанию: 3)
--embed-cover Встраивать обложку в .mp3 файл (по умолчанию: False)
--add-version Добавлять информацию о версии трека (по умолчанию: --add-version Добавлять информацию о версии трека (по умолчанию:
False) False)
--stick-to-artist Загружать только альбомы созданные данным исполнителем --stick-to-artist Загружать только альбомы созданные данным исполнителем

43
main.py
View file

@ -10,12 +10,14 @@ import sys
import urllib.parse import urllib.parse
import re import re
import eyed3 import eyed3
from eyed3.id3.frames import ImageFrame
import datetime import datetime
from typing import Optional from typing import Optional, BinaryIO
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from dataclasses import dataclass from dataclasses import dataclass
from requests import Session from requests import Session
from pathlib import Path from pathlib import Path
import tempfile
MD5_SALT = 'XGRlBW9FXlekgbPrRHuSiA' MD5_SALT = 'XGRlBW9FXlekgbPrRHuSiA'
ENCODED_BY = 'https://gitlab.com/llistochek/yandex-music-downloader' ENCODED_BY = 'https://gitlab.com/llistochek/yandex-music-downloader'
@ -30,7 +32,7 @@ ALBUM_RE = re.compile(r'album/(\d+)$')
ARTIST_RE = re.compile(r'artist/(\d+)$') ARTIST_RE = re.compile(r'artist/(\d+)$')
PLAYLIST_RE = re.compile(r'([\w\-]+)/playlists/(\d+)$') PLAYLIST_RE = re.compile(r'([\w\-]+)/playlists/(\d+)$')
CLEAR_PATH_RE = re.compile(r'[^\w\-_\.\\()/ ]+') CLEAR_PATH_RE = re.compile(r'[^\w\-\.\'\\()/_ ]+')
@dataclass @dataclass
@ -147,13 +149,18 @@ def get_track_download_url(session: Session, track: BasicTrackInfo, hq: bool) ->
% (host, path_hash, ts, path, track.id) % (host, path_hash, ts, path, track.id)
def download_file(session: Session, url: str, filename: Path) -> None: def download_file(session: Session, url: str, path: Path) -> None:
resp = session.get(url) resp = session.get(url)
with open(filename, 'wb') as f: with open(path, 'wb') as f:
for chunk in resp.iter_content(chunk_size=1024): for chunk in resp.iter_content(chunk_size=1024):
f.write(chunk) f.write(chunk)
def download_bytes(session: Session, url: str) -> bytes:
resp = session.get(url)
return resp.content
def get_full_track_info(session: Session, track_id: str) -> FullTrackInfo: def get_full_track_info(session: Session, track_id: str) -> FullTrackInfo:
resp = session.get(f'https://music.yandex.ru/handlers/track.jsx?track={track_id}&lang=ru') resp = session.get(f'https://music.yandex.ru/handlers/track.jsx?track={track_id}&lang=ru')
return FullTrackInfo.from_json(resp.json()) return FullTrackInfo.from_json(resp.json())
@ -188,7 +195,8 @@ def prepare_track_path(directory: Path, path: Path, track: BasicTrackInfo) -> Pa
return directory / path_part return directory / path_part
def set_id3_tags(path: Path, track: BasicTrackInfo, lyrics: Optional[str]) -> None: def set_id3_tags(path: Path, track: BasicTrackInfo, lyrics: Optional[str],
album_cover: Optional[bytes]) -> None:
audiofile = eyed3.load(path) audiofile = eyed3.load(path)
audiofile.tag = tag = eyed3.id3.tag.Tag(version=(2, 4, 0)) audiofile.tag = tag = eyed3.id3.tag.Tag(version=(2, 4, 0))
tag.artist = '; '.join(track.artists) tag.artist = '; '.join(track.artists)
@ -200,8 +208,11 @@ def set_id3_tags(path: Path, track: BasicTrackInfo, lyrics: Optional[str]) -> No
= track.album.year = track.album.year
tag.disc_num = track.disc_number tag.disc_num = track.disc_number
tag.encoded_by = ENCODED_BY tag.encoded_by = ENCODED_BY
if lyrics is not None: if lyrics is not None:
tag.lyrics.set(lyrics) tag.lyrics.set(lyrics)
if album_cover is not None:
tag.images.set(ImageFrame.FRONT_COVER, album_cover, 'image/jpeg')
tag.save() tag.save()
@ -230,6 +241,8 @@ if __name__ == '__main__':
help=help_str('Загружать тексты песен')) help=help_str('Загружать тексты песен'))
common_group.add_argument('--delay', default=DEFAULT_DELAY, metavar='<Задержка>', common_group.add_argument('--delay', default=DEFAULT_DELAY, metavar='<Задержка>',
type=int, help=help_str('Задержка между запросами, в секундах')) type=int, help=help_str('Задержка между запросами, в секундах'))
common_group.add_argument('--embed-cover', action='store_true',
help=help_str('Встраивать обложку в .mp3 файл'))
common_group.add_argument('--add-version', action='store_true', common_group.add_argument('--add-version', action='store_true',
help=help_str('Добавлять информацию о версии трека')) help=help_str('Добавлять информацию о версии трека'))
common_group.add_argument('--stick-to-artist', action='store_true', common_group.add_argument('--stick-to-artist', action='store_true',
@ -320,12 +333,13 @@ if __name__ == '__main__':
result_tracks = get_playlist(session, args.playlist_id) result_tracks = get_playlist(session, args.playlist_id)
print(f'Треков: {len(result_tracks)}') print(f'Треков: {len(result_tracks)}')
covers: dict[str, bytes] = {}
for track in result_tracks: for track in result_tracks:
album = track.album
if args.add_version: if args.add_version:
if track.version is not None: if track.version is not None:
track.title = f'{track.title} ({track.version})' track.title = f'{track.title} ({track.version})'
album = track.album
if album.version is not None: if album.version is not None:
album.title = f'{album.title} ({track.album.version})' album.title = f'{album.title} ({track.album.version})'
@ -338,7 +352,6 @@ if __name__ == '__main__':
save_dir = save_path.parent save_dir = save_path.parent
if not save_dir.is_dir(): if not save_dir.is_dir():
save_dir.mkdir(parents=True) save_dir.mkdir(parents=True)
cover_path = save_dir / 'cover.jpg'
url = get_track_download_url(session, track, args.hq) url = get_track_download_url(session, track, args.hq)
logging.info('Загружается %s', save_path) logging.info('Загружается %s', save_path)
@ -351,7 +364,17 @@ if __name__ == '__main__':
else: else:
full_info = get_full_track_info(session, track.id) full_info = get_full_track_info(session, track.id)
lyrics = full_info.lyrics lyrics = full_info.lyrics
set_id3_tags(save_path, track, lyrics)
if not cover_path.is_file(): cover = None
download_file(session, track.pic_url(args.cover_resolution), cover_path) if args.embed_cover:
if cached_cover := covers.get(album.id, None):
cover = cached_cover
else:
cover = covers[album.id] = download_bytes(session,
track.pic_url(args.cover_resolution))
else:
cover_path = save_dir / 'cover.jpg'
if not cover_path.is_file():
download_file(session, track.pic_url(args.cover_resolution), cover_path)
set_id3_tags(save_path, track, lyrics, cover)