diff --git a/CHANGES.rst b/CHANGES.rst index c6f0701..abd046c 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,6 +2,22 @@ Список изменений ================ +Версия 2.1.0 +============ + +**24.09.2022** + +**Крупные изменения** + +- В модели добавлены методы `download_bytes` и `download_bytes_async`, для получения файлов в виде байтов (`#539`_). + +**Незначительные изменения и/или исправления** + +- Исправлены методы-сокращения класса Playlist (like, dislike) (`#516`_). + +.. _`#539`: https://github.com/MarshalX/yandex-music-api/issues/539 +.. _`#516`: https://github.com/MarshalX/yandex-music-api/pull/516 + Версия 2.0.0 ============ diff --git a/yandex_music/__init__.py b/yandex_music/__init__.py index 5b92d71..39bc7d6 100644 --- a/yandex_music/__init__.py +++ b/yandex_music/__init__.py @@ -1,4 +1,4 @@ -__version__ = '2.0.1' +__version__ = '2.1' __license__ = 'GNU Lesser General Public License v3 (LGPLv3)' __copyright__ = 'Copyright (C) 2019-2022 Il`ya (Marshal) ' diff --git a/yandex_music/album/album.py b/yandex_music/album/album.py index c9a4bfe..19bb48e 100644 --- a/yandex_music/album/album.py +++ b/yandex_music/album/album.py @@ -133,6 +133,28 @@ class Album(YandexMusicObject): """ return await self.client.albums_with_tracks(self.id, *args, **kwargs) + def get_cover_url(self, size: str = '200x200') -> str: + """Возвращает URL обложки. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`str`: URL обложки. + """ + return f'https://{self.cover_uri.replace("%%", size)}' + + def get_og_image_url(self, size: str = '200x200') -> str: + """Возвращает URL OG обложки. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`str`: URL обложки. + """ + return f'https://{self.og_image.replace("%%", size)}' + def download_cover(self, filename: str, size: str = '200x200') -> None: """Загрузка обложки. @@ -140,7 +162,7 @@ class Album(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер обложки. """ - self.client.request.download(f'https://{self.cover_uri.replace("%%", size)}', filename) + self.client.request.download(self.get_cover_url(size), filename) async def download_cover_async(self, filename: str, size: str = '200x200') -> None: """Загрузка обложки. @@ -149,7 +171,7 @@ class Album(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер обложки. """ - await self.client.request.download(f'https://{self.cover_uri.replace("%%", size)}', filename) + await self.client.request.download(self.get_cover_url(size), filename) def download_og_image(self, filename: str, size: str = '200x200') -> None: """Загрузка обложки. @@ -160,7 +182,7 @@ class Album(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер обложки. """ - self.client.request.download(f'https://{self.og_image.replace("%%", size)}', filename) + self.client.request.download(self.get_og_image_url(size), filename) async def download_og_image_async(self, filename: str, size: str = '200x200') -> None: """Загрузка обложки. @@ -171,7 +193,55 @@ class Album(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер обложки. """ - await self.client.request.download(f'https://{self.og_image.replace("%%", size)}', filename) + await self.client.request.download(self.get_og_image_url(size), filename) + + def download_cover_bytes(self, size: str = '200x200') -> bytes: + """Загрузка обложки и возврат в виде байтов. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`bytes`: Обложка в виде байтов. + """ + return self.client.request.retrieve(self.get_cover_url(size)) + + async def download_cover_bytes_async(self, size: str = '200x200') -> bytes: + """Загрузка обложки и возврат в виде байтов. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`bytes`: Обложка в виде байтов. + """ + return await self.client.request.retrieve(self.get_cover_url(size)) + + def download_og_image_bytes(self, size: str = '200x200') -> bytes: + """Загрузка обложки и возврат в виде байтов. + + Предпочтительнее использовать `self.download_cover()`. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`bytes`: Обложка в виде байтов. + """ + return self.client.request.retrieve(self.get_og_image_url(size)) + + async def download_og_image_bytes_async(self, size: str = '200x200') -> bytes: + """Загрузка обложки и возврат в виде байтов. + + Предпочтительнее использовать `self.download_cover_async()`. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`bytes`: Обложка в виде байтов. + """ + return await self.client.request.retrieve(self.get_og_image_url(size)) def like(self, *args, **kwargs) -> bool: """Сокращение для:: diff --git a/yandex_music/artist/artist.py b/yandex_music/artist/artist.py index 02eab5e..81fb073 100644 --- a/yandex_music/artist/artist.py +++ b/yandex_music/artist/artist.py @@ -81,6 +81,28 @@ class Artist(YandexMusicObject): def __post_init__(self): self._id_attrs = (self.id, self.name, self.cover) + def get_op_image_url(self, size: str = '200x200') -> str: + """Возвращает URL OP обложки. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`str`: URL обложки. + """ + return f'https://{self.op_image.replace("%%", size)}' + + def get_og_image_url(self, size: str = '200x200') -> str: + """Возвращает URL OG обложки. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`str`: URL обложки. + """ + return f'https://{self.og_image.replace("%%", size)}' + def download_og_image(self, filename: str, size: str = '200x200') -> None: """Загрузка изображения для Open Graph. @@ -88,7 +110,7 @@ class Artist(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер обложки. """ - self.client.request.download(f'https://{self.og_image.replace("%%", size)}', filename) + self.client.request.download(self.get_og_image_url(size), filename) async def download_og_image_async(self, filename: str, size: str = '200x200') -> None: """Загрузка изображения для Open Graph. @@ -97,7 +119,7 @@ class Artist(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер обложки. """ - await self.client.request.download(f'https://{self.og_image.replace("%%", size)}', filename) + await self.client.request.download(self.get_og_image_url(size), filename) def download_op_image(self, filename: str, size: str = '200x200') -> None: """Загрузка обложки. @@ -109,7 +131,7 @@ class Artist(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер обложки. """ - self.client.request.download(f'https://{self.op_image.replace("%%", size)}', filename) + self.client.request.download(self.get_op_image_url(size), filename) async def download_op_image_async(self, filename: str, size: str = '200x200') -> None: """Загрузка обложки. @@ -121,7 +143,57 @@ class Artist(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер обложки. """ - await self.client.request.download(f'https://{self.op_image.replace("%%", size)}', filename) + await self.client.request.download(self.get_op_image_url(size), filename) + + def download_og_image_bytes(self, size: str = '200x200') -> bytes: + """Загрузка изображения для Open Graph и возврат в виде байтов. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`bytes`: Изображение в виде байтов. + """ + return self.client.request.retrieve(self.get_og_image_url(size)) + + async def download_og_image_bytes_async(self, size: str = '200x200') -> bytes: + """Загрузка изображения для Open Graph и возврат в виде байтов. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`bytes`: Изображение в виде байтов. + """ + return await self.client.request.retrieve(self.get_og_image_url(size)) + + def download_op_image_bytes(self, size: str = '200x200') -> bytes: + """Загрузка обложки и возврат в виде байтов. + + Notes: + Используйте это только когда нет self.cover! + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`bytes`: Обложка в виде байтов. + """ + return self.client.request.retrieve(self.get_op_image_url(size)) + + async def download_op_image_bytes_async(self, size: str = '200x200') -> bytes: + """Загрузка обложки и возврат в виде байтов. + + Notes: + Используйте это только когда нет self.cover! + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`bytes`: Обложка в виде байтов. + """ + return await self.client.request.retrieve(self.get_op_image_url(size)) def like(self, *args, **kwargs) -> bool: """Сокращение для:: diff --git a/yandex_music/cover.py b/yandex_music/cover.py index 6677d89..720eeff 100644 --- a/yandex_music/cover.py +++ b/yandex_music/cover.py @@ -42,6 +42,20 @@ class Cover(YandexMusicObject): def __post_init__(self): self._id_attrs = (self.prefix, self.version, self.uri, self.items_uri) + def get_url(self, index: int = 0, size: str = '200x200') -> str: + """Возвращает URL обложки. + + Args: + index (:obj:`int`, optional): Индекс элемента в списке ссылок на обложки если нет `self.uri`. + size (:obj:`str`, optional): Размер изображения. + + Returns: + :obj:`str`: URL адрес. + """ + uri = self.uri or self.items_uri[index] + + return f'https://{uri.replace("%%", size)}' + def download(self, filename: str, index: int = 0, size: str = '200x200') -> None: """Загрузка обложки. @@ -50,9 +64,7 @@ class Cover(YandexMusicObject): index (:obj:`int`, optional): Индекс элемента в списке ссылок на обложки если нет `self.uri`. size (:obj:`str`, optional): Размер изображения. """ - uri = self.uri or self.items_uri[index] - - self.client.request.download(f'https://{uri.replace("%%", size)}', filename) + self.client.request.download(self.get_url(index, size), filename) async def download_async(self, filename: str, index: int = 0, size: str = '200x200') -> None: """Загрузка обложки. @@ -62,9 +74,31 @@ class Cover(YandexMusicObject): index (:obj:`int`, optional): Индекс элемента в списке ссылок на обложки если нет `self.uri`. size (:obj:`str`, optional): Размер изображения. """ - uri = self.uri or self.items_uri[index] + await self.client.request.download(self.get_url(index, size), filename) - await self.client.request.download(f'https://{uri.replace("%%", size)}', filename) + def download_bytes(self, index: int = 0, size: str = '200x200') -> bytes: + """Загрузка обложки и возврат в виде байтов. + + Args: + index (:obj:`int`, optional): Индекс элемента в списке ссылок на обложки если нет `self.uri`. + size (:obj:`str`, optional): Размер изображения. + + Returns: + :obj:`bytes`: Обложка в виде байтов. + """ + return self.client.request.retrieve(self.get_url(index, size)) + + async def download_bytes_async(self, index: int = 0, size: str = '200x200') -> bytes: + """Загрузка обложки и возврат в виде байтов. + + Args: + index (:obj:`int`, optional): Индекс элемента в списке ссылок на обложки если нет `self.uri`. + size (:obj:`str`, optional): Размер изображения. + + Returns: + :obj:`bytes`: Обложка в виде байтов. + """ + return await self.client.request.retrieve(self.get_url(index, size)) @classmethod def de_json(cls, data: dict, client: 'Client') -> Optional['Cover']: diff --git a/yandex_music/download_info.py b/yandex_music/download_info.py index 46622a6..9dbe43c 100644 --- a/yandex_music/download_info.py +++ b/yandex_music/download_info.py @@ -108,6 +108,28 @@ class DownloadInfo(YandexMusicObject): await self.client.request.download(self.direct_link, filename) + def download_bytes(self) -> bytes: + """Загрузка трека и возврат в виде байтов. + + Returns: + :obj:`bytes`: Трек в виде байтов. + """ + if self.direct_link is None: + self.get_direct_link() + + return self.client.request.retrieve(self.direct_link) + + async def download_bytes_async(self) -> bytes: + """Загрузка трека и возврат в виде байтов. + + Returns: + :obj:`bytes`: Трек в виде байтов. + """ + if self.direct_link is None: + await self.get_direct_link_async() + + return await self.client.request.retrieve(self.direct_link) + @classmethod def de_json(cls, data: dict, client: 'Client') -> Optional['DownloadInfo']: """Десериализация объекта. diff --git a/yandex_music/genre/images.py b/yandex_music/genre/images.py index e7b4ee5..9aedac1 100644 --- a/yandex_music/genre/images.py +++ b/yandex_music/genre/images.py @@ -40,6 +40,22 @@ class Images(YandexMusicObject): """ self.client.request.download(self._300x300, filename) + def download_208x208_bytes(self) -> bytes: + """Загрузка изображения 208x208 и возврат в виде байтов. + + Returns: + :obj:`bytes`: Изображение в виде байтов. + """ + return self.client.request.retrieve(self._208x208) + + def download_300x300_bytes(self) -> bytes: + """Загрузка изображения 300x300 и возврат в виде байтов. + + Returns: + :obj:`bytes`: Изображение в виде байтов. + """ + return self.client.request.retrieve(self._300x300) + @classmethod def de_json(cls, data: dict, client: 'Client') -> Optional['Images']: """Десериализация объекта. diff --git a/yandex_music/icon.py b/yandex_music/icon.py index a815a84..14905e4 100644 --- a/yandex_music/icon.py +++ b/yandex_music/icon.py @@ -42,6 +42,28 @@ class Icon(YandexMusicObject): """ await self.client.request.download(self.get_url(size), filename) + def download_bytes(self, size: str = '200x200') -> bytes: + """Загрузка иконки и возврат в виде байтов. + + Args: + size (:obj:`str`, optional): Размер иконки. + + Returns: + :obj:`bytes`: Иконка в виде байтов. + """ + return self.client.request.retrieve(self.get_url(size)) + + async def download_bytes_async(self, size: str = '200x200') -> bytes: + """Загрузка иконки и возврат в виде байтов. + + Args: + size (:obj:`str`, optional): Размер иконки. + + Returns: + :obj:`bytes`: Иконка в виде байтов. + """ + return await self.client.request.retrieve(self.get_url(size)) + def get_url(self, size: str = '200x200'): """Получение URL иконки. diff --git a/yandex_music/landing/mix_link.py b/yandex_music/landing/mix_link.py index ea0a8d3..8d8a1ce 100644 --- a/yandex_music/landing/mix_link.py +++ b/yandex_music/landing/mix_link.py @@ -49,6 +49,39 @@ class MixLink(YandexMusicObject): self.cover_white, ) + def get_cover_url(self, size: str = '200x200') -> str: + """Возвращает URL обложки. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`str`: URL обложки. + """ + return f'https://{self.cover_uri.replace("%%", size)}' + + def get_cover_white_url(self, size: str = '200x200') -> str: + """Возвращает URL обложки white. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`str`: URL обложки. + """ + return f'https://{self.cover_white.replace("%%", size)}' + + def get_background_url(self, size: str = '200x200') -> str: + """Возвращает URL заднего фона. + + Args: + size (:obj:`str`, optional): Размер заднего фона. + + Returns: + :obj:`str`: URL заднего фона. + """ + return f'https://{self.background_image_uri.replace("%%", size)}' + def download_background_image(self, filename: str, size: str = '200x200') -> None: """Загрузка заднего фона. @@ -56,7 +89,7 @@ class MixLink(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер заднего фона. """ - self.client.request.download(f'https://{self.background_image_uri.replace("%%", size)}', filename) + self.client.request.download(self.get_background_url(size), filename) async def download_background_image_async(self, filename: str, size: str = '200x200') -> None: """Загрузка заднего фона. @@ -65,7 +98,7 @@ class MixLink(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер заднего фона. """ - await self.client.request.download(f'https://{self.background_image_uri.replace("%%", size)}', filename) + await self.client.request.download(self.get_background_url(size), filename) def download_cover_white(self, filename: str, size: str = '200x200') -> None: """Загрузка обложки TODO. @@ -74,7 +107,7 @@ class MixLink(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер обложки. """ - self.client.request.download(f'https://{self.cover_white.replace("%%", size)}', filename) + self.client.request.download(self.get_cover_white_url(size), filename) async def download_cover_white_async(self, filename: str, size: str = '200x200') -> None: """Загрузка обложки TODO. @@ -83,7 +116,7 @@ class MixLink(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер обложки. """ - await self.client.request.download(f'https://{self.cover_white.replace("%%", size)}', filename) + await self.client.request.download(self.get_cover_white_url(size), filename) def download_cover_uri(self, filename: str, size: str = '200x200') -> None: """Загрузка обложки. @@ -92,7 +125,7 @@ class MixLink(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер обложки. """ - self.client.request.download(f'https://{self.cover_uri.replace("%%", size)}', filename) + self.client.request.download(self.get_cover_url(size), filename) async def download_cover_uri_async(self, filename: str, size: str = '200x200') -> None: """Загрузка обложки. @@ -101,7 +134,73 @@ class MixLink(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер обложки. """ - await self.client.request.download(f'https://{self.cover_uri.replace("%%", size)}', filename) + await self.client.request.download(self.get_cover_url(size), filename) + + def download_background_image_bytes(self, size: str = '200x200') -> bytes: + """Загрузка заднего фона и возврат в виде байтов. + + Args: + size (:obj:`str`, optional): Размер заднего фона. + + Returns: + :obj:`bytes`: Задний фон в виде байтов. + """ + return self.client.request.retrieve(self.get_background_url(size)) + + async def download_background_image_bytes_async(self, size: str = '200x200') -> bytes: + """Загрузка заднего фона и возврат в виде байтов. + + Args: + size (:obj:`str`, optional): Размер заднего фона. + + Returns: + :obj:`bytes`: Задний фон в виде байтов. + """ + return await self.client.request.retrieve(self.get_background_url(size)) + + def download_cover_white_bytes(self, size: str = '200x200') -> bytes: + """Загрузка обложки и возврат в виде байтов TODO. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`bytes`: Обложка в виде байтов. + """ + return self.client.request.retrieve(self.get_cover_white_url(size)) + + async def download_cover_white_bytes_async(self, size: str = '200x200') -> bytes: + """Загрузка обложки и возврат в виде байтов TODO. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`bytes`: Обложка в виде байтов. + """ + return await self.client.request.retrieve(self.get_cover_white_url(size)) + + def download_cover_uri_bytes(self, size: str = '200x200') -> bytes: + """Загрузка обложки и возврат в виде байтов. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`bytes`: Обложка в виде байтов. + """ + return self.client.request.retrieve(self.get_cover_url(size)) + + async def download_cover_uri_bytes_async(self, size: str = '200x200') -> bytes: + """Загрузка обложки и возврат в виде байтов. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`bytes`: Обложка в виде байтов. + """ + return await self.client.request.retrieve(self.get_cover_url(size)) @classmethod def de_json(cls, data: dict, client: 'Client') -> Optional['MixLink']: diff --git a/yandex_music/landing/promotion.py b/yandex_music/landing/promotion.py index 3a9df76..9d56a0d 100644 --- a/yandex_music/landing/promotion.py +++ b/yandex_music/landing/promotion.py @@ -53,6 +53,17 @@ class Promotion(YandexMusicObject): self.image, ) + def get_image_url(self, size: str = '300x300') -> str: + """Возвращает URL изображения. + + Args: + size (:obj:`str`, optional): Размер изображения. + + Returns: + :obj:`str`: URL изображения. + """ + return f'https://{self.image.replace("%%", size)}' + def download_image(self, filename: str, size: str = '300x300') -> None: """Загрузка рекламного изображения. @@ -60,7 +71,7 @@ class Promotion(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер изображения. """ - self.client.request.download(f'https://{self.image.replace("%%", size)}', filename) + self.client.request.download(self.get_image_url(size), filename) async def download_image_async(self, filename: str, size: str = '300x300') -> None: """Загрузка рекламного изображения. @@ -69,7 +80,29 @@ class Promotion(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер изображения. """ - await self.client.request.download(f'https://{self.image.replace("%%", size)}', filename) + await self.client.request.download(self.get_image_url(size), filename) + + def download_image_bytes(self, size: str = '300x300') -> bytes: + """Загрузка рекламного изображения и возврат в виде байтов. + + Args: + size (:obj:`str`, optional): Размер изображения. + + Returns: + :obj:`bytes`: Рекламное изображение в виде байтов. + """ + return self.client.request.retrieve(self.get_image_url(size)) + + async def download_image_bytes_async(self, size: str = '300x300') -> bytes: + """Загрузка рекламного изображения и возврат в виде байтов. + + Args: + size (:obj:`str`, optional): Размер изображения. + + Returns: + :obj:`bytes`: Рекламное изображение в виде байтов. + """ + return await self.client.request.retrieve(self.get_image_url(size)) @classmethod def de_json(cls, data: dict, client: 'Client') -> Optional['Promotion']: diff --git a/yandex_music/playlist/playlist.py b/yandex_music/playlist/playlist.py index 804884a..2d40797 100644 --- a/yandex_music/playlist/playlist.py +++ b/yandex_music/playlist/playlist.py @@ -179,6 +179,28 @@ class Playlist(YandexMusicObject): """ return await self.client.users_playlists_recommendations(self.kind, self.owner.uid, *args, **kwargs) + def get_animated_cover_url(self, size: str = '300x300') -> str: + """Возвращает URL анимированной обложки. + + Args: + size (:obj:`str`, optional): Размер анимированной обложки. + + Returns: + :obj:`str`: URL анимированной обложки. + """ + return f'https://{self.animated_cover_uri.replace("%%", size)}' + + def get_og_image_url(self, size: str = '300x300') -> str: + """Возвращает URL обложки. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`str`: URL обложки. + """ + return f'https://{self.og_image.replace("%%", size)}' + def download_animated_cover(self, filename: str, size: str = '200x200') -> None: """Загрузка анимированной обложки. @@ -186,7 +208,7 @@ class Playlist(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением (GIF). size (:obj:`str`, optional): Размер анимированной обложки. """ - self.client.request.download(f'https://{self.animated_cover_uri.replace("%%", size)}', filename) + self.client.request.download(self.get_animated_cover_url(size), filename) async def download_animated_cover_async(self, filename: str, size: str = '200x200') -> None: """Загрузка анимированной обложки. @@ -195,7 +217,7 @@ class Playlist(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением (GIF). size (:obj:`str`, optional): Размер анимированной обложки. """ - await self.client.request.download(f'https://{self.animated_cover_uri.replace("%%", size)}', filename) + await self.client.request.download(self.get_animated_cover_url(size), filename) def download_og_image(self, filename: str, size: str = '200x200') -> None: """Загрузка обложки. @@ -206,7 +228,7 @@ class Playlist(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер обложки. """ - self.client.request.download(f'https://{self.og_image.replace("%%", size)}', filename) + self.client.request.download(self.get_og_image_url(size), filename) async def download_og_image_async(self, filename: str, size: str = '200x200') -> None: """Загрузка обложки. @@ -217,7 +239,55 @@ class Playlist(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер обложки. """ - await self.client.request.download(f'https://{self.og_image.replace("%%", size)}', filename) + await self.client.request.download(self.get_og_image_url(size), filename) + + def download_animated_cover_bytes(self, size: str = '200x200') -> bytes: + """Загрузка анимированной обложки и возврат в виде байтов. + + Args: + size (:obj:`str`, optional): Размер анимированной обложки. + + Returns: + :obj:`bytes`: Анимированная обложка в виде байтов. + """ + return self.client.request.retrieve(self.get_animated_cover_url(size)) + + async def download_animated_cover_bytes_async(self, size: str = '200x200') -> bytes: + """Загрузка анимированной обложки и возврат в виде байтов. + + Args: + size (:obj:`str`, optional): Размер анимированной обложки. + + Returns: + :obj:`bytes`: Анимированная обложка в виде байтов. + """ + return await self.client.request.retrieve(self.get_animated_cover_url(size)) + + def download_og_image_bytes(self, size: str = '200x200') -> bytes: + """Загрузка обложки и возврат в виде байтов. + + Используйте это только когда нет self.cover! + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`bytes`: Обложка в виде байтов. + """ + return self.client.request.retrieve(self.get_og_image_url(size)) + + async def download_og_image_bytes_async(self, size: str = '200x200') -> bytes: + """Загрузка обложки и возврат в виде байтов. + + Используйте это только когда нет self.cover! + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`bytes`: Обложка в виде байтов. + """ + return await self.client.request.retrieve(self.get_og_image_url(size)) def rename(self, name: str) -> None: client, kind = self.client, self.kind diff --git a/yandex_music/shot/shot_data.py b/yandex_music/shot/shot_data.py index 12a6e9c..beb571e 100644 --- a/yandex_music/shot/shot_data.py +++ b/yandex_music/shot/shot_data.py @@ -28,6 +28,17 @@ class ShotData(YandexMusicObject): def __post_init__(self): self._id_attrs = (self.cover_uri, self.mds_url, self.shot_text, self.shot_type) + def get_cover_url(self, size: str = '200x200') -> str: + """Возвращает URL обложки. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`str`: URL обложки. + """ + return f'https://{self.cover_uri.replace("%%", size)}' + def download_cover(self, filename: str, size: str = '200x200') -> None: """Загрузка обложки. @@ -35,7 +46,7 @@ class ShotData(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер обложки. """ - self.client.request.download(f'https://{self.cover_uri.replace("%%", size)}', filename) + self.client.request.download(self.get_cover_url(size), filename) async def download_cover_async(self, filename: str, size: str = '200x200') -> None: """Загрузка обложки. @@ -44,7 +55,7 @@ class ShotData(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер обложки. """ - await self.client.request.download(f'https://{self.cover_uri.replace("%%", size)}', filename) + await self.client.request.download(self.get_cover_url(size), filename) def download_mds(self, filename: str) -> None: """Загрузка аудиоверсии шота. @@ -62,6 +73,44 @@ class ShotData(YandexMusicObject): """ await self.client.request.download(self.mds_url, filename) + def download_cover_bytes(self, size: str = '200x200') -> bytes: + """Загрузка обложки и возврат в виде байтов. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`bytes`: Обложка в виде байтов + """ + return self.client.request.retrieve(self.get_cover_url(size)) + + async def download_cover_bytes_async(self, size: str = '200x200') -> bytes: + """Загрузка обложки и возврат в виде байтов. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`bytes`: Обложка в виде байтов + """ + return await self.client.request.retrieve(self.get_cover_url(size)) + + def download_mds_bytes(self) -> bytes: + """Загрузка аудиоверсии шота и возврат в виде байтов. + + Returns: + :obj:`bytes`: Аудиоверсия шота в виде байтов + """ + return self.client.request.retrieve(self.mds_url) + + async def download_mds_bytes_async(self) -> bytes: + """Загрузка аудиоверсии шота и возврат в виде байтов. + + Returns: + :obj:`bytes`: Аудиоверсия шота в виде байтов + """ + return await self.client.request.retrieve(self.mds_url) + @classmethod def de_json(cls, data: dict, client: 'Client') -> Optional['ShotData']: """Десериализация объекта. diff --git a/yandex_music/track/track.py b/yandex_music/track/track.py index aba42f7..a28b796 100644 --- a/yandex_music/track/track.py +++ b/yandex_music/track/track.py @@ -154,6 +154,28 @@ class Track(YandexMusicObject): """ return await self.client.track_supplement(self.id, *args, **kwargs) + def get_cover_url(self, size: str = '200x200') -> str: + """Возвращает URL обложки. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`str`: URL обложки. + """ + return f'https://{self.cover_uri.replace("%%", size)}' + + def get_og_image_url(self, size: str = '200x200') -> str: + """Возвращает URL OG обложки. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`str`: URL обложки. + """ + return f'https://{self.og_image.replace("%%", size)}' + def download_cover(self, filename: str, size: str = '200x200') -> None: """Загрузка обложки. @@ -161,7 +183,7 @@ class Track(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер обложки. """ - self.client.request.download(f'https://{self.cover_uri.replace("%%", size)}', filename) + self.client.request.download(self.get_cover_url(size), filename) async def download_cover_async(self, filename: str, size: str = '200x200') -> None: """Загрузка обложки. @@ -170,7 +192,7 @@ class Track(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер обложки. """ - await self.client.request.download(f'https://{self.cover_uri.replace("%%", size)}', filename) + await self.client.request.download(self.get_cover_url(size), filename) def download_og_image(self, filename: str, size: str = '200x200') -> None: """Загрузка обложки. @@ -181,7 +203,7 @@ class Track(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер обложки. """ - self.client.request.download(f'https://{self.og_image.replace("%%", size)}', filename) + self.client.request.download(self.get_og_image_url(size), filename) async def download_og_image_async(self, filename: str, size: str = '200x200') -> None: """Загрузка обложки. @@ -192,7 +214,91 @@ class Track(YandexMusicObject): filename (:obj:`str`): Путь для сохранения файла с названием и расширением. size (:obj:`str`, optional): Размер обложки. """ - await self.client.request.download(f'https://{self.og_image.replace("%%", size)}', filename) + await self.client.request.download(self.get_og_image_url(size), filename) + + def download_cover_bytes(self, size: str = '200x200') -> bytes: + """Загрузка обложки и возврат в виде байтов. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`bytes`: Обложка в виде байтов. + """ + return self.client.request.retrieve(self.get_cover_url(size)) + + async def download_cover_bytes_async(self, size: str = '200x200') -> bytes: + """Загрузка обложки и возврат в виде байтов. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`bytes`: Обложка в виде байтов. + """ + return await self.client.request.retrieve(self.get_cover_url(size)) + + def download_og_image_bytes(self, size: str = '200x200') -> bytes: + """Загрузка обложки и возврат в виде байтов. + + Предпочтительнее использовать `self.download_cover()`. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`bytes`: Обложка в виде байтов. + """ + return self.client.request.retrieve(self.get_og_image_url(size)) + + async def download_og_image_bytes_async(self, size: str = '200x200') -> bytes: + """Загрузка обложки и возврат в виде байтов. + + Предпочтительнее использовать `self.download_cover_async()`. + + Args: + size (:obj:`str`, optional): Размер обложки. + + Returns: + :obj:`bytes`: Обложка в виде байтов. + """ + return await self.client.request.retrieve(self.get_og_image_url(size)) + + def get_specific_download_info(self, codec: str, bitrate_in_kbps: int) -> Optional['DownloadInfo']: + """Возвращает вариант загрузки по критериям. + + Args: + codec (:obj:`str`, optional): Кодек из доступных в `self.download_info`. + bitrate_in_kbps (:obj:`int`, optional): Битрейт из доступных в `self.download_info` для данного кодека. + + Returns: + :obj:`yandex_music.DownloadInfo` | :obj:`None`: Вариант загрузки трека или :obj:`None`. + """ + if self.download_info is None: + self.get_download_info() + + for info in self.download_info: + if info.codec == codec and info.bitrate_in_kbps == bitrate_in_kbps: + return info + return None + + async def get_specific_download_info_async(self, codec: str, bitrate_in_kbps: int) -> Optional['DownloadInfo']: + """Возвращает вариант загрузки по критериям. + + Args: + codec (:obj:`str`, optional): Кодек из доступных в `self.download_info`. + bitrate_in_kbps (:obj:`int`, optional): Битрейт из доступных в `self.download_info` для данного кодека. + + Returns: + :obj:`yandex_music.DownloadInfo` | :obj:`None`: Вариант загрузки трека или :obj:`None`. + """ + if self.download_info is None: + await self.get_download_info_async() + + for info in self.download_info: + if info.codec == codec and info.bitrate_in_kbps == bitrate_in_kbps: + return info + return None def download(self, filename: str, codec: str = 'mp3', bitrate_in_kbps: int = 192) -> None: """Загрузка трека. @@ -210,13 +316,9 @@ class Track(YandexMusicObject): Raises: :class:`yandex_music.exceptions.InvalidBitrateError`: Если в `self.download_info` не найден подходящий трек. """ - if self.download_info is None: - self.get_download_info() - - for info in self.download_info: - if info.codec == codec and info.bitrate_in_kbps == bitrate_in_kbps: - info.download(filename) - break + info = self.get_specific_download_info(codec, bitrate_in_kbps) + if info: + info.download(filename) else: raise InvalidBitrateError('Unavailable bitrate') @@ -236,13 +338,57 @@ class Track(YandexMusicObject): Raises: :class:`yandex_music.exceptions.InvalidBitrateError`: Если в `self.download_info` не найден подходящий трек. """ - if self.download_info is None: - await self.get_download_info_async() + info = await self.get_specific_download_info_async(codec, bitrate_in_kbps) + if info: + await info.download_async(filename) + else: + raise InvalidBitrateError('Unavailable bitrate') - for info in self.download_info: - if info.codec == codec and info.bitrate_in_kbps == bitrate_in_kbps: - await info.download_async(filename) - break + def download_bytes(self, codec: str = 'mp3', bitrate_in_kbps: int = 192) -> bytes: + """Загрузка трека и возврат в виде байтов. + + Note: + Известные значения `codec`: `mp3`, `aac`. + + Известные значения `bitrate_in_kbps`: `64`, `128`, `192`, `320`. + + Args: + codec (:obj:`str`, optional): Кодек из доступных в `self.download_info`. + bitrate_in_kbps (:obj:`int`, optional): Битрейт из доступных в `self.download_info` для данного кодека. + + Raises: + :class:`yandex_music.exceptions.InvalidBitrateError`: Если в `self.download_info` не найден подходящий трек. + + Returns: + :obj:`bytes`: Трек в виде байтов. + """ + info = self.get_specific_download_info(codec, bitrate_in_kbps) + if info: + return info.download_bytes() + else: + raise InvalidBitrateError('Unavailable bitrate') + + async def download_bytes_async(self, codec: str = 'mp3', bitrate_in_kbps: int = 192) -> bytes: + """Загрузка трека и возврат в виде байтов. + + Note: + Известные значения `codec`: `mp3`, `aac`. + + Известные значения `bitrate_in_kbps`: `64`, `128`, `192`, `320`. + + Args: + codec (:obj:`str`, optional): Кодек из доступных в `self.download_info`. + bitrate_in_kbps (:obj:`int`, optional): Битрейт из доступных в `self.download_info` для данного кодека. + + Raises: + :class:`yandex_music.exceptions.InvalidBitrateError`: Если в `self.download_info` не найден подходящий трек. + + Returns: + :obj:`bytes`: Трек в виде байтов. + """ + info = await self.get_specific_download_info_async(codec, bitrate_in_kbps) + if info: + return await info.download_bytes_async() else: raise InvalidBitrateError('Unavailable bitrate')