2019-06-01 15:04:15 +09:00
|
|
|
|
from enum import Enum
|
2020-03-22 20:58:25 +09:00
|
|
|
|
from typing import List, Union
|
2019-06-01 15:04:15 +09:00
|
|
|
|
|
2019-12-23 18:07:11 +09:00
|
|
|
|
ujson = False
|
|
|
|
|
try:
|
|
|
|
|
import ujson as json
|
2021-02-03 21:28:10 +09:00
|
|
|
|
|
2019-12-23 18:07:11 +09:00
|
|
|
|
ujson = True
|
|
|
|
|
except ImportError:
|
|
|
|
|
import json
|
|
|
|
|
|
2019-06-01 15:04:15 +09:00
|
|
|
|
|
|
|
|
|
class Operation(Enum):
|
2020-03-22 20:58:25 +09:00
|
|
|
|
"""Класс перечисления типов операций для изменения плейлиста.
|
|
|
|
|
|
|
|
|
|
Note:
|
|
|
|
|
Существует две операции: вставка, удаление.
|
|
|
|
|
"""
|
|
|
|
|
|
2019-06-01 15:04:15 +09:00
|
|
|
|
INSERT = 'insert'
|
|
|
|
|
DELETE = 'delete'
|
|
|
|
|
|
|
|
|
|
|
2019-08-18 18:54:13 +09:00
|
|
|
|
class Difference:
|
2020-03-22 21:29:38 +09:00
|
|
|
|
"""Класс, представляющий обёртку над созданием данных для запроса изменения плейлиста.
|
|
|
|
|
|
|
|
|
|
Note:
|
|
|
|
|
Результатом является перечень (массив) операций, которые будут применены к плейлисту.
|
|
|
|
|
|
|
|
|
|
Конечной разницей (набором операций) является JSON, который будет отправлен в теле запроса.
|
|
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
|
operations (:obj:`list` из :obj:`dict`): Перечень операция для изменения плейлиста.
|
|
|
|
|
"""
|
|
|
|
|
|
2019-06-01 15:04:15 +09:00
|
|
|
|
def __init__(self):
|
|
|
|
|
self.operations = []
|
|
|
|
|
|
2020-03-22 21:29:38 +09:00
|
|
|
|
def to_json(self) -> str:
|
|
|
|
|
"""Сериализация всех операций над плейлистом.
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
:obj:`str`: Сформированное тело для запроса.
|
|
|
|
|
"""
|
2019-12-23 18:07:11 +09:00
|
|
|
|
return json.dumps(self.operations, ensure_ascii=not ujson)
|
2019-06-01 15:04:15 +09:00
|
|
|
|
|
2020-03-22 21:32:04 +09:00
|
|
|
|
def add_delete(self, from_: int, to: int) -> 'Difference':
|
2020-03-22 21:29:38 +09:00
|
|
|
|
"""Добавление операции удаления.
|
|
|
|
|
|
|
|
|
|
Note:
|
|
|
|
|
Передаётся диапазон для удаления треков.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
from_ (:obj:`int`): С какого индекса.
|
|
|
|
|
to (:obj:`int`): По какой индекс.
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
:obj:`yandex_music.utils.difference.Difference`: Набор операций над плейлистом.
|
|
|
|
|
"""
|
2021-02-03 21:28:10 +09:00
|
|
|
|
operation = {'op': Operation.DELETE.value, 'from': from_, 'to': to}
|
2019-06-01 15:04:15 +09:00
|
|
|
|
|
|
|
|
|
self.operations.append(operation)
|
|
|
|
|
return self
|
|
|
|
|
|
2020-03-22 21:32:04 +09:00
|
|
|
|
def add_insert(self, at: int, tracks: Union[dict, List[dict]]) -> 'Difference':
|
2020-03-22 21:29:38 +09:00
|
|
|
|
"""Добавление операции вставки.
|
|
|
|
|
|
|
|
|
|
Note:
|
|
|
|
|
В `tracks` передаётся словарь с двумя ключами: `id`, `album_id`. Это нужно для формирования операции.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
at (:obj:`int`): Индекс для вставки.
|
|
|
|
|
tracks (:obj:`dict` | :obj:`list: из :obj:`dict`): Словарь уникальными идентификаторами треков.
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
:obj:`yandex_music.utils.difference.Difference`: Набор операций над плейлистом.
|
|
|
|
|
"""
|
2022-11-01 00:12:59 +09:00
|
|
|
|
# TODO (MarshalX) принимать TrackId, а так же строку и сплитить её по ":".
|
|
|
|
|
# При отсутствии album_id кидать исключение.
|
|
|
|
|
# https://github.com/MarshalX/yandex-music-api/issues/558
|
2019-06-01 15:04:15 +09:00
|
|
|
|
if not isinstance(tracks, list):
|
|
|
|
|
tracks = [tracks]
|
|
|
|
|
|
2021-02-03 21:28:10 +09:00
|
|
|
|
operation = {'op': Operation.INSERT.value, 'at': at, 'tracks': []}
|
2019-06-01 15:04:15 +09:00
|
|
|
|
|
|
|
|
|
for track in tracks:
|
2022-11-01 00:12:59 +09:00
|
|
|
|
# TODO (MarshalX) replace to normal TrackId object
|
|
|
|
|
# https://github.com/MarshalX/yandex-music-api/issues/558
|
|
|
|
|
track = type('TrackId', (), track)
|
2019-06-01 15:04:15 +09:00
|
|
|
|
|
2021-02-03 21:28:10 +09:00
|
|
|
|
operation['tracks'].append({'id': track.id, 'albumId': track.album_id})
|
2019-06-01 15:04:15 +09:00
|
|
|
|
|
|
|
|
|
self.operations.append(operation)
|
|
|
|
|
return self
|