album.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. from dataclasses import field
  2. from typing import TYPE_CHECKING, Any, List, Optional, Union, cast
  3. from yandex_music import YandexMusicModel
  4. from yandex_music.utils import model
  5. if TYPE_CHECKING:
  6. from yandex_music import Artist, ClientType, Deprecation, JSONType, Label, Track, TrackPosition
  7. @model
  8. class Album(YandexMusicModel):
  9. """Класс, представляющий альбом.
  10. Note:
  11. Известные типы альбома: `single` - сингл, `compilation` - сборник.
  12. Известные предупреждения о содержимом: `explicit` - ненормативная лексика.
  13. Известные ошибки: `not-found` - альбом с таким ID не существует.
  14. Известные значения поля `meta_type`: `music`.
  15. Известные значения поля `available_for_options`: `bookmate`.
  16. Attributes:
  17. id (:obj:`int`, optional): Идентификатор альбома.
  18. error (:obj:`str`, optional): Ошибка получения альбома.
  19. title (:obj:`str`, optional): Название альбома.
  20. track_count (:obj:`int`, optional): Количество треков.
  21. artists (:obj:`list` из :obj:`yandex_music.Artist`, optional): Артисты.
  22. labels (:obj:`list` из :obj:`yandex_music.Label` или :obj:`str`, optional): Лейблы.
  23. available (:obj:`bool`, optional): Доступен ли альбом.
  24. available_for_premium_users (:obj:`bool`, optional): Доступен ли альбом для пользователей с подпиской.
  25. version (:obj:`str`, optional): Дополнительная информация об альбоме.
  26. cover_uri (:obj:`str`, optional): Ссылка на обложку.
  27. content_warning (:obj:`str`, optional): Предупреждение о содержимом альбома.
  28. original_release_year: TODO.
  29. genre (:obj:`str`, optional): Жанр музыки.
  30. text_color (:obj:`str`, optional): Цвет текста описания.
  31. short_description (:obj:`str`, optional): Короткое описание.
  32. description (:obj:`str`, optional): Описание.
  33. is_premiere (:obj:`bool`, optional): Премьера ли.
  34. is_banner (:obj:`bool`, optional): Является ли баннером.
  35. meta_type (:obj:`str`, optional): Мета тип TODO.
  36. storage_dir (:obj:`str`, optional): В какой папке на сервере хранится файл TODO.
  37. og_image (:obj:`str`, optional): Ссылка на превью Open Graph.
  38. recent (:obj:`bool`, optional): Является ли альбом новым.
  39. very_important (:obj:`bool`, optional): Популярен ли альбом у слушателей.
  40. available_for_mobile (:obj:`bool`, optional): Доступен ли альбом из приложения для телефона.
  41. available_partially (:obj:`bool`, optional): Доступен ли альбом частично для пользователей без подписки.
  42. bests (:obj:`list` из :obj:`int`, optional): ID лучших треков альбома.
  43. duplicates (:obj:`list` из :obj:`yandex_music.Album`, optional): Альбомы-дубликаты.
  44. prerolls (:obj:`list`, optional): Прероллы TODO.
  45. volumes (:obj:`list` из :obj:`list` из :obj:`Track`, optional): Треки альбома, разделённые по дискам.
  46. year (:obj:`int`, optional): Год релиза.
  47. release_date (:obj:`str`, optional): Дата релиза в формате ISO 8601.
  48. type (:obj:`str`, optional): Тип альбома.
  49. track_position (:obj:`yandex_music.TrackPosition`, optional): Позиция трека в альбоме. Возвращается при
  50. получении альбома в составе трека.
  51. regions (:obj:`list` из :obj:`str`, optional): Список регионов в которых доступен альбом.
  52. available_as_rbt (:obj:`bool`, optional): TODO.
  53. lyrics_available (:obj:`bool`, optional): Доступны ли слова TODO.
  54. remember_position (:obj:`bool`, optional): Запоминание позиции TODO.
  55. albums (:obj:`list` из :obj:`yandex_music.Album`, optional): Альбомы TODO.
  56. duration_ms (:obj:`int`, optional): Длительность в миллисекундах.
  57. explicit (:obj:`bool`, optional): Есть ли в треке ненормативная лексика.
  58. start_date (:obj:`str`, optional): Дата начала в формате ISO 8601 TODO.
  59. likes_count (:obj:`int`, optional): Количество лайков TODO.
  60. deprecation (:obj:`yandex_music.Deprecation`, optional): TODO.
  61. available_regions (:obj:`list` из :obj:`str`, optional): Регионы, где доступен альбом.
  62. available_for_options (:obj:`list` из :obj:`str`, optional): Возможные опции для альбома.
  63. client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
  64. """
  65. id: Optional[int] = None
  66. error: Optional[str] = None
  67. title: Optional[str] = None
  68. track_count: Optional[int] = None
  69. artists: List['Artist'] = field(default_factory=list)
  70. labels: Union[List['Label'], List['str']] = field(default_factory=list)
  71. available: Optional[bool] = None
  72. available_for_premium_users: Optional[bool] = None
  73. version: Optional[str] = None
  74. cover_uri: Optional[str] = None
  75. content_warning: Optional[str] = None
  76. original_release_year: Any = None
  77. genre: Optional[str] = None
  78. text_color: Optional[str] = None
  79. short_description: Optional[str] = None
  80. description: Optional[str] = None
  81. is_premiere: Optional[bool] = None
  82. is_banner: Optional[bool] = None
  83. meta_type: Optional[str] = None
  84. storage_dir: Optional[str] = None
  85. og_image: Optional[str] = None
  86. buy: Optional[list] = None
  87. recent: Optional[bool] = None
  88. very_important: Optional[bool] = None
  89. available_for_mobile: Optional[bool] = None
  90. available_partially: Optional[bool] = None
  91. bests: Optional[List[int]] = None
  92. duplicates: List['Album'] = field(default_factory=list)
  93. prerolls: Optional[list] = None
  94. volumes: Optional[List[List['Track']]] = None
  95. year: Optional[int] = None
  96. release_date: Optional[str] = None
  97. type: Optional[str] = None
  98. track_position: Optional['TrackPosition'] = None
  99. regions: Optional[List[str]] = None
  100. available_as_rbt: Optional[bool] = None
  101. lyrics_available: Optional[bool] = None
  102. remember_position: Optional[bool] = None
  103. albums: Optional[List['Album']] = None
  104. duration_ms: Optional[int] = None
  105. explicit: Optional[bool] = None
  106. start_date: Optional[str] = None
  107. likes_count: Optional[int] = None
  108. deprecation: Optional['Deprecation'] = None
  109. available_regions: Optional[List[str]] = None
  110. available_for_options: Optional[List[str]] = None
  111. client: Optional['ClientType'] = None
  112. def __post_init__(self) -> None:
  113. self._id_attrs = (self.id,)
  114. def with_tracks(self, *args: Any, **kwargs: Any) -> Optional['Album']:
  115. """Сокращение для::
  116. client.albums_with_tracks(album.id, *args, **kwargs)
  117. """
  118. assert isinstance(self.id, int)
  119. assert self.valid_client(self.client)
  120. return self.client.albums_with_tracks(self.id, *args, **kwargs)
  121. async def with_tracks_async(self, *args: Any, **kwargs: Any) -> Optional['Album']:
  122. """Сокращение для::
  123. await client.albums_with_tracks(album.id, *args, **kwargs)
  124. """
  125. assert isinstance(self.id, int)
  126. assert self.valid_async_client(self.client)
  127. return await self.client.albums_with_tracks(self.id, *args, **kwargs)
  128. def get_cover_url(self, size: str = '200x200') -> str:
  129. """Возвращает URL обложки.
  130. Args:
  131. size (:obj:`str`, optional): Размер обложки.
  132. Returns:
  133. :obj:`str`: URL обложки.
  134. """
  135. assert isinstance(self.cover_uri, str)
  136. return f'https://{self.cover_uri.replace("%%", size)}'
  137. def get_og_image_url(self, size: str = '200x200') -> str:
  138. """Возвращает URL OG обложки.
  139. Args:
  140. size (:obj:`str`, optional): Размер обложки.
  141. Returns:
  142. :obj:`str`: URL обложки.
  143. """
  144. assert isinstance(self.og_image, str)
  145. return f'https://{self.og_image.replace("%%", size)}'
  146. def download_cover(self, filename: str, size: str = '200x200') -> None:
  147. """Загрузка обложки.
  148. Args:
  149. filename (:obj:`str`): Путь для сохранения файла с названием и расширением.
  150. size (:obj:`str`, optional): Размер обложки.
  151. """
  152. assert self.valid_client(self.client)
  153. self.client.request.download(self.get_cover_url(size), filename)
  154. async def download_cover_async(self, filename: str, size: str = '200x200') -> None:
  155. """Загрузка обложки.
  156. Args:
  157. filename (:obj:`str`): Путь для сохранения файла с названием и расширением.
  158. size (:obj:`str`, optional): Размер обложки.
  159. """
  160. assert self.valid_async_client(self.client)
  161. await self.client.request.download(self.get_cover_url(size), filename)
  162. def download_og_image(self, filename: str, size: str = '200x200') -> None:
  163. """Загрузка обложки.
  164. Предпочтительнее использовать `self.download_cover()`.
  165. Args:
  166. filename (:obj:`str`): Путь для сохранения файла с названием и расширением.
  167. size (:obj:`str`, optional): Размер обложки.
  168. """
  169. assert self.valid_client(self.client)
  170. self.client.request.download(self.get_og_image_url(size), filename)
  171. async def download_og_image_async(self, filename: str, size: str = '200x200') -> None:
  172. """Загрузка обложки.
  173. Предпочтительнее использовать `self.download_cover_async()`.
  174. Args:
  175. filename (:obj:`str`): Путь для сохранения файла с названием и расширением.
  176. size (:obj:`str`, optional): Размер обложки.
  177. """
  178. assert self.valid_async_client(self.client)
  179. await self.client.request.download(self.get_og_image_url(size), filename)
  180. def download_cover_bytes(self, size: str = '200x200') -> bytes:
  181. """Загрузка обложки и возврат в виде байтов.
  182. Args:
  183. size (:obj:`str`, optional): Размер обложки.
  184. Returns:
  185. :obj:`bytes`: Обложка в виде байтов.
  186. """
  187. assert self.valid_client(self.client)
  188. return self.client.request.retrieve(self.get_cover_url(size))
  189. async def download_cover_bytes_async(self, size: str = '200x200') -> bytes:
  190. """Загрузка обложки и возврат в виде байтов.
  191. Args:
  192. size (:obj:`str`, optional): Размер обложки.
  193. Returns:
  194. :obj:`bytes`: Обложка в виде байтов.
  195. """
  196. assert self.valid_async_client(self.client)
  197. return await self.client.request.retrieve(self.get_cover_url(size))
  198. def download_og_image_bytes(self, size: str = '200x200') -> bytes:
  199. """Загрузка обложки и возврат в виде байтов.
  200. Предпочтительнее использовать `self.download_cover()`.
  201. Args:
  202. size (:obj:`str`, optional): Размер обложки.
  203. Returns:
  204. :obj:`bytes`: Обложка в виде байтов.
  205. """
  206. assert self.valid_client(self.client)
  207. return self.client.request.retrieve(self.get_og_image_url(size))
  208. async def download_og_image_bytes_async(self, size: str = '200x200') -> bytes:
  209. """Загрузка обложки и возврат в виде байтов.
  210. Предпочтительнее использовать `self.download_cover_async()`.
  211. Args:
  212. size (:obj:`str`, optional): Размер обложки.
  213. Returns:
  214. :obj:`bytes`: Обложка в виде байтов.
  215. """
  216. assert self.valid_async_client(self.client)
  217. return await self.client.request.retrieve(self.get_og_image_url(size))
  218. def like(self, *args: Any, **kwargs: Any) -> bool:
  219. """Сокращение для::
  220. client.users_likes_albums_add(album.id, user.id *args, **kwargs)
  221. """
  222. assert isinstance(self.id, int)
  223. assert self.valid_client(self.client)
  224. return self.client.users_likes_albums_add(self.id, self.client.account_uid, *args, **kwargs)
  225. async def like_async(self, *args: Any, **kwargs: Any) -> bool:
  226. """Сокращение для::
  227. await client.users_likes_albums_add(album.id, user.id *args, **kwargs)
  228. """
  229. assert isinstance(self.id, int)
  230. assert self.valid_async_client(self.client)
  231. return await self.client.users_likes_albums_add(self.id, self.client.account_uid, *args, **kwargs)
  232. def dislike(self, *args: Any, **kwargs: Any) -> bool:
  233. """Сокращение для::
  234. client.users_likes_albums_remove(album.id, user.id *args, **kwargs)
  235. """
  236. assert isinstance(self.id, int)
  237. assert self.valid_client(self.client)
  238. return self.client.users_likes_albums_remove(self.id, self.client.account_uid, *args, **kwargs)
  239. async def dislike_async(self, *args: Any, **kwargs: Any) -> bool:
  240. """Сокращение для::
  241. await client.users_likes_albums_remove(album.id, user.id *args, **kwargs)
  242. """
  243. assert isinstance(self.id, int)
  244. assert self.valid_async_client(self.client)
  245. return await self.client.users_likes_albums_remove(self.id, self.client.account_uid, *args, **kwargs)
  246. def artists_name(self) -> List[str]:
  247. """Получает имена всех исполнителей.
  248. Returns:
  249. :obj:`list` из :obj:`str`: Имена исполнителей.
  250. """
  251. return [i.name for i in self.artists if i.name]
  252. @classmethod
  253. def de_json(cls, data: 'JSONType', client: 'ClientType') -> Optional['Album']:
  254. """Десериализация объекта.
  255. Args:
  256. data (:obj:`dict`): Поля и значения десериализуемого объекта.
  257. client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
  258. Returns:
  259. :obj:`yandex_music.Album`: Альбом.
  260. """
  261. if not cls.is_dict_model_data(data):
  262. return None
  263. cls_data = cls.cleanup_data(data, client)
  264. from yandex_music import Artist, Deprecation, Label, Track, TrackPosition
  265. cls_data['artists'] = Artist.de_list(data.get('artists'), client)
  266. # В зависимости от запроса содержимое лейблов может быть списком объектом или списком строк.
  267. labels = data.get('labels')
  268. if cls.is_array_model_data(labels):
  269. cls_data['labels'] = Label.de_list(labels, client)
  270. elif isinstance(labels, list) and all(isinstance(label, str) for label in labels):
  271. cls_data['labels'] = cast(List[str], labels)
  272. else:
  273. # Поддержка формата. Все листы [] по умолчанию вместо None даже если данных нет.
  274. cls_data['labels'] = []
  275. cls_data['track_position'] = TrackPosition.de_json(data.get('track_position'), client)
  276. cls_data['duplicates'] = Album.de_list(data.get('duplicates'), client)
  277. cls_data['albums'] = Album.de_list(data.get('albums'), client)
  278. cls_data['deprecation'] = Deprecation.de_json(data.get('deprecation'), client)
  279. volumes = data.get('volumes')
  280. if isinstance(volumes, list):
  281. cls_data['volumes'] = [Track.de_list(volume, client) for volume in volumes]
  282. return cls(client=client, **cls_data) # type: ignore
  283. # camelCase псевдонимы
  284. #: Псевдоним для :attr:`with_tracks`
  285. withTracks = with_tracks
  286. #: Псевдоним для :attr:`with_tracks_async`
  287. withTracksAsync = with_tracks_async
  288. #: Псевдоним для :attr:`get_cover_url`
  289. getCoverUrl = get_cover_url
  290. #: Псевдоним для :attr:`get_og_image_url`
  291. getOgImageUrl = get_og_image_url
  292. #: Псевдоним для :attr:`download_cover`
  293. downloadCover = download_cover
  294. #: Псевдоним для :attr:`download_cover_async`
  295. downloadCoverAsync = download_cover_async
  296. #: Псевдоним для :attr:`download_og_image`
  297. downloadOgImage = download_og_image
  298. #: Псевдоним для :attr:`download_og_image_async`
  299. downloadOgImageAsync = download_og_image_async
  300. #: Псевдоним для :attr:`download_cover_bytes`
  301. downloadCoverBytes = download_cover_bytes
  302. #: Псевдоним для :attr:`download_cover_bytes_async`
  303. downloadCoverBytesAsync = download_cover_bytes_async
  304. #: Псевдоним для :attr:`download_og_image_bytes`
  305. downloadOgImageBytes = download_og_image_bytes
  306. #: Псевдоним для :attr:`download_og_image_bytes_async`
  307. downloadOgImageBytesAsync = download_og_image_bytes_async
  308. #: Псевдоним для :attr:`like_async`
  309. likeAsync = like_async
  310. #: Псевдоним для :attr:`dislike_async`
  311. dislikeAsync = dislike_async
  312. #: Псевдоним для :attr:`artists_name`
  313. artistsName = artists_name