artist.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. from typing import TYPE_CHECKING, Any, List, Optional, Union
  2. from yandex_music import YandexMusicModel
  3. from yandex_music.exceptions import IdMissingError
  4. from yandex_music.utils import model
  5. if TYPE_CHECKING:
  6. from yandex_music import (
  7. ArtistAlbums,
  8. ArtistTracks,
  9. ClientType,
  10. Counts,
  11. Cover,
  12. Description,
  13. JSONType,
  14. Link,
  15. Ratings,
  16. Track,
  17. )
  18. @model
  19. class Artist(YandexMusicModel):
  20. """Класс, представляющий исполнителя.
  21. Attributes:
  22. id (:obj:`int`, optional): Уникальный идентификатор.
  23. error (:obj:`str`, optional): Сообщение об ошибке с объяснением почему не вернуло исполнителя.
  24. reason (:obj:`str`, optional): Причина отсутствия исполнителя (сообщение об ошибке).
  25. name (:obj:`str`, optional): Название.
  26. cover (:obj:`yandex_music.Cover`, optional): Обложка.
  27. various (:obj:`bool`, optional): TODO.
  28. composer (:obj:`bool`, optional): TODO.
  29. genres (:obj:`list` из :obj:`str`, optional): Жанры.
  30. og_image (:obj:`str`, optional): Ссылка на изображение для Open Graph.
  31. op_image (:obj:`str`, optional): Ссылка на изображение обложки. Используется когда не указано поле cover.
  32. no_pictures_from_search: TODO.
  33. counts (:obj:`yandex_music.Counts`, optional): Счётчики.
  34. available (:obj:`bool`, optional): Доступен ли для прослушивания.
  35. ratings (:obj:`yandex_music.Ratings`, optional): Рейтинги.
  36. links (:obj:`list` из :obj:`yandex_music.Link`, optional): Ссылки на ресурсы исполнителя.
  37. tickets_available (:obj:`bool`, optional): Имеются ли в продаже билеты на концерт.
  38. likes_count (:obj:`int`, optional): Количество лайков.
  39. popular_tracks (:obj:`list` из :obj:`yandex_music.Track`, optional): Популярные треки.
  40. regions (:obj:`list` из :obj:`str`, optional): Регион TODO.
  41. decomposed (:obj:`list` из :obj:`str` и :obj:`yandex_music.Artist`, optional): Декомпозиция всех исполнителей.
  42. Лист, где чередуется разделитель и артист. Фиты и прочее.
  43. full_names: TODO.
  44. hand_made_description (:obj:`str`, optional): Описание от Яндекс TODO.
  45. description (:obj:`yandex_music.Description`, optional): Описание.
  46. countries (:obj:`list` из :obj:`str`, optional): Страны.
  47. en_wikipedia_link (:obj:`str`, optional): Адрес страницы на wikipedia.org.
  48. db_aliases (:obj:`list` из :obj:`str`, optional): Другие названия. Как правило названия на разных языках.
  49. aliases: TODO.
  50. init_date (:obj:`str`, optional): Дата начала в формате YYYY-MM-DD или YYYY.
  51. end_date (:obj:`str`, optional): Дата окончания в формате YYYY-MM-DD или YYYY.
  52. ya_money_id (:obj:`str`): Номер кошеляка Яндекс.Деньги TODO.
  53. client (:obj:`yandex_music.Client`): Клиент Yandex Music.
  54. """
  55. id: Optional[int] = None
  56. error: Optional[str] = None
  57. reason: Optional[str] = None
  58. name: Optional[str] = None
  59. cover: Optional['Cover'] = None
  60. various: Optional[bool] = None
  61. composer: Optional[bool] = None
  62. genres: Optional[List[str]] = None
  63. og_image: Optional[str] = None
  64. op_image: Optional[str] = None
  65. no_pictures_from_search: Any = None
  66. counts: Optional['Counts'] = None
  67. available: Optional[bool] = None
  68. ratings: Optional['Ratings'] = None
  69. links: Optional[List['Link']] = None
  70. tickets_available: Optional[bool] = None
  71. likes_count: Optional[int] = None
  72. popular_tracks: Optional[List['Track']] = None
  73. regions: Optional[List[str]] = None
  74. decomposed: Optional[List[Union[str, 'Artist']]] = None
  75. full_names: Any = None
  76. hand_made_description: Optional[str] = None
  77. description: Optional['Description'] = None
  78. countries: Optional[List[str]] = None
  79. en_wikipedia_link: Optional[str] = None
  80. db_aliases: Optional[List[str]] = None
  81. aliases: Any = None
  82. init_date: Optional[str] = None
  83. end_date: Optional[str] = None
  84. ya_money_id: Optional[str] = None
  85. client: Optional['ClientType'] = None
  86. def __post_init__(self) -> None:
  87. self._id_attrs = (self.id, self.name, self.cover)
  88. @property
  89. def id_required(self) -> int:
  90. """Возвращает ID исполнителя, удостоверяясь, что он указан.
  91. Raises:
  92. IdMissingError: Если ID исполнителя не установлен.
  93. Returns:
  94. :obj:`int`: Уникальный идентификатор исполнителя.
  95. """
  96. if self.id is None:
  97. raise IdMissingError('Artist.id is required')
  98. return self.id
  99. def get_op_image_url(self, size: str = '200x200') -> str:
  100. """Возвращает URL OP обложки.
  101. Args:
  102. size (:obj:`str`, optional): Размер обложки.
  103. Returns:
  104. :obj:`str`: URL обложки.
  105. """
  106. assert isinstance(self.op_image, str)
  107. return f'https://{self.op_image.replace("%%", size)}'
  108. def get_og_image_url(self, size: str = '200x200') -> str:
  109. """Возвращает URL OG обложки.
  110. Args:
  111. size (:obj:`str`, optional): Размер обложки.
  112. Returns:
  113. :obj:`str`: URL обложки.
  114. """
  115. assert isinstance(self.og_image, str)
  116. return f'https://{self.og_image.replace("%%", size)}'
  117. def download_og_image(self, filename: str, size: str = '200x200') -> None:
  118. """Загрузка изображения для Open Graph.
  119. Args:
  120. filename (:obj:`str`): Путь для сохранения файла с названием и расширением.
  121. size (:obj:`str`, optional): Размер обложки.
  122. """
  123. assert self.valid_client(self.client)
  124. self.client.request.download(self.get_og_image_url(size), filename)
  125. async def download_og_image_async(self, filename: str, size: str = '200x200') -> None:
  126. """Загрузка изображения для Open Graph.
  127. Args:
  128. filename (:obj:`str`): Путь для сохранения файла с названием и расширением.
  129. size (:obj:`str`, optional): Размер обложки.
  130. """
  131. assert self.valid_async_client(self.client)
  132. await self.client.request.download(self.get_og_image_url(size), filename)
  133. def download_op_image(self, filename: str, size: str = '200x200') -> None:
  134. """Загрузка обложки.
  135. Notes:
  136. Используйте это только когда нет self.cover!
  137. Args:
  138. filename (:obj:`str`): Путь для сохранения файла с названием и расширением.
  139. size (:obj:`str`, optional): Размер обложки.
  140. """
  141. assert self.valid_client(self.client)
  142. self.client.request.download(self.get_op_image_url(size), filename)
  143. async def download_op_image_async(self, filename: str, size: str = '200x200') -> None:
  144. """Загрузка обложки.
  145. Notes:
  146. Используйте это только когда нет self.cover!
  147. Args:
  148. filename (:obj:`str`): Путь для сохранения файла с названием и расширением.
  149. size (:obj:`str`, optional): Размер обложки.
  150. """
  151. assert self.valid_async_client(self.client)
  152. await self.client.request.download(self.get_op_image_url(size), filename)
  153. def download_og_image_bytes(self, size: str = '200x200') -> bytes:
  154. """Загрузка изображения для Open Graph и возврат в виде байтов.
  155. Args:
  156. size (:obj:`str`, optional): Размер обложки.
  157. Returns:
  158. :obj:`bytes`: Изображение в виде байтов.
  159. """
  160. assert self.valid_client(self.client)
  161. return self.client.request.retrieve(self.get_og_image_url(size))
  162. async def download_og_image_bytes_async(self, size: str = '200x200') -> bytes:
  163. """Загрузка изображения для Open Graph и возврат в виде байтов.
  164. Args:
  165. size (:obj:`str`, optional): Размер обложки.
  166. Returns:
  167. :obj:`bytes`: Изображение в виде байтов.
  168. """
  169. assert self.valid_async_client(self.client)
  170. return await self.client.request.retrieve(self.get_og_image_url(size))
  171. def download_op_image_bytes(self, size: str = '200x200') -> bytes:
  172. """Загрузка обложки и возврат в виде байтов.
  173. Notes:
  174. Используйте это только когда нет self.cover!
  175. Args:
  176. size (:obj:`str`, optional): Размер обложки.
  177. Returns:
  178. :obj:`bytes`: Обложка в виде байтов.
  179. """
  180. assert self.valid_client(self.client)
  181. return self.client.request.retrieve(self.get_op_image_url(size))
  182. async def download_op_image_bytes_async(self, size: str = '200x200') -> bytes:
  183. """Загрузка обложки и возврат в виде байтов.
  184. Notes:
  185. Используйте это только когда нет self.cover!
  186. Args:
  187. size (:obj:`str`, optional): Размер обложки.
  188. Returns:
  189. :obj:`bytes`: Обложка в виде байтов.
  190. """
  191. assert self.valid_async_client(self.client)
  192. return await self.client.request.retrieve(self.get_op_image_url(size))
  193. def like(self, *args: Any, **kwargs: Any) -> bool:
  194. """Сокращение для::
  195. client.users_likes_artists_add(artist.id_required, user.id *args, **kwargs)
  196. """
  197. assert self.valid_client(self.client)
  198. return self.client.users_likes_artists_add(self.id_required, self.client.account_uid, *args, **kwargs)
  199. async def like_async(self, *args: Any, **kwargs: Any) -> bool:
  200. """Сокращение для::
  201. await client.users_likes_artists_add(artist.id_required, user.id *args, **kwargs)
  202. """
  203. assert self.valid_async_client(self.client)
  204. return await self.client.users_likes_artists_add(self.id_required, self.client.account_uid, *args, **kwargs)
  205. def dislike(self, *args: Any, **kwargs: Any) -> bool:
  206. """Сокращение для::
  207. client.users_likes_artists_remove(artist.id_required, user.id *args, **kwargs)
  208. """
  209. assert self.valid_client(self.client)
  210. return self.client.users_likes_artists_remove(self.id_required, self.client.account_uid, *args, **kwargs)
  211. async def dislike_async(self, *args: Any, **kwargs: Any) -> bool:
  212. """Сокращение для::
  213. await client.users_likes_artists_remove(artist.id_required, user.id *args, **kwargs)
  214. """
  215. assert self.valid_async_client(self.client)
  216. return await self.client.users_likes_artists_remove(self.id_required, self.client.account_uid, *args, **kwargs)
  217. def get_tracks(self, page: int = 0, page_size: int = 20, *args: Any, **kwargs: Any) -> Optional['ArtistTracks']:
  218. """Сокращение для::
  219. client.artists_tracks(artist.id_required, page, page_size, *args, **kwargs)
  220. """
  221. assert self.valid_client(self.client)
  222. return self.client.artists_tracks(self.id_required, page, page_size, *args, **kwargs)
  223. async def get_tracks_async(
  224. self, page: int = 0, page_size: int = 20, *args: Any, **kwargs: Any
  225. ) -> Optional['ArtistTracks']:
  226. """Сокращение для::
  227. await client.artists_tracks(artist.id_required, page, page_size, *args, **kwargs)
  228. """
  229. assert self.valid_async_client(self.client)
  230. return await self.client.artists_tracks(self.id_required, page, page_size, *args, **kwargs)
  231. def get_albums(
  232. self, page: int = 0, page_size: int = 20, sort_by: str = 'year', *args: Any, **kwargs: Any
  233. ) -> Optional['ArtistAlbums']:
  234. """Сокращение для::
  235. client.artists_direct_albums(artist.id_required, page, page_size, sort_by, *args, **kwargs)
  236. """
  237. assert self.valid_client(self.client)
  238. return self.client.artists_direct_albums(self.id_required, page, page_size, sort_by, *args, **kwargs)
  239. async def get_albums_async(
  240. self, page: int = 0, page_size: int = 20, sort_by: str = 'year', *args: Any, **kwargs: Any
  241. ) -> Optional['ArtistAlbums']:
  242. """Сокращение для::
  243. await client.artists_direct_albums(artist.id_required, page, page_size, sort_by, *args, **kwargs)
  244. """
  245. assert self.valid_async_client(self.client)
  246. return await self.client.artists_direct_albums(self.id_required, page, page_size, sort_by, *args, **kwargs)
  247. @classmethod
  248. def de_json(cls, data: 'JSONType', client: 'ClientType') -> Optional['Artist']:
  249. """Десериализация объекта.
  250. Args:
  251. data (:obj:`dict`): Поля и значения десериализуемого объекта.
  252. client (:obj:`yandex_music.Client`): Клиент Yandex Music.
  253. Returns:
  254. :obj:`yandex_music.Artist`: Исполнитель.
  255. """
  256. if not cls.is_dict_model_data(data):
  257. return None
  258. cls_data = cls.cleanup_data(data, client)
  259. from yandex_music import Counts, Cover, Description, Link, Ratings, Track
  260. cls_data['cover'] = Cover.de_json(data.get('cover'), client)
  261. cls_data['ratings'] = Ratings.de_json(data.get('ratings'), client)
  262. cls_data['counts'] = Counts.de_json(data.get('counts'), client)
  263. cls_data['links'] = Link.de_list(data.get('links'), client)
  264. cls_data['popular_tracks'] = Track.de_list(data.get('popular_tracks'), client)
  265. cls_data['description'] = Description.de_json(data.get('description'), client)
  266. # Мне всё равно как в яндухе на клиентах солвят свой бэковский костыль
  267. decomposed = data.get('decomposed')
  268. if isinstance(decomposed, list):
  269. decomposed_items: List[Union[str, 'Artist']] = []
  270. for part in decomposed:
  271. if isinstance(part, str):
  272. decomposed_items.append(part)
  273. elif isinstance(part, dict):
  274. artist = Artist.de_json(part, client)
  275. if artist:
  276. decomposed_items.append(artist)
  277. cls_data['decomposed'] = decomposed_items
  278. return cls(client=client, **cls_data) # type: ignore
  279. # camelCase псевдонимы
  280. #: Псевдоним для :attr:`id_required`
  281. idRequired = id_required
  282. #: Псевдоним для :attr:`get_op_image_url`
  283. getOpImageUrl = get_op_image_url
  284. #: Псевдоним для :attr:`get_og_image_url`
  285. getOgImageUrl = get_og_image_url
  286. #: Псевдоним для :attr:`download_og_image`
  287. downloadOgImage = download_og_image
  288. #: Псевдоним для :attr:`download_og_image_async`
  289. downloadOgImageAsync = download_og_image_async
  290. #: Псевдоним для :attr:`download_op_image`
  291. downloadOpImage = download_op_image
  292. #: Псевдоним для :attr:`download_op_image_async`
  293. downloadOpImageAsync = download_op_image_async
  294. #: Псевдоним для :attr:`download_og_image_bytes`
  295. downloadOgImageBytes = download_og_image_bytes
  296. #: Псевдоним для :attr:`download_og_image_bytes_async`
  297. downloadOgImageBytesAsync = download_og_image_bytes_async
  298. #: Псевдоним для :attr:`download_op_image_bytes`
  299. downloadOpImageBytes = download_op_image_bytes
  300. #: Псевдоним для :attr:`download_op_image_bytes_async`
  301. downloadOpImageBytesAsync = download_op_image_bytes_async
  302. #: Псевдоним для :attr:`like_async`
  303. likeAsync = like_async
  304. #: Псевдоним для :attr:`dislike_async`
  305. dislikeAsync = dislike_async
  306. #: Псевдоним для :attr:`get_tracks`
  307. getTracks = get_tracks
  308. #: Псевдоним для :attr:`get_tracks_async`
  309. getTracksAsync = get_tracks_async
  310. #: Псевдоним для :attr:`get_albums`
  311. getAlbums = get_albums
  312. #: Псевдоним для :attr:`get_albums_async`
  313. getAlbumsAsync = get_albums_async