yandex-music-downloader/ymd/ym_api/models.py
Lev Plyusnin 5b116e1a1b
Изменение структуры проекта
Данное изменение позволяет использовать проект
в качестве библиотеки, также упрощает поддержку
и добавление новых возможностей.
2023-08-19 13:00:50 +05:00

170 lines
5.1 KiB
Python

import datetime as dt
from dataclasses import dataclass
from typing import Optional
TITLE_TEMPLATE = '{title} ({version})'
@dataclass
class CoverInfo:
cover_url_template: Optional[str]
def cover_url(self, resolution: int) -> Optional[str]:
if self.cover_url_template is None:
return
return self.cover_url_template.replace('%%',
f'{resolution}x{resolution}')
@classmethod
def from_json(cls, data: dict) -> 'CoverInfo':
og_image = data.get("ogImage")
return cls(f'https://{og_image}' if og_image is not None else None)
@dataclass
class PlaylistId:
owner: str
kind: int
@dataclass
class BasicArtistInfo:
id: str
name: str
@classmethod
def from_json(cls, data: dict) -> 'BasicArtistInfo':
return cls(id=data['id'], name=data['name'])
@dataclass
class FullArtistInfo(BasicArtistInfo):
albums: list['BasicAlbumInfo']
cover_info: CoverInfo
@classmethod
def from_json(cls, data: dict) -> 'FullArtistInfo':
base = BasicArtistInfo.from_json(data['artist'])
albums = map(BasicAlbumInfo.from_json, data.get('albums', []))
albums = [a for a in albums if a is not None]
cover_info = CoverInfo.from_json(data)
return cls(**base.__dict__, cover_info=cover_info, albums=albums)
@dataclass
class BasicAlbumInfo:
id: str
title: str
release_date: Optional[dt.datetime]
year: Optional[int]
artists: list[BasicArtistInfo]
meta_type: str
@classmethod
def from_json(cls, data: dict) -> Optional['BasicAlbumInfo']:
artists = parse_artists(data['artists'])
title = parse_title(data)
if release_date := data.get('releaseDate'):
release_date = dt.datetime.fromisoformat(release_date)
return cls(id=data['id'],
title=title,
year=data.get('year'),
meta_type=data['metaType'],
artists=artists,
release_date=release_date)
@dataclass
class BasicTrackInfo:
title: str
id: str
real_id: str
album: BasicAlbumInfo
number: int
disc_number: int
artists: list[BasicArtistInfo]
has_lyrics: bool
cover_info: CoverInfo
@classmethod
def from_json(cls, data: dict) -> Optional['BasicTrackInfo']:
if not data['available']:
return None
track_id = str(data['id'])
title = parse_title(data)
albums_data = data['albums']
artists = parse_artists(data['artists'])
track_position = {'index': 1, 'volume': 1}
if len(albums_data):
album_data = albums_data[0]
album = BasicAlbumInfo.from_json(album_data)
track_position = album_data.get('trackPosition', track_position)
else:
album = BasicAlbumInfo(id=track_id,
title=title,
release_date=None,
year=None,
meta_type='music',
artists=artists)
if album is None:
raise ValueError
cover_info = CoverInfo.from_json(data)
has_lyrics = data.get('lyricsInfo', {}).get('hasAvailableTextLyrics',
False)
return cls(title=title,
id=track_id,
real_id=data['realId'],
number=track_position['index'],
disc_number=track_position['volume'],
artists=artists,
album=album,
has_lyrics=has_lyrics,
cover_info=cover_info)
@property
def url(self) -> str:
return f'https://music.yandex.ru/album/{self.album.id}/track/{self.id}'
@dataclass
class FullTrackInfo(BasicTrackInfo):
lyrics: str
@classmethod
def from_json(cls, data: dict) -> 'FullTrackInfo':
base = BasicTrackInfo.from_json(data['track'])
lyrics = data['lyric'][0]['fullLyrics']
return cls(**base.__dict__, lyrics=lyrics)
@dataclass
class FullAlbumInfo(BasicAlbumInfo):
tracks: list[BasicTrackInfo]
@classmethod
def from_json(cls, data: dict) -> 'FullAlbumInfo':
base = BasicAlbumInfo.from_json(data)
tracks = data.get('volumes', [])
tracks = [t for v in tracks for t in v]
tracks = map(BasicTrackInfo.from_json, tracks)
tracks = [t for t in tracks if t is not None]
return cls(**base.__dict__, tracks=tracks)
def parse_artists(data: list) -> list[BasicArtistInfo]:
artists = []
for artist in data:
artists.append(artist)
if decomposed := artist.get('decomposed'):
for d_artist in decomposed:
if isinstance(d_artist, dict):
artists.append(d_artist)
return [BasicArtistInfo.from_json(a) for a in artists]
def parse_title(data: dict) -> str:
title = data['title']
if version := data.get('version'):
title = TITLE_TEMPLATE.format(title=title, version=version)
return title