Добавление флага --embed-cover
- Небольшое изменение паттерна очистки пути
This commit is contained in:
parent
32acd1400b
commit
53373e41a3
2 changed files with 36 additions and 11 deletions
|
|
@ -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
43
main.py
|
|
@ -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)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue