コミット
07b30cb0b9
|
@ -1,25 +0,0 @@
|
|||
name: Black
|
||||
|
||||
on: [ pull_request ]
|
||||
|
||||
jobs:
|
||||
black:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository.
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Python.
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.7
|
||||
|
||||
- name: Install dependencies.
|
||||
run: pip install black
|
||||
|
||||
- name: Check code style of tests.
|
||||
run: black --config=black.toml --check tests
|
||||
|
||||
- name: Check code style of package.
|
||||
run: black --config=black.toml --check yandex_music
|
|
@ -0,0 +1,29 @@
|
|||
name: Linter and code style check
|
||||
|
||||
on: [ pull_request ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
ruff:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository.
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Python.
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.7
|
||||
|
||||
- name: Run linter check.
|
||||
uses: chartboost/ruff-action@v1
|
||||
with:
|
||||
version: 0.1.6
|
||||
|
||||
- name: Run code style check.
|
||||
uses: chartboost/ruff-action@v1
|
||||
with:
|
||||
version: 0.1.6
|
||||
args: format --check
|
|
@ -39,17 +39,17 @@ PR'ы должны быть сделаны в `main` ветку. Определ
|
|||
|
||||
## Форматирование кода (стиль написания)
|
||||
|
||||
В проекте используется `black`. Не забывайте перед публикацией отформатировать код и проверить его на работоспособность. Используются одинарные кавычки. Запускайте `black` с конфигом из основной директории:
|
||||
В проекте используется `ruff`. Не забывайте перед публикацией отформатировать код и проверить его на работоспособность. Используются одинарные кавычки.
|
||||
|
||||
Запуск линтера:
|
||||
```shell
|
||||
black --config=black.toml yandex_music
|
||||
ruff .
|
||||
```
|
||||
|
||||
или
|
||||
|
||||
Запуск форматера:
|
||||
```shell
|
||||
make black
|
||||
```
|
||||
ruff format .
|
||||
````
|
||||
|
||||
## Создание новых моделей
|
||||
|
||||
|
@ -94,4 +94,4 @@ _Используйте WSL если вы на Windows._
|
|||
make all
|
||||
```
|
||||
|
||||
Выполнит за вас black для основного модуля и тестов, сгенерирует асинхронную версию клиента, сгенерирует camel case псевдонимы.
|
||||
Выполнит за вас ruff и ruff format, сгенерирует асинхронную версию клиента, сгенерирует camel case псевдонимы.
|
||||
|
|
16
Makefile
16
Makefile
|
@ -1,10 +1,10 @@
|
|||
# makefile for Yandex Music project
|
||||
|
||||
black:
|
||||
black --config=black.toml yandex_music
|
||||
ruff:
|
||||
ruff . --fix
|
||||
|
||||
black_test:
|
||||
black --config=black.toml tests
|
||||
ruff_format:
|
||||
ruff format .
|
||||
|
||||
gen_async:
|
||||
python generate_async_version.py
|
||||
|
@ -15,17 +15,11 @@ gen_alias:
|
|||
gen:
|
||||
make gen_async && make gen_alias
|
||||
|
||||
b:
|
||||
make black
|
||||
|
||||
bt:
|
||||
make black_test
|
||||
|
||||
g:
|
||||
make gen
|
||||
|
||||
all:
|
||||
make g && make b && make bt
|
||||
make g && make ruff && make ruff_format
|
||||
|
||||
a:
|
||||
make all
|
||||
|
|
21
black.toml
21
black.toml
|
@ -1,21 +0,0 @@
|
|||
[tool.black]
|
||||
line-length = 120
|
||||
skip-string-normalization=true
|
||||
target-version = ['py37']
|
||||
include = '\.pyi?$'
|
||||
exclude = '''
|
||||
(
|
||||
/(
|
||||
\.eggs
|
||||
| \.git
|
||||
| \.hg
|
||||
| \.mypy_cache
|
||||
| \.tox
|
||||
| \.venv
|
||||
| _build
|
||||
| buck-out
|
||||
| build
|
||||
| dist
|
||||
)/
|
||||
)
|
||||
'''
|
|
@ -49,7 +49,7 @@ exclude_patterns = []
|
|||
|
||||
myst_heading_anchors = 4
|
||||
# https://myst-parser.readthedocs.io/en/latest/syntax/optional.html?highlight=header-anchors#code-fences-using-colons
|
||||
myst_enable_extensions = ["colon_fence"]
|
||||
myst_enable_extensions = ['colon_fence']
|
||||
# TODO add substitution https://myst-parser.readthedocs.io/en/latest/syntax/optional.html?highlight=header-anchors#substitutions-with-jinja2
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
|
|
@ -2,7 +2,6 @@ import os
|
|||
|
||||
from yandex_music import Client
|
||||
|
||||
|
||||
CHART_ID = 'world'
|
||||
TOKEN = os.environ.get('TOKEN')
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import sys
|
||||
import datetime
|
||||
import sys
|
||||
|
||||
from yandex_music.client import Client
|
||||
|
||||
# Help text
|
||||
|
@ -19,7 +20,7 @@ DailyPlaylist = next(
|
|||
|
||||
# Check if we don't need to update it
|
||||
if DailyPlaylist.play_counter.updated:
|
||||
modifiedDate = datetime.datetime.strptime(DailyPlaylist.modified, "%Y-%m-%dT%H:%M:%S%z").date()
|
||||
modifiedDate = datetime.datetime.strptime(DailyPlaylist.modified, '%Y-%m-%dT%H:%M:%S%z').date()
|
||||
if datetime.datetime.now().date() == modifiedDate:
|
||||
print('\x1b[6;30;43m' + 'Looks like it has been already updated today' + '\x1b[0m')
|
||||
quit()
|
||||
|
|
|
@ -2,7 +2,6 @@ import os
|
|||
|
||||
from yandex_music import Client
|
||||
|
||||
|
||||
TOKEN = os.environ.get('TOKEN')
|
||||
ALBUM_ID = 2832563
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ import os
|
|||
from yandex_music import Client
|
||||
from yandex_music.exceptions import NotFoundError
|
||||
|
||||
|
||||
TOKEN = os.environ.get('TOKEN')
|
||||
|
||||
client = Client(TOKEN).init()
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import argparse
|
||||
import re
|
||||
from time import sleep
|
||||
from subprocess import call
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from subprocess import call
|
||||
from time import sleep
|
||||
from typing import List
|
||||
|
||||
from yandex_music import Client
|
||||
|
@ -22,7 +22,7 @@ parser.add_argument('--shuffle', action='store_true', help='randomize tracks ord
|
|||
parser.add_argument(
|
||||
'--token', default=DEFAULT_CACHE_FOLDER / CONFIG_NAME, help='YM API token as string or path to file'
|
||||
)
|
||||
parser.add_argument('--no-save-token', action='store_true', help='do\'nt save token in cache folder')
|
||||
parser.add_argument('--no-save-token', action='store_true', help="do'nt save token in cache folder")
|
||||
parser.add_argument('--cache-folder', type=Path, default=DEFAULT_CACHE_FOLDER, help='cached tracks folder')
|
||||
parser.add_argument('--audio-player', default='cvlc', help='player to use')
|
||||
parser.add_argument(
|
||||
|
@ -43,7 +43,7 @@ if args.print_args:
|
|||
print(args)
|
||||
sys.exit()
|
||||
|
||||
if type(args.token) is str and re.match(r'^[A-Za-z0-9]{39}$', args.token):
|
||||
if isinstance(args.token, str) and re.match(r'^[A-Za-z0-9]{39}$', args.token):
|
||||
if not args.no_save_token:
|
||||
parser.get_default('token').write_text(args.token)
|
||||
else:
|
||||
|
@ -62,7 +62,7 @@ if client.me.account.now and client.me.account.now.split('T')[0] == client.me.ac
|
|||
if args.playlist == 'user':
|
||||
user_playlists = client.users_playlists_list()
|
||||
if not args.playlist_name:
|
||||
print('specify --playlist-name', list(p.title for p in user_playlists))
|
||||
print('specify --playlist-name', [p.title for p in user_playlists])
|
||||
sys.exit(1)
|
||||
playlist = next((p for p in user_playlists if p.title == args.playlist_name), None)
|
||||
if playlist is None:
|
||||
|
@ -82,7 +82,7 @@ if args.shuffle:
|
|||
shuffle(tracks.tracks)
|
||||
|
||||
error_count = 0
|
||||
for (i, short_track) in enumerate(tracks):
|
||||
for i, short_track in enumerate(tracks):
|
||||
if args.skip and args.skip > i:
|
||||
continue
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ proxied_request = Request(proxy_url=os.environ.get('PROXY_URL'))
|
|||
|
||||
try:
|
||||
if not yandex_music_token:
|
||||
raise YandexMusicError()
|
||||
raise YandexMusicError
|
||||
|
||||
# подключаемся без прокси для получения информации об аккаунте (доступно из других стран)
|
||||
client = Client(yandex_music_token, request=Request()).init()
|
||||
|
|
|
@ -60,7 +60,7 @@ class Radio:
|
|||
def __send_play_start_track(self, track, play_id):
|
||||
total_seconds = track.duration_ms / 1000
|
||||
self.client.play_audio(
|
||||
from_="desktop_win-home-playlist_of_the_day-playlist-default",
|
||||
from_='desktop_win-home-playlist_of_the_day-playlist-default',
|
||||
track_id=track.id,
|
||||
album_id=track.albums[0].id,
|
||||
play_id=play_id,
|
||||
|
@ -77,7 +77,7 @@ class Radio:
|
|||
played_seconds = track.duration_ms / 1000
|
||||
total_seconds = track.duration_ms / 1000
|
||||
self.client.play_audio(
|
||||
from_="desktop_win-home-playlist_of_the_day-playlist-default",
|
||||
from_='desktop_win-home-playlist_of_the_day-playlist-default',
|
||||
track_id=track.id,
|
||||
album_id=track.albums[0].id,
|
||||
play_id=play_id,
|
||||
|
@ -91,8 +91,7 @@ class Radio:
|
|||
self.client.rotor_station_feedback_track_finished(
|
||||
station=self.station_id, track_id=track.id, total_played_seconds=played_seconds, batch_id=batch_id
|
||||
)
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def __generate_play_id():
|
||||
return "%s-%s-%s" % (int(random() * 1000), int(random() * 1000), int(random() * 1000))
|
||||
return '%s-%s-%s' % (int(random() * 1000), int(random() * 1000), int(random() * 1000))
|
||||
|
|
|
@ -2,10 +2,10 @@ from math import floor
|
|||
from random import random
|
||||
from time import sleep
|
||||
|
||||
from yandex_music import Client
|
||||
|
||||
from radio import Radio
|
||||
|
||||
from yandex_music import Client
|
||||
|
||||
# API instance
|
||||
client = Client(token='YOUR_TOKEN_HERE')
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
from time import sleep
|
||||
|
||||
from yandex_music import Client
|
||||
|
||||
from radio import Radio
|
||||
|
||||
from yandex_music import Client
|
||||
|
||||
# API instance
|
||||
client = Client(token='YOUR_API_KEY_HERE').init()
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
from yandex_music import Client
|
||||
|
||||
|
||||
client = Client().init()
|
||||
|
||||
type_to_name = {
|
||||
|
@ -15,7 +14,7 @@ type_to_name = {
|
|||
}
|
||||
|
||||
|
||||
def send_search_request_and_print_result(query):
|
||||
def send_search_request_and_print_result(query): # noqa: C901
|
||||
search_result = client.search(query)
|
||||
|
||||
text = [f'Результаты по запросу "{query}":', '']
|
||||
|
@ -35,7 +34,7 @@ def send_search_request_and_print_result(query):
|
|||
elif type_ == 'artist':
|
||||
best_result_text = best.name
|
||||
elif type_ in ['album', 'podcast']:
|
||||
best_result_text = best.title
|
||||
best_result_text = best.title # noqa: SIM114
|
||||
elif type_ == 'playlist':
|
||||
best_result_text = best.title
|
||||
elif type_ == 'video':
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
#!/usr/bin/env python3
|
||||
import subprocess
|
||||
|
||||
|
||||
DISCLAIMER = '# THIS IS AUTO GENERATED COPY OF client.py. DON\'T EDIT IN BY HANDS #'
|
||||
DISCLAIMER = "# THIS IS AUTO GENERATED COPY OF client.py. DON'T EDIT IN BY HANDS #"
|
||||
DISCLAIMER = f'{"#" * len(DISCLAIMER)}\n{DISCLAIMER}\n{"#" * len(DISCLAIMER)}\n\n'
|
||||
|
||||
REQUEST_METHODS = ('_request_wrapper', 'get', 'post', 'retrieve', 'download')
|
||||
|
@ -18,7 +17,7 @@ def gen_request(output_request_filename):
|
|||
code = code.replace('resp.content', 'content')
|
||||
code = code.replace(
|
||||
'resp = requests.request(*args, **kwargs)',
|
||||
f'async with aiohttp.request(*args, **kwargs) as _resp:\n{" " * 16}resp = _resp\n{" " * 16}content = await resp.content.read()',
|
||||
f'async with aiohttp.request(*args, **kwargs) as _resp:\n{" " * 16}resp = _resp\n{" " * 16}content = await resp.content.read()', # noqa: E501
|
||||
)
|
||||
|
||||
code = code.replace('except requests.Timeout', 'except asyncio.TimeoutError')
|
||||
|
@ -32,7 +31,7 @@ def gen_request(output_request_filename):
|
|||
code = code.replace('proxies=self.proxies', 'proxy=self.proxy_url')
|
||||
code = code.replace(
|
||||
"kwargs['timeout'] = self._timeout",
|
||||
f"kwargs['timeout'] = aiohttp.ClientTimeout(total=self._timeout)\n{' ' * 8}else:\n{' ' * 12}kwargs['timeout'] = aiohttp.ClientTimeout(total=kwargs['timeout'])",
|
||||
f"kwargs['timeout'] = aiohttp.ClientTimeout(total=self._timeout)\n{' ' * 8}else:\n{' ' * 12}kwargs['timeout'] = aiohttp.ClientTimeout(total=kwargs['timeout'])", # noqa: E501
|
||||
)
|
||||
|
||||
# download method
|
||||
|
@ -85,4 +84,6 @@ if __name__ == '__main__':
|
|||
gen_client(client_filename)
|
||||
|
||||
for file in (request_filename, client_filename):
|
||||
subprocess.run(['black', '--config', 'black.toml', file])
|
||||
subprocess.run(['ruff', 'format', '--quiet', file]) # noqa: S603, S607
|
||||
subprocess.run(['ruff', '--quiet', '--fix', file]) # noqa: S603, S607
|
||||
subprocess.run(['ruff', 'format', '--quiet', file]) # noqa: S603, S607
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
#!/usr/bin/env python3
|
||||
import os
|
||||
import ast
|
||||
import os
|
||||
|
||||
SOURCE_FOLDER = 'yandex_music'
|
||||
EXCLUDED_FUNCTIONS = {'de_dict', 'de_json', 'de_list', 'de_json_async', 'de_list_async'}
|
||||
|
||||
ALIAS_TEMPLATE = '''
|
||||
ALIAS_TEMPLATE = """
|
||||
#: Псевдоним для :attr:`{name}`
|
||||
{camel_case_name} = {name}
|
||||
'''
|
||||
"""
|
||||
|
||||
ALIAS_SECTION_MARKER = ' # camelCase псевдонимы'
|
||||
|
||||
|
@ -38,9 +38,8 @@ def _generate_code(function_name: str, intent=0) -> str:
|
|||
|
||||
code_lines = [line for line in code.split('\n') if line]
|
||||
code_lines = [f'{" " * intent}{line}' for line in code_lines]
|
||||
code = '\n'.join(code_lines)
|
||||
|
||||
return code
|
||||
return '\n'.join(code_lines)
|
||||
|
||||
|
||||
def _process_file(file: str) -> None:
|
||||
|
@ -52,10 +51,9 @@ def _process_file(file: str) -> None:
|
|||
if isinstance(node, ast.ClassDef):
|
||||
count_of_class_def += 1
|
||||
|
||||
if isinstance(node, ast.FunctionDef) or isinstance(node, ast.AsyncFunctionDef):
|
||||
if _validate_function_name(node.name):
|
||||
alias_code = _generate_code(node.name, node.col_offset)
|
||||
file_aliases_code_fragments.append(alias_code)
|
||||
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)) and _validate_function_name(node.name):
|
||||
alias_code = _generate_code(node.name, node.col_offset)
|
||||
file_aliases_code_fragments.append(alias_code)
|
||||
|
||||
# there are no such cases in data models yet
|
||||
# only in yandex_music/exceptions.py and yandex_music/utils/difference.py
|
||||
|
@ -76,7 +74,7 @@ def _process_file(file: str) -> None:
|
|||
return
|
||||
|
||||
# remove prev aliases
|
||||
file_code_lines = file_code_lines[:marker_lineno + 1]
|
||||
file_code_lines = file_code_lines[: marker_lineno + 1]
|
||||
file_code_lines.append('')
|
||||
file_code_lines.extend(file_aliases_code_fragments)
|
||||
file_code_lines.append('')
|
||||
|
|
|
@ -3,7 +3,7 @@ requests
|
|||
aiohttp
|
||||
aiofiles
|
||||
# rly dev
|
||||
black
|
||||
ruff==0.1.6
|
||||
coverage
|
||||
pytest
|
||||
pytest-cov
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
extend-select = [
|
||||
"E", # pycodestyle errors
|
||||
"W", # pycodestyle warnings
|
||||
"F", # Pyflakes
|
||||
"I", # isort
|
||||
"C90", # flake8-comprehensions
|
||||
"B", # flake8-bugbear
|
||||
"Q", # flake8-quotes
|
||||
"S", # flake8-bandit
|
||||
"ASYNC", # flake8-async
|
||||
# "ANN", # flake8-annotations. Not all resolved yet
|
||||
"C",
|
||||
"BLE",
|
||||
"ERA",
|
||||
"ICN",
|
||||
"INP",
|
||||
"ISC",
|
||||
"NPY",
|
||||
"PGH",
|
||||
"PIE",
|
||||
"RET",
|
||||
"RSE",
|
||||
"SIM",
|
||||
"T20",
|
||||
"TCH",
|
||||
"TID",
|
||||
"YTT",
|
||||
]
|
||||
line-length = 120
|
||||
target-version = "py37"
|
||||
ignore = [
|
||||
"PGH004", # use specific rule code with noqa; works bad with JetBrains IDE Warnings
|
||||
"ANN002", # Missing type annotation for `*args`
|
||||
"ANN003", # Missing type annotation for `**kwargs`
|
||||
"ANN101", # Missing type annotation for `self` in method
|
||||
"ANN102", # Missing type annotation for `cls` in classmethod
|
||||
]
|
||||
|
||||
[per-file-ignores]
|
||||
"examples/*.py" = ["T201", "S311", "ERA001", "INP001", "S106", "BLE001", "S603"]
|
||||
"docs/source/conf.py" = ["INP001"]
|
||||
"tests/*.py" = ["S101"] # Use of assert
|
||||
"tests/__init__.py" = ["F401"] # Unused import
|
||||
"yandex_music/__init__.py" = ["I001"] # Import sort
|
||||
"yandex_music/client*.py" = ["T201"] # print
|
||||
"test.py" = ["S101", "ERA001", "T201", "E501", "F401", "F841"]
|
||||
|
||||
[flake8-quotes]
|
||||
docstring-quotes = "double"
|
||||
multiline-quotes = "double"
|
||||
inline-quotes = "single"
|
||||
|
||||
[format]
|
||||
quote-style = "single"
|
16
setup.py
16
setup.py
|
@ -1,7 +1,7 @@
|
|||
import re
|
||||
import sys
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
from setuptools import find_packages, setup
|
||||
from setuptools.command.test import test
|
||||
|
||||
|
||||
|
@ -41,20 +41,20 @@ setup(
|
|||
'Operating System :: OS Independent',
|
||||
'Topic :: Internet',
|
||||
'Topic :: Multimedia :: Sound/Audio',
|
||||
"Topic :: Software Development :: Libraries",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
"Topic :: Software Development :: Libraries :: Application Frameworks",
|
||||
'Topic :: Software Development :: Libraries',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
'Topic :: Software Development :: Libraries :: Application Frameworks',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Programming Language :: Python :: 3.9',
|
||||
'Programming Language :: Python :: 3.10',
|
||||
'Programming Language :: Python :: 3.11',
|
||||
"Programming Language :: Python :: Implementation",
|
||||
"Programming Language :: Python :: Implementation :: CPython",
|
||||
"Programming Language :: Python :: Implementation :: PyPy",
|
||||
'Programming Language :: Python :: Implementation',
|
||||
'Programming Language :: Python :: Implementation :: CPython',
|
||||
'Programming Language :: Python :: Implementation :: PyPy',
|
||||
],
|
||||
python_requires="~=3.7",
|
||||
python_requires='~=3.7',
|
||||
cmdclass={'test': PyTest},
|
||||
tests_require=['pytest'],
|
||||
project_urls={
|
||||
|
|
|
@ -2,24 +2,32 @@ from .test_account import TestAccount
|
|||
from .test_ad_params import TestAdParams
|
||||
from .test_album import TestAlbum
|
||||
from .test_album_event import TestAlbumEvent
|
||||
from .test_alert import TestAlert
|
||||
from .test_alert_button import TestAlertButton
|
||||
from .test_artist import TestArtist
|
||||
from .test_artist_event import TestArtistEvent
|
||||
from .test_auto_renewable import TestAutoRenewable
|
||||
from .test_best import TestBest
|
||||
from .test_block import TestBlock
|
||||
from .test_block_entity import TestBlockEntity
|
||||
from .test_brand import TestBrand
|
||||
from .test_case_forms import TestCaseForms
|
||||
from .test_chart import TestChart
|
||||
from .test_chart_info import TestChartInfo
|
||||
from .test_chart_info_menu import TestChartInfoMenu
|
||||
from .test_chart_info_menu_item import TestChartInfoMenuItem
|
||||
from .test_contest import TestContest
|
||||
from .test_context import TestContext
|
||||
from .test_counts import TestCounts
|
||||
from .test_cover import TestCover
|
||||
from .test_custom_wave import TestCustomWave
|
||||
from .test_day import TestDay
|
||||
from .test_deactivation import TestDeactivation
|
||||
from .test_deprecation import TestDeprecation
|
||||
from .test_description import TestDescription
|
||||
from .test_discrete_scale import TestDiscreteScale
|
||||
from .test_enum import TestEnum
|
||||
from .test_event import TestEvent
|
||||
from .test_chart_info_menu_item import TestChartInfoMenuItem
|
||||
from .test_chart_info_menu import TestChartInfoMenu
|
||||
from .test_chart_info import TestChartInfo
|
||||
from .test_generated_playlist import TestGeneratedPlaylist
|
||||
from .test_genre import TestGenre
|
||||
from .test_icon import TestIcon
|
||||
|
@ -27,13 +35,19 @@ from .test_id import TestId
|
|||
from .test_images import TestImages
|
||||
from .test_invocation_info import TestInvocationInfo
|
||||
from .test_label import TestLabel
|
||||
from .test_link import TestLink
|
||||
from .test_licence_text_part import TestLicenceTextPart
|
||||
from .test_link import TestLink
|
||||
from .test_lyrics import TestLyrics
|
||||
from .test_lyrics_info import TestLyricsInfo
|
||||
from .test_lyrics_major import TestLyricsMajor
|
||||
from .test_made_for import TestMadeFor
|
||||
from .test_major import TestMajor
|
||||
from .test_meta_data import TestMetaData
|
||||
from .test_mix_link import TestMixLink
|
||||
from .test_non_auto_renewable import TestNonAutoRenewable
|
||||
from .test_normalization import TestNormalization
|
||||
from .test_open_graph_data import TestOpenGraphData
|
||||
from .test_operator import TestOperator
|
||||
from .test_pager import TestPager
|
||||
from .test_passport_phone import TestPassportPhone
|
||||
from .test_permissions import TestPermissions
|
||||
|
@ -44,57 +58,40 @@ from .test_play_counter import TestPlayCounter
|
|||
from .test_playlist import TestPlaylist
|
||||
from .test_playlist_absence import TestPlaylistAbsence
|
||||
from .test_playlist_id import TestPlaylistId
|
||||
from .test_playlist_id import TestPlaylistId
|
||||
from .test_plus import TestPlus
|
||||
from .test_poetry_lover_match import TestPoetryLoverMatch
|
||||
from .test_price import TestPrice
|
||||
from .test_product import TestProduct
|
||||
from .test_promotion import TestPromotion
|
||||
from .test_queue_item import TestQueueItem
|
||||
from .test_r128 import TestR128
|
||||
from .test_ratings import TestRatings
|
||||
from .test_renewable_remainder import TestRenewableRemainder
|
||||
from .test_restrictions import TestRestrictions
|
||||
from .test_rotor_settings import TestRotorSettings
|
||||
from .test_search_result import TestSearchResult
|
||||
from .test_sequence import TestSequence
|
||||
from .test_settings import TestSettings
|
||||
from .test_shot import TestShot
|
||||
from .test_shot_data import TestShotData
|
||||
from .test_shot_type import TestShotType
|
||||
from .test_station import TestStation
|
||||
from .test_station_data import TestStationData
|
||||
from .test_station_result import TestStationResult
|
||||
from .test_status import TestStatus
|
||||
from .test_subscription import TestSubscription
|
||||
from .test_suggestions import TestSuggestions
|
||||
from .test_tag import TestTag
|
||||
from .test_title import TestTitle
|
||||
from .test_track import TestTrack
|
||||
from .test_track_id import TestTrackId
|
||||
from .test_track_lyrics import TestTrackLyrics
|
||||
from .test_track_position import TestTrackPosition
|
||||
from .test_track_short import TestTrackShort
|
||||
from .test_track_short_old import TestTrackShortOld
|
||||
from .test_track_with_ads import TestTrackWithAds
|
||||
from .test_user import TestUser
|
||||
from .test_value import TestValue
|
||||
from .test_value import TestValue
|
||||
from .test_video import TestVideo
|
||||
from .test_video_supplement import TestVideoSupplement
|
||||
from .test_vinyl import TestVinyl
|
||||
from .test_shot_type import TestShotType
|
||||
from .test_shot_data import TestShotData
|
||||
from .test_shot import TestShot
|
||||
from .test_renewable_remainder import TestRenewableRemainder
|
||||
from .test_tag import TestTag
|
||||
from .test_meta_data import TestMetaData
|
||||
from .test_licence_text_part import TestLicenceTextPart
|
||||
from .test_station_data import TestStationData
|
||||
from .test_alert_button import TestAlertButton
|
||||
from .test_alert import TestAlert
|
||||
from .test_non_auto_renewable import TestNonAutoRenewable
|
||||
from .test_poetry_lover_match import TestPoetryLoverMatch
|
||||
from .test_deactivation import TestDeactivation
|
||||
from .test_operator import TestOperator
|
||||
from .test_contest import TestContest
|
||||
from .test_open_graph_data import TestOpenGraphData
|
||||
from .test_brand import TestBrand
|
||||
from .test_context import TestContext
|
||||
from .test_queue_item import TestQueueItem
|
||||
from .test_deprecation import TestDeprecation
|
||||
from .test_lyrics_major import TestLyricsMajor
|
||||
from .test_track_lyrics import TestTrackLyrics
|
||||
from .test_custom_wave import TestCustomWave
|
||||
from .test_r128 import TestR128
|
||||
from .test_lyrics_info import TestLyricsInfo
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
import pytest
|
||||
|
||||
from yandex_music import (
|
||||
R128,
|
||||
Account,
|
||||
AdParams,
|
||||
Album,
|
||||
AlbumEvent,
|
||||
Alert,
|
||||
AlertButton,
|
||||
Artist,
|
||||
ArtistEvent,
|
||||
AutoRenewable,
|
||||
Best,
|
||||
Block,
|
||||
BlockEntity,
|
||||
Brand,
|
||||
CaseForms,
|
||||
Chart,
|
||||
ChartInfo,
|
||||
|
@ -18,10 +22,14 @@ from yandex_music import (
|
|||
ChartInfoMenuItem,
|
||||
ChartItem,
|
||||
Client,
|
||||
Contest,
|
||||
Context,
|
||||
Counts,
|
||||
Cover,
|
||||
CustomWave,
|
||||
Day,
|
||||
Deactivation,
|
||||
Deprecation,
|
||||
Description,
|
||||
DiscreteScale,
|
||||
Enum,
|
||||
|
@ -35,11 +43,16 @@ from yandex_music import (
|
|||
LicenceTextPart,
|
||||
Link,
|
||||
Lyrics,
|
||||
LyricsInfo,
|
||||
LyricsMajor,
|
||||
MadeFor,
|
||||
Major,
|
||||
MetaData,
|
||||
MixLink,
|
||||
NonAutoRenewable,
|
||||
Normalization,
|
||||
OpenGraphData,
|
||||
Operator,
|
||||
Pager,
|
||||
PassportPhone,
|
||||
Permissions,
|
||||
|
@ -51,6 +64,7 @@ from yandex_music import (
|
|||
PlaylistAbsence,
|
||||
PlaylistId,
|
||||
Plus,
|
||||
PoetryLoverMatch,
|
||||
Price,
|
||||
Product,
|
||||
Promotion,
|
||||
|
@ -65,6 +79,7 @@ from yandex_music import (
|
|||
ShotData,
|
||||
ShotType,
|
||||
Station,
|
||||
StationData,
|
||||
StationResult,
|
||||
Status,
|
||||
Subscription,
|
||||
|
@ -72,6 +87,7 @@ from yandex_music import (
|
|||
Title,
|
||||
Track,
|
||||
TrackId,
|
||||
TrackLyrics,
|
||||
TrackPosition,
|
||||
TrackShort,
|
||||
TrackShortOld,
|
||||
|
@ -81,40 +97,33 @@ from yandex_music import (
|
|||
Video,
|
||||
VideoSupplement,
|
||||
Vinyl,
|
||||
StationData,
|
||||
AlertButton,
|
||||
Alert,
|
||||
NonAutoRenewable,
|
||||
PoetryLoverMatch,
|
||||
Deactivation,
|
||||
Operator,
|
||||
Contest,
|
||||
OpenGraphData,
|
||||
Brand,
|
||||
Context,
|
||||
Deprecation,
|
||||
TrackLyrics,
|
||||
LyricsMajor,
|
||||
R128,
|
||||
LyricsInfo,
|
||||
)
|
||||
|
||||
from . import (
|
||||
TestAccount,
|
||||
TestAdParams,
|
||||
TestAlbum,
|
||||
TestAlert,
|
||||
TestAlertButton,
|
||||
TestArtist,
|
||||
TestArtistEvent,
|
||||
TestAutoRenewable,
|
||||
TestBest,
|
||||
TestBlock,
|
||||
TestBlockEntity,
|
||||
TestBrand,
|
||||
TestCaseForms,
|
||||
TestChart,
|
||||
TestChartInfo,
|
||||
TestChartInfoMenuItem,
|
||||
TestContest,
|
||||
TestContext,
|
||||
TestCounts,
|
||||
TestCover,
|
||||
TestCustomWave,
|
||||
TestDay,
|
||||
TestDeactivation,
|
||||
TestDeprecation,
|
||||
TestDescription,
|
||||
TestDiscreteScale,
|
||||
TestEnum,
|
||||
|
@ -128,10 +137,15 @@ from . import (
|
|||
TestLicenceTextPart,
|
||||
TestLink,
|
||||
TestLyrics,
|
||||
TestLyricsInfo,
|
||||
TestLyricsMajor,
|
||||
TestMajor,
|
||||
TestMetaData,
|
||||
TestMixLink,
|
||||
TestNonAutoRenewable,
|
||||
TestNormalization,
|
||||
TestOpenGraphData,
|
||||
TestOperator,
|
||||
TestPager,
|
||||
TestPassportPhone,
|
||||
TestPermissions,
|
||||
|
@ -142,9 +156,11 @@ from . import (
|
|||
TestPlaylistAbsence,
|
||||
TestPlaylistId,
|
||||
TestPlus,
|
||||
TestPoetryLoverMatch,
|
||||
TestPrice,
|
||||
TestProduct,
|
||||
TestPromotion,
|
||||
TestR128,
|
||||
TestRatings,
|
||||
TestRenewableRemainder,
|
||||
TestRotorSettings,
|
||||
|
@ -155,6 +171,7 @@ from . import (
|
|||
TestShotData,
|
||||
TestShotType,
|
||||
TestStation,
|
||||
TestStationData,
|
||||
TestStationResult,
|
||||
TestStatus,
|
||||
TestSubscription,
|
||||
|
@ -162,6 +179,7 @@ from . import (
|
|||
TestTitle,
|
||||
TestTrack,
|
||||
TestTrackId,
|
||||
TestTrackLyrics,
|
||||
TestTrackPosition,
|
||||
TestTrackShort,
|
||||
TestTrackShortOld,
|
||||
|
@ -171,23 +189,6 @@ from . import (
|
|||
TestVideo,
|
||||
TestVideoSupplement,
|
||||
TestVinyl,
|
||||
TestArtistEvent,
|
||||
TestStationData,
|
||||
TestAlertButton,
|
||||
TestAlert,
|
||||
TestNonAutoRenewable,
|
||||
TestPoetryLoverMatch,
|
||||
TestDeactivation,
|
||||
TestOperator,
|
||||
TestContest,
|
||||
TestOpenGraphData,
|
||||
TestBrand,
|
||||
TestContext,
|
||||
TestDeprecation,
|
||||
TestLyricsMajor,
|
||||
TestTrackLyrics,
|
||||
TestR128,
|
||||
TestLyricsInfo,
|
||||
)
|
||||
|
||||
|
||||
|
@ -742,11 +743,6 @@ def playlist_absence():
|
|||
return PlaylistAbsence(TestPlaylistAbsence.kind, TestPlaylistAbsence.reason)
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def results(playlist):
|
||||
return [playlist]
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def context():
|
||||
return Context(TestContext.type_, TestContext.id_, TestContext.description)
|
||||
|
|
|
@ -112,10 +112,10 @@ class TestAlbum:
|
|||
|
||||
def test_de_json_required(self, client):
|
||||
json_dict = {'id': self.id}
|
||||
album = Album.de_json(json_dict, client)
|
||||
Album.de_json(json_dict, client)
|
||||
|
||||
def test_de_json_all(self, client, artist, label, track_position, track, album_without_nested_albums, deprecation):
|
||||
labels = [label] if type(label) == str else [label.to_dict()]
|
||||
labels = [label] if isinstance(label, str) else [label.to_dict()]
|
||||
json_dict = {
|
||||
'id': self.id,
|
||||
'error': self.error,
|
||||
|
|
|
@ -64,7 +64,7 @@ class TestChartInfo:
|
|||
self.id, self.type, self.type_for_from, self.title, self.chart_description, chart_info_menu, playlist
|
||||
)
|
||||
b = ChartInfo(
|
||||
"no_id", self.type, self.type_for_from, self.title, self.chart_description, chart_info_menu, playlist
|
||||
'no_id', self.type, self.type_for_from, self.title, self.chart_description, chart_info_menu, playlist
|
||||
)
|
||||
c = ChartInfo(
|
||||
self.id, self.type, self.type_for_from, self.title, self.chart_description, chart_info_menu, playlist
|
||||
|
|
|
@ -19,7 +19,7 @@ class TestChartInfoMenu:
|
|||
|
||||
def test_equality(self, chart_info_menu_item):
|
||||
a = ChartInfoMenu([chart_info_menu_item])
|
||||
b = ChartInfoMenu([ChartInfoMenuItem("tt", "no_url")])
|
||||
b = ChartInfoMenu([ChartInfoMenuItem('tt', 'no_url')])
|
||||
c = ChartInfoMenu([chart_info_menu_item])
|
||||
|
||||
assert a != b
|
||||
|
|
|
@ -40,7 +40,7 @@ class TestChartInfoMenuItem:
|
|||
|
||||
def test_equality(self):
|
||||
a = ChartInfoMenuItem(self.title, self.url, self.selected)
|
||||
b = ChartInfoMenuItem(self.title, "no_url", self.selected)
|
||||
b = ChartInfoMenuItem(self.title, 'no_url', self.selected)
|
||||
c = ChartInfoMenuItem(self.title, self.url, self.selected)
|
||||
|
||||
assert a != b
|
||||
|
|
|
@ -38,7 +38,7 @@ class TestCover:
|
|||
|
||||
def test_de_json_required(self, client):
|
||||
json_dict = {}
|
||||
cover = Cover.de_json(json_dict, client)
|
||||
Cover.de_json(json_dict, client)
|
||||
|
||||
def test_de_json_all(self, client):
|
||||
json_dict = {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import pytest
|
||||
|
||||
from yandex_music import CustomWave
|
||||
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ class TestGenre:
|
|||
assert genre.weight == self.weight
|
||||
assert genre.composer_top == self.composer_top
|
||||
assert genre.title == self.title
|
||||
assert genre.titles == {"uz": title}
|
||||
assert genre.titles == {'uz': title}
|
||||
assert genre.images == images
|
||||
assert genre.show_in_menu == self.show_in_menu
|
||||
assert genre.show_in_regions == self.show_in_regions
|
||||
|
|
|
@ -14,7 +14,7 @@ class TestImages:
|
|||
|
||||
def test_de_json_required(self, client):
|
||||
json_dict = {}
|
||||
images = Images.de_json(json_dict, client)
|
||||
Images.de_json(json_dict, client)
|
||||
|
||||
def test_de_json_all(self, client):
|
||||
json_dict = {'_208x208': self._208x208, '_300x300': self._300x300}
|
||||
|
|
|
@ -8,7 +8,7 @@ class TestLabel:
|
|||
another_representation_of_label = 'NoCopyrightSounds'
|
||||
|
||||
def test_expected_values(self, label):
|
||||
if type(label) == str:
|
||||
if isinstance(label, str):
|
||||
assert label == self.another_representation_of_label
|
||||
else:
|
||||
assert label.id == self.id
|
||||
|
|
|
@ -8,19 +8,19 @@ class TestLyrics:
|
|||
'Too big, too small?\nSize does matter, after all\nZu groß, zu klein?\nEr könnte etwas größer '
|
||||
'sein\n\nMercedes-Benz und Autobahn\nAlleine in das Ausland fahren\nReise, '
|
||||
'Reise! Fahrvergnügen\nIch will nur Spaß, mich nicht verlieben\n\nJust a little bit...\nJust a '
|
||||
'little, bitch!\n\nYou\'ve got a pussy\nI have a dick, ah.\nSo what\'s the problem?\nLet\'s do it '
|
||||
'quick!\n\nSo take me now, before it\'s too late\nLife\'s too short, so I can\'t wait\nTake me now! '
|
||||
'Oh, don\'t you see?\nI can\'t get laid in Germany…\n\nToo short, too tall?\nDoesn\'t matter, '
|
||||
"little, bitch!\n\nYou've got a pussy\nI have a dick, ah.\nSo what's the problem?\nLet's do it "
|
||||
"quick!\n\nSo take me now, before it's too late\nLife's too short, so I can't wait\nTake me now! "
|
||||
"Oh, don't you see?\nI can't get laid in Germany…\n\nToo short, too tall?\nDoesn't matter, "
|
||||
'one size fits all\nZu groß, zu klein?\nDer Schlagbaum sollte oben sein\n\nSchönes Fräulein, '
|
||||
'Lust auf mehr\nBlitzkrieg mit dem Fleischgewehr\nSchnaps im Kopf, du holde Braut\nSteck Bratwurst '
|
||||
'in dein Sauerkraut\n\nJust a little bit...\nBe my little bitch!\n\nYou\'ve got a pussy\nI have a '
|
||||
'dick, ah\nSo what\'s the problem?\nLet\'s do it quick!\n\nSo take me now, before it\'s too '
|
||||
'late\nLife\'s too short, so I can\'t wait\nTake me now! Oh, don\'t you see?\nI can\'t get laid in '
|
||||
'Germany…\n\nGermany! Germany!\n\nYou\'ve got a pussy\nI have a dick, ah\nSo what\'s the '
|
||||
'problem?\nLet\'s do it quick!\n\nYou\'ve got a pussy\nI have a dick, ah\nSo what\'s the '
|
||||
'problem?\nLet\'s do it quick!\n\nYou\'ve got a pussy\nI have a dick, ah\nSo what\'s the '
|
||||
'problem?\nLet\'s do it quick!\n\nSo take me now, before it\'s too late\nLife\'s too short, '
|
||||
'so I can\'t wait\nTake me now! Oh, don\'t you see?\nI can\'t get laid in Germany…\n '
|
||||
"in dein Sauerkraut\n\nJust a little bit...\nBe my little bitch!\n\nYou've got a pussy\nI have a "
|
||||
"dick, ah\nSo what's the problem?\nLet's do it quick!\n\nSo take me now, before it's too "
|
||||
"late\nLife's too short, so I can't wait\nTake me now! Oh, don't you see?\nI can't get laid in "
|
||||
"Germany…\n\nGermany! Germany!\n\nYou've got a pussy\nI have a dick, ah\nSo what's the "
|
||||
"problem?\nLet's do it quick!\n\nYou've got a pussy\nI have a dick, ah\nSo what's the "
|
||||
"problem?\nLet's do it quick!\n\nYou've got a pussy\nI have a dick, ah\nSo what's the "
|
||||
"problem?\nLet's do it quick!\n\nSo take me now, before it's too late\nLife's too short, "
|
||||
"so I can't wait\nTake me now! Oh, don't you see?\nI can't get laid in Germany…\n "
|
||||
)
|
||||
has_rights = True
|
||||
text_language = 'de'
|
||||
|
|
|
@ -35,7 +35,7 @@ class TestMetaData:
|
|||
'Можете величать меня исчадьем ада\nМожете линчевать меня, мыча как стадо\nНо на мне нет печати зла, '
|
||||
'сгущать не надо\nКраски. Я счастлив, что я не раб мещанских взглядов\nМожете обличать меня, крича с экрана'
|
||||
'\nМожете исключать меня из ваших кланов\nНо вы же сами не без греха. Признай, что я был\nК несчастью таким'
|
||||
' же, как ты. Ша!\nМолчать и на пол!\n\nСпасибо Kaas\'у, так что не смейте обвинять меня в плагиате\nВсе'
|
||||
" же, как ты. Ша!\nМолчать и на пол!\n\nСпасибо Kaas'у, так что не смейте обвинять меня в плагиате\nВсе"
|
||||
' сейчас на Одноклассниках, ВКонтакте\nНо далеко не все одноклассники в контакте\nПонимаете, о чем идет'
|
||||
' речь?\nЙее, Оксимирон. В Лондоне наконец-то солнце'
|
||||
)
|
||||
|
|
|
@ -8,7 +8,7 @@ class TestMixLink:
|
|||
text_color = '#6c65a9'
|
||||
background_color = 'transparent'
|
||||
background_image_uri = (
|
||||
'avatars.yandex.net/get-music-misc/28592/mix.5cf0bd5e58ea3a1e70caa07b.' 'background-image.1559281047248/%%'
|
||||
'avatars.yandex.net/get-music-misc/28592/mix.5cf0bd5e58ea3a1e70caa07b.background-image.1559281047248/%%'
|
||||
)
|
||||
cover_white = 'avatars.yandex.net/get-music-misc/28052/mix.5cf0bd5e58ea3a1e70caa07b.cover-white.1559281049219/%%'
|
||||
cover_uri = 'avatars.yandex.net/get-music-misc/34161/mix.57c6d15a2d3213a86ac653d2.cover.1555818786846/%%'
|
||||
|
|
|
@ -27,7 +27,7 @@ class TestPlaylist:
|
|||
id_for_from = 'playlist_of_the_day'
|
||||
dummy_description = 'Слушайте интересные подкасты, чтобы мы могли узнать вас получше и\\xa0собрать этот плейлист'
|
||||
dummy_page_description = (
|
||||
'Чтобы собрать для вас этот плейлист, мы должны узнать ' 'вас чуточку поближе. Слушайте больше!'
|
||||
'Чтобы собрать для вас этот плейлист, мы должны узнать вас чуточку поближе. Слушайте больше!'
|
||||
)
|
||||
metrika_id = 666666
|
||||
coauthors = [1130000003905541]
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import pytest
|
||||
|
||||
from yandex_music import R128
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ from yandex_music import StationData
|
|||
|
||||
|
||||
class TestStationData:
|
||||
name = 'Marshal\'s station'
|
||||
name = "Marshal's station"
|
||||
|
||||
def test_expected_values(self, station_data):
|
||||
assert station_data.name == self.name
|
||||
|
|
|
@ -51,7 +51,7 @@ class TestStationTracksResult:
|
|||
|
||||
def test_equality(self, id_, sequence):
|
||||
a = StationTracksResult(id_, sequence, self.batch_id, self.pumpkin)
|
||||
b = StationTracksResult(id_, sequence, "", False)
|
||||
b = StationTracksResult(id_, sequence, '', False)
|
||||
c = StationTracksResult(id_, sequence, self.batch_id, self.pumpkin)
|
||||
|
||||
assert a != b
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import pytest
|
||||
|
||||
from tests import TestBest
|
||||
|
||||
from yandex_music import Suggestions, Best
|
||||
from yandex_music import Best, Suggestions
|
||||
|
||||
|
||||
@pytest.fixture(scope='class', params=[1, 2, 3, 4, 5])
|
||||
|
|
|
@ -266,6 +266,7 @@ __all__ = [
|
|||
'QueueItem',
|
||||
'Deprecation',
|
||||
'TrackLyrics',
|
||||
'LyricsMajor',
|
||||
'CustomWave',
|
||||
'R128',
|
||||
'LyricsInfo',
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
@ -26,7 +26,8 @@ class Account(YandexMusicObject):
|
|||
passport_phones (:obj:`list` из :obj:`yandex_music.PassportPhone`): Мобильные номера.
|
||||
registered_at (:obj:`str`, optional): Дата создания учётной записи.
|
||||
has_info_for_app_metrica (:obj:`bool`, optional): Наличие информации для App Metrica.
|
||||
child (:obj:`bool`): Дочерний / детский аккаунт (скорее детский, позволяет ограничить доступный контент ребенку на Кинопоиске).
|
||||
child (:obj:`bool`): Дочерний / детский аккаунт (скорее детский, позволяет ограничить
|
||||
доступный контент ребенку на Кинопоиске).
|
||||
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
|
||||
**kwargs: Произвольные ключевые аргументы полученные от API.
|
||||
"""
|
||||
|
|
|
@ -4,7 +4,7 @@ from yandex_music import YandexMusicObject
|
|||
from yandex_music.utils import model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from yandex_music import Client, AlertButton
|
||||
from yandex_music import AlertButton, Client
|
||||
|
||||
|
||||
@model
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import List, TYPE_CHECKING, Optional
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import List, TYPE_CHECKING, Optional
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
@ -102,7 +102,7 @@ class Product(YandexMusicObject):
|
|||
return None
|
||||
|
||||
data = super(Product, cls).de_json(data, client)
|
||||
from yandex_music import Price, LicenceTextPart
|
||||
from yandex_music import LicenceTextPart, Price
|
||||
|
||||
data['price'] = Price.de_json(data.get('price'), client)
|
||||
data['intro_price'] = Price.de_json(data.get('intro_price'), client)
|
||||
|
|
|
@ -4,7 +4,7 @@ from yandex_music import YandexMusicObject
|
|||
from yandex_music.utils import model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from yandex_music import Client, Account, Permissions, Subscription, Plus, StationData, Alert
|
||||
from yandex_music import Account, Alert, Client, Permissions, Plus, StationData, Subscription
|
||||
|
||||
|
||||
@model
|
||||
|
@ -69,7 +69,7 @@ class Status(YandexMusicObject):
|
|||
return None
|
||||
|
||||
data = super(Status, cls).de_json(data, client)
|
||||
from yandex_music import Account, Permissions, Plus, Subscription, StationData, Alert
|
||||
from yandex_music import Account, Alert, Permissions, Plus, StationData, Subscription
|
||||
|
||||
data['account'] = Account.de_json(data.get('account'), client)
|
||||
data['permissions'] = Permissions.de_json(data.get('permissions'), client)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from yandex_music import Client, AutoRenewable, RenewableRemainder, NonAutoRenewable, Operator
|
||||
from yandex_music import AutoRenewable, Client, NonAutoRenewable, Operator, RenewableRemainder
|
||||
|
||||
|
||||
@model
|
||||
|
@ -53,7 +53,7 @@ class Subscription(YandexMusicObject):
|
|||
return None
|
||||
|
||||
data = super(Subscription, cls).de_json(data, client)
|
||||
from yandex_music import AutoRenewable, RenewableRemainder, NonAutoRenewable, Operator
|
||||
from yandex_music import AutoRenewable, NonAutoRenewable, Operator, RenewableRemainder
|
||||
|
||||
data['auto_renewable'] = AutoRenewable.de_list(data.get('auto_renewable'), client)
|
||||
data['family_auto_renewable'] = AutoRenewable.de_list(data.get('family_auto_renewable'), client)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from typing import Any, TYPE_CHECKING, Optional, List, Union
|
||||
from typing import TYPE_CHECKING, Any, List, Optional, Union
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from yandex_music import Client, Artist, Label, TrackPosition, Track, Deprecation
|
||||
from yandex_music import Artist, Client, Deprecation, Label, Track, TrackPosition
|
||||
|
||||
|
||||
@model
|
||||
|
@ -299,7 +299,7 @@ class Album(YandexMusicObject):
|
|||
return None
|
||||
|
||||
data = super(Album, cls).de_json(data, client)
|
||||
from yandex_music import Artist, Label, TrackPosition, Track, Deprecation
|
||||
from yandex_music import Artist, Deprecation, Label, Track, TrackPosition
|
||||
|
||||
data['artists'] = Artist.de_list(data.get('artists'), client)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List, Union
|
||||
from typing import TYPE_CHECKING, List, Optional, Union
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
@ -58,7 +58,7 @@ class Label(YandexMusicObject):
|
|||
if not cls.is_valid_model_data(data, array=True):
|
||||
return []
|
||||
|
||||
labels = list()
|
||||
labels = []
|
||||
for label in data:
|
||||
if isinstance(label, dict):
|
||||
labels.append(cls.de_json(label, client))
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from typing import Any, TYPE_CHECKING, Optional, List, Union
|
||||
from typing import TYPE_CHECKING, Any, List, Optional, Union
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from yandex_music import Client, Cover, Ratings, Counts, Link, Track, Description, ArtistTracks, ArtistAlbums
|
||||
from yandex_music import ArtistAlbums, ArtistTracks, Client, Counts, Cover, Description, Link, Ratings, Track
|
||||
|
||||
|
||||
@model
|
||||
|
@ -266,7 +266,7 @@ class Artist(YandexMusicObject):
|
|||
return None
|
||||
|
||||
data = super(Artist, cls).de_json(data, client)
|
||||
from yandex_music import Cover, Ratings, Counts, Link, Track, Description
|
||||
from yandex_music import Counts, Cover, Description, Link, Ratings, Track
|
||||
|
||||
data['cover'] = Cover.de_json(data.get('cover'), client)
|
||||
data['ratings'] = Ratings.de_json(data.get('ratings'), client)
|
||||
|
@ -297,7 +297,7 @@ class Artist(YandexMusicObject):
|
|||
if not cls.is_valid_model_data(data, array=True):
|
||||
return []
|
||||
|
||||
artists = list()
|
||||
artists = []
|
||||
for artist in data:
|
||||
artists.append(cls.de_json(artist, client))
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from typing import TYPE_CHECKING, Optional, List, Iterator
|
||||
from typing import TYPE_CHECKING, Iterator, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from yandex_music import Client, Album, Pager
|
||||
from yandex_music import Album, Client, Pager
|
||||
|
||||
|
||||
@model
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from typing import TYPE_CHECKING, Optional, List, Iterator
|
||||
from typing import TYPE_CHECKING, Iterator, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from yandex_music import Client, Track, Pager
|
||||
from yandex_music import Client, Pager, Track
|
||||
|
||||
|
||||
@model
|
||||
|
@ -48,7 +48,7 @@ class ArtistTracks(YandexMusicObject):
|
|||
return None
|
||||
|
||||
data = super(ArtistTracks, cls).de_json(data, client)
|
||||
from yandex_music import Track, Pager
|
||||
from yandex_music import Pager, Track
|
||||
|
||||
data['tracks'] = Track.de_list(data.get('tracks'), client)
|
||||
data['pager'] = Pager.de_json(data.get('pager'), client)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from typing import Any, TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, Any, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from yandex_music import Client, Artist, Track, Album, Cover, PlaylistId, Video, Chart, Vinyl, Playlist
|
||||
from yandex_music import Album, Artist, Chart, Client, Cover, Playlist, PlaylistId, Track, Video, Vinyl
|
||||
|
||||
|
||||
@model
|
||||
|
@ -79,7 +79,7 @@ class BriefInfo(YandexMusicObject):
|
|||
return None
|
||||
|
||||
data = super(BriefInfo, cls).de_json(data, client)
|
||||
from yandex_music import Artist, Track, Album, Cover, PlaylistId, Video, Chart, Vinyl, Playlist
|
||||
from yandex_music import Album, Artist, Chart, Cover, Playlist, PlaylistId, Track, Video, Vinyl
|
||||
|
||||
data['playlists'] = Playlist.de_list(data.get('playlists'), client)
|
||||
data['artist'] = Artist.de_json(data.get('artist'), client)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
@ -63,7 +63,7 @@ class Link(YandexMusicObject):
|
|||
if not cls.is_valid_model_data(data, array=True):
|
||||
return []
|
||||
|
||||
links = list()
|
||||
links = []
|
||||
for link in data:
|
||||
links.append(cls.de_json(link, client))
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
@ -78,7 +78,7 @@ class Vinyl(YandexMusicObject):
|
|||
if not cls.is_valid_model_data(data, array=True):
|
||||
return []
|
||||
|
||||
vinyls = list()
|
||||
vinyls = []
|
||||
for vinyl in data:
|
||||
vinyls.append(cls.de_json(vinyl, client))
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import dataclasses
|
||||
import logging
|
||||
import keyword
|
||||
import logging
|
||||
from abc import ABCMeta
|
||||
from typing import TYPE_CHECKING, Optional, Any
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from yandex_music import Client
|
||||
|
@ -67,8 +67,8 @@ class YandexMusicObject:
|
|||
|
||||
fields = {f.name for f in dataclasses.fields(cls)}
|
||||
|
||||
cleaned_data = dict()
|
||||
unknown_data = dict()
|
||||
cleaned_data = {}
|
||||
unknown_data = {}
|
||||
|
||||
for k, v in data.items():
|
||||
if k in fields:
|
||||
|
@ -110,12 +110,11 @@ class YandexMusicObject:
|
|||
def parse(val):
|
||||
if hasattr(val, 'to_dict'):
|
||||
return val.to_dict(for_request)
|
||||
elif isinstance(val, list):
|
||||
if isinstance(val, list):
|
||||
return [parse(it) for it in val]
|
||||
elif isinstance(val, dict):
|
||||
if isinstance(val, dict):
|
||||
return {key: parse(value) for key, value in val.items()}
|
||||
else:
|
||||
return val
|
||||
return val
|
||||
|
||||
data = self.__dict__.copy()
|
||||
data.pop('client', None)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import functools
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional, Union, TypeVar, Callable, Any
|
||||
from typing import Any, Callable, Dict, List, Optional, TypeVar, Union
|
||||
|
||||
from yandex_music import (
|
||||
Album,
|
||||
|
@ -9,36 +9,36 @@ from yandex_music import (
|
|||
ArtistAlbums,
|
||||
ArtistTracks,
|
||||
BriefInfo,
|
||||
ChartInfo,
|
||||
Dashboard,
|
||||
DownloadInfo,
|
||||
Experiments,
|
||||
Feed,
|
||||
Genre,
|
||||
Landing,
|
||||
LandingList,
|
||||
Like,
|
||||
PermissionAlerts,
|
||||
Playlist,
|
||||
PlaylistRecommendations,
|
||||
PromoCodeStatus,
|
||||
Queue,
|
||||
QueueItem,
|
||||
Search,
|
||||
Settings,
|
||||
ShotEvent,
|
||||
Supplement,
|
||||
SimilarTracks,
|
||||
StationResult,
|
||||
StationTracksResult,
|
||||
Status,
|
||||
Suggestions,
|
||||
SimilarTracks,
|
||||
TrackLyrics,
|
||||
Supplement,
|
||||
TagResult,
|
||||
Track,
|
||||
TrackLyrics,
|
||||
TracksList,
|
||||
UserSettings,
|
||||
YandexMusicObject,
|
||||
ChartInfo,
|
||||
TagResult,
|
||||
PlaylistRecommendations,
|
||||
LandingList,
|
||||
QueueItem,
|
||||
Queue,
|
||||
__copyright__,
|
||||
__license__,
|
||||
__version__,
|
||||
|
@ -855,13 +855,11 @@ class Client(YandexMusicObject):
|
|||
data = {'kinds': kind}
|
||||
|
||||
result = self._request.post(url, data, *args, **kwargs)
|
||||
|
||||
return Playlist.de_list(result, self)
|
||||
else:
|
||||
url = f'{self.base_url}/users/{user_id}/playlists/{kind}'
|
||||
result = self._request.get(url, *args, **kwargs)
|
||||
|
||||
return Playlist.de_json(result, self)
|
||||
url = f'{self.base_url}/users/{user_id}/playlists/{kind}'
|
||||
result = self._request.get(url, *args, **kwargs)
|
||||
return Playlist.de_json(result, self)
|
||||
|
||||
@log
|
||||
def users_playlists_recommendations(self, kind: Union[str, int], user_id: Union[str, int] = None, *args, **kwargs):
|
||||
|
@ -2196,7 +2194,7 @@ class Client(YandexMusicObject):
|
|||
action = 'remove' if remove else 'add-multiple'
|
||||
url = f'{self.base_url}/users/{user_id}/dislikes/tracks/{action}'
|
||||
|
||||
result = self._request.post(url, {f'track-ids': ids}, *args, **kwargs)
|
||||
result = self._request.post(url, {'track-ids': ids}, *args, **kwargs)
|
||||
|
||||
return 'revision' in result
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
import functools
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional, Union, TypeVar, Callable, Any
|
||||
from typing import Any, Callable, Dict, List, Optional, TypeVar, Union
|
||||
|
||||
from yandex_music import (
|
||||
Album,
|
||||
|
@ -13,36 +13,36 @@ from yandex_music import (
|
|||
ArtistAlbums,
|
||||
ArtistTracks,
|
||||
BriefInfo,
|
||||
ChartInfo,
|
||||
Dashboard,
|
||||
DownloadInfo,
|
||||
Experiments,
|
||||
Feed,
|
||||
Genre,
|
||||
Landing,
|
||||
LandingList,
|
||||
Like,
|
||||
PermissionAlerts,
|
||||
Playlist,
|
||||
PlaylistRecommendations,
|
||||
PromoCodeStatus,
|
||||
Queue,
|
||||
QueueItem,
|
||||
Search,
|
||||
Settings,
|
||||
ShotEvent,
|
||||
Supplement,
|
||||
SimilarTracks,
|
||||
StationResult,
|
||||
StationTracksResult,
|
||||
Status,
|
||||
Suggestions,
|
||||
SimilarTracks,
|
||||
TrackLyrics,
|
||||
Supplement,
|
||||
TagResult,
|
||||
Track,
|
||||
TrackLyrics,
|
||||
TracksList,
|
||||
UserSettings,
|
||||
YandexMusicObject,
|
||||
ChartInfo,
|
||||
TagResult,
|
||||
PlaylistRecommendations,
|
||||
LandingList,
|
||||
QueueItem,
|
||||
Queue,
|
||||
__copyright__,
|
||||
__license__,
|
||||
__version__,
|
||||
|
@ -861,13 +861,11 @@ class ClientAsync(YandexMusicObject):
|
|||
data = {'kinds': kind}
|
||||
|
||||
result = await self._request.post(url, data, *args, **kwargs)
|
||||
|
||||
return Playlist.de_list(result, self)
|
||||
else:
|
||||
url = f'{self.base_url}/users/{user_id}/playlists/{kind}'
|
||||
result = await self._request.get(url, *args, **kwargs)
|
||||
|
||||
return Playlist.de_json(result, self)
|
||||
url = f'{self.base_url}/users/{user_id}/playlists/{kind}'
|
||||
result = await self._request.get(url, *args, **kwargs)
|
||||
return Playlist.de_json(result, self)
|
||||
|
||||
@log
|
||||
async def users_playlists_recommendations(
|
||||
|
@ -2214,7 +2212,7 @@ class ClientAsync(YandexMusicObject):
|
|||
action = 'remove' if remove else 'add-multiple'
|
||||
url = f'{self.base_url}/users/{user_id}/dislikes/tracks/{action}'
|
||||
|
||||
result = await self._request.post(url, {f'track-ids': ids}, *args, **kwargs)
|
||||
result = await self._request.post(url, {'track-ids': ids}, *args, **kwargs)
|
||||
|
||||
return 'revision' in result
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
@ -132,7 +132,7 @@ class Cover(YandexMusicObject):
|
|||
if not cls.is_valid_model_data(data, array=True):
|
||||
return []
|
||||
|
||||
covers = list()
|
||||
covers = []
|
||||
for cover in data:
|
||||
covers.append(cls.de_json(cover, client))
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
|
||||
from hashlib import md5
|
||||
import xml.dom.minidom as minidom
|
||||
from hashlib import md5
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from yandex_music import Client
|
||||
from xml.dom.minicompat import NodeList
|
||||
|
||||
from yandex_music import Client
|
||||
|
||||
SIGN_SALT = 'XGRlBW9FXlekgbPrRHuSiA'
|
||||
|
||||
|
||||
|
@ -40,7 +40,7 @@ class DownloadInfo(YandexMusicObject):
|
|||
self._id_attrs = (self.codec, self.bitrate_in_kbps, self.gain, self.preview, self.download_info_url)
|
||||
|
||||
@staticmethod
|
||||
def _get_text_node_data(elements: 'NodeList') -> str:
|
||||
def _get_text_node_data(elements: 'NodeList') -> Optional[str]:
|
||||
""":obj:`str`: Получение текстовой информации из узлов XML элемента."""
|
||||
for element in elements:
|
||||
nodes = element.childNodes
|
||||
|
@ -48,13 +48,15 @@ class DownloadInfo(YandexMusicObject):
|
|||
if node.nodeType == node.TEXT_NODE:
|
||||
return node.data
|
||||
|
||||
return None
|
||||
|
||||
def __build_direct_link(self, xml: str) -> str:
|
||||
doc = minidom.parseString(xml)
|
||||
doc = minidom.parseString(xml) # noqa: S318
|
||||
host = self._get_text_node_data(doc.getElementsByTagName('host'))
|
||||
path = self._get_text_node_data(doc.getElementsByTagName('path'))
|
||||
ts = self._get_text_node_data(doc.getElementsByTagName('ts'))
|
||||
s = self._get_text_node_data(doc.getElementsByTagName('s'))
|
||||
sign = md5((SIGN_SALT + path[1::] + s).encode('utf-8')).hexdigest()
|
||||
sign = md5((SIGN_SALT + path[1::] + s).encode('utf-8')).hexdigest() # noqa: S324
|
||||
|
||||
return f'https://{host}/get-mp3/{sign}/{ts}{path}'
|
||||
|
||||
|
@ -165,7 +167,7 @@ class DownloadInfo(YandexMusicObject):
|
|||
if not cls.is_valid_model_data(data, array=True):
|
||||
return []
|
||||
|
||||
downloads_info = list()
|
||||
downloads_info = []
|
||||
for download_info in data:
|
||||
downloads_info.append(cls.de_json(download_info, client))
|
||||
|
||||
|
@ -190,7 +192,7 @@ class DownloadInfo(YandexMusicObject):
|
|||
if not cls.is_valid_model_data(data, array=True):
|
||||
return []
|
||||
|
||||
downloads_info = list()
|
||||
downloads_info = []
|
||||
for download_info in data:
|
||||
downloads_info.append(cls.de_json(download_info, client))
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from yandex_music import Client, Album, Track
|
||||
from yandex_music import Album, Client, Track
|
||||
|
||||
|
||||
@model
|
||||
|
@ -60,7 +60,7 @@ class AlbumEvent(YandexMusicObject):
|
|||
if not cls.is_valid_model_data(data, array=True):
|
||||
return []
|
||||
|
||||
album_events = list()
|
||||
album_events = []
|
||||
for album_event in data:
|
||||
album_events.append(cls.de_json(album_event, client))
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from yandex_music import Client, Artist, Track
|
||||
from yandex_music import Artist, Client, Track
|
||||
|
||||
|
||||
@model
|
||||
|
@ -65,7 +65,7 @@ class ArtistEvent(YandexMusicObject):
|
|||
if not cls.is_valid_model_data(data, array=True):
|
||||
return []
|
||||
|
||||
artist_events = list()
|
||||
artist_events = []
|
||||
for artist_event in data:
|
||||
artist_events.append(cls.de_json(artist_event, client))
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
@ -65,7 +65,7 @@ class Day(YandexMusicObject):
|
|||
if not cls.is_valid_model_data(data, array=True):
|
||||
return []
|
||||
|
||||
days = list()
|
||||
days = []
|
||||
for day in data:
|
||||
days.append(cls.de_json(day, client))
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from yandex_music import Client, Track, AlbumEvent, ArtistEvent
|
||||
from yandex_music import AlbumEvent, ArtistEvent, Client, Track
|
||||
|
||||
|
||||
@model
|
||||
|
@ -67,7 +67,7 @@ class Event(YandexMusicObject):
|
|||
return None
|
||||
|
||||
data = super(Event, cls).de_json(data, client)
|
||||
from yandex_music import Track, AlbumEvent, ArtistEvent
|
||||
from yandex_music import AlbumEvent, ArtistEvent, Track
|
||||
|
||||
data['tracks'] = Track.de_list(data.get('tracks'), client)
|
||||
data['albums'] = AlbumEvent.de_list(data.get('albums'), client)
|
||||
|
@ -89,7 +89,7 @@ class Event(YandexMusicObject):
|
|||
if not cls.is_valid_model_data(data, array=True):
|
||||
return []
|
||||
|
||||
events = list()
|
||||
events = []
|
||||
for event in data:
|
||||
events.append(cls.de_json(event, client))
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from yandex_music import Client, GeneratedPlaylist, Day
|
||||
from yandex_music import Client, Day, GeneratedPlaylist
|
||||
|
||||
|
||||
@model
|
||||
|
@ -54,7 +54,7 @@ class Feed(YandexMusicObject):
|
|||
return None
|
||||
|
||||
data = super(Feed, cls).de_json(data, client)
|
||||
from yandex_music import GeneratedPlaylist, Day
|
||||
from yandex_music import Day, GeneratedPlaylist
|
||||
|
||||
data['generated_playlists'] = GeneratedPlaylist.de_list(data.get('generated_playlists'), client)
|
||||
data['days'] = Day.de_list(data.get('days'), client)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
@ -62,7 +62,7 @@ class TrackWithAds(YandexMusicObject):
|
|||
if not cls.is_valid_model_data(data, array=True):
|
||||
return []
|
||||
|
||||
tracks_with_ads = list()
|
||||
tracks_with_ads = []
|
||||
for track_with_ads in data:
|
||||
tracks_with_ads.append(cls.de_json(track_with_ads, client))
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from typing import TYPE_CHECKING, Optional, List, Dict
|
||||
from typing import TYPE_CHECKING, Dict, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from yandex_music import Client, Title, Icon, Images
|
||||
from yandex_music import Client, Icon, Images, Title
|
||||
|
||||
|
||||
@model
|
||||
|
@ -63,7 +63,7 @@ class Genre(YandexMusicObject):
|
|||
return None
|
||||
|
||||
data = super(Genre, cls).de_json(data, client)
|
||||
from yandex_music import Title, Icon, Images
|
||||
from yandex_music import Icon, Images, Title
|
||||
|
||||
data['titles'] = Title.de_dict(data.get('titles'), client)
|
||||
data['images'] = Images.de_json(data.get('images'), client)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, Dict
|
||||
from typing import TYPE_CHECKING, Dict, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
@ -56,7 +56,7 @@ class Title(YandexMusicObject):
|
|||
if not data:
|
||||
return {}
|
||||
|
||||
titles = dict()
|
||||
titles = {}
|
||||
for lang, title in data.items():
|
||||
titles.update({lang: cls.de_json(title, client)})
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from typing import TYPE_CHECKING, Optional, List, Union
|
||||
from typing import TYPE_CHECKING, List, Optional, Union
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from yandex_music import Client, BlockEntity, PersonalPlaylistsData, PlayContextsData
|
||||
from yandex_music import BlockEntity, Client, PersonalPlaylistsData, PlayContextsData
|
||||
|
||||
|
||||
@model
|
||||
|
@ -56,7 +56,7 @@ class Block(YandexMusicObject):
|
|||
return None
|
||||
|
||||
data = super(Block, cls).de_json(data, client)
|
||||
from yandex_music import BlockEntity, PlayContextsData, PersonalPlaylistsData
|
||||
from yandex_music import BlockEntity, PersonalPlaylistsData, PlayContextsData
|
||||
|
||||
data['entities'] = BlockEntity.de_list(data.get('entities'), client)
|
||||
|
||||
|
@ -82,7 +82,7 @@ class Block(YandexMusicObject):
|
|||
if not cls.is_valid_model_data(data, array=True):
|
||||
return []
|
||||
|
||||
blocks = list()
|
||||
blocks = []
|
||||
for block in data:
|
||||
blocks.append(cls.de_json(block, client))
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
from typing import TYPE_CHECKING, Optional, List, Union
|
||||
from typing import TYPE_CHECKING, List, Optional, Union
|
||||
|
||||
from yandex_music import (
|
||||
YandexMusicObject,
|
||||
Promotion,
|
||||
Album,
|
||||
Playlist,
|
||||
MixLink,
|
||||
PlayContext,
|
||||
ChartItem,
|
||||
GeneratedPlaylist,
|
||||
MixLink,
|
||||
PlayContext,
|
||||
Playlist,
|
||||
Promotion,
|
||||
YandexMusicObject,
|
||||
)
|
||||
from yandex_music.utils import model
|
||||
|
||||
|
@ -86,7 +86,7 @@ class BlockEntity(YandexMusicObject):
|
|||
if not cls.is_valid_model_data(data, array=True):
|
||||
return []
|
||||
|
||||
entities = list()
|
||||
entities = []
|
||||
for entity in data:
|
||||
entities.append(cls.de_json(entity, client))
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject, Playlist, ChartInfoMenu
|
||||
from yandex_music import ChartInfoMenu, Playlist, YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject, ChartInfoMenuItem
|
||||
from yandex_music import ChartInfoMenuItem, YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from yandex_music import Client, Track, Chart
|
||||
from yandex_music import Chart, Client, Track
|
||||
|
||||
|
||||
@model
|
||||
|
@ -60,7 +60,7 @@ class ChartItem(YandexMusicObject):
|
|||
if not cls.is_valid_model_data(data, array=True):
|
||||
return []
|
||||
|
||||
tracks = list()
|
||||
tracks = []
|
||||
for track in data:
|
||||
tracks.append(cls.de_json(track, client))
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from typing import TYPE_CHECKING, Optional, List, Union
|
||||
from typing import TYPE_CHECKING, List, Optional, Union
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from yandex_music import Client, Block
|
||||
from yandex_music import Block, Client
|
||||
|
||||
|
||||
@model
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
@ -40,7 +40,7 @@ class LandingList(YandexMusicObject):
|
|||
self._id_attrs = (self.id, self.new_releases, self.new_playlists, self.podcasts)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: dict, client: 'Client') -> Optional['Chart']:
|
||||
def de_json(cls, data: dict, client: 'Client') -> Optional['LandingList']:
|
||||
"""Десериализация объекта.
|
||||
|
||||
Args:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.exceptions import YandexMusicError
|
||||
|
@ -71,7 +71,7 @@ class MixLink(YandexMusicObject):
|
|||
"""
|
||||
|
||||
if not self.cover_white:
|
||||
raise YandexMusicError('You can\'t get cover white because it\'s None.')
|
||||
raise YandexMusicError("You can't get cover white because it's None.")
|
||||
|
||||
return f'https://{self.cover_white.replace("%%", size)}'
|
||||
|
||||
|
@ -238,7 +238,7 @@ class MixLink(YandexMusicObject):
|
|||
if not cls.is_valid_model_data(data, array=True):
|
||||
return []
|
||||
|
||||
mix_links = list()
|
||||
mix_links = []
|
||||
for mix_link in data:
|
||||
mix_links.append(cls.de_json(mix_link, client))
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
@ -136,7 +136,7 @@ class Promotion(YandexMusicObject):
|
|||
if not cls.is_valid_model_data(data, array=True):
|
||||
return []
|
||||
|
||||
promotions = list()
|
||||
promotions = []
|
||||
for promotion in data:
|
||||
promotions.append(cls.de_json(promotion, client))
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from yandex_music import Client, Track
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
@ -64,7 +64,7 @@ class TrackShortOld(YandexMusicObject):
|
|||
if not cls.is_valid_model_data(data, array=True):
|
||||
return []
|
||||
|
||||
tracks = list()
|
||||
tracks = []
|
||||
for track in data:
|
||||
tracks.append(cls.de_json(track, client))
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import List, Optional, TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import Album, Artist, Playlist, YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
@ -95,7 +95,7 @@ class Like(YandexMusicObject):
|
|||
if not cls.is_valid_model_data(data, array=True):
|
||||
return []
|
||||
|
||||
likes = list()
|
||||
likes = []
|
||||
for like in data:
|
||||
likes.append(cls.de_json(like, client, type_))
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Any, TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
|
|
@ -4,7 +4,7 @@ from yandex_music import YandexMusicObject
|
|||
from yandex_music.utils import model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from yandex_music import Client, User, CaseForms
|
||||
from yandex_music import CaseForms, Client, User
|
||||
|
||||
|
||||
@model
|
||||
|
@ -39,7 +39,7 @@ class MadeFor(YandexMusicObject):
|
|||
return None
|
||||
|
||||
data = super(MadeFor, cls).de_json(data, client)
|
||||
from yandex_music import User, CaseForms
|
||||
from yandex_music import CaseForms, User
|
||||
|
||||
data['user_info'] = User.de_json(data.get('user_info'), client)
|
||||
data['case_forms'] = CaseForms.de_json(data.get('case_forms'), client)
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
from typing import Any, TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, Any, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from yandex_music import (
|
||||
Client,
|
||||
User,
|
||||
Cover,
|
||||
MadeFor,
|
||||
TrackShort,
|
||||
PlaylistAbsence,
|
||||
PlayCounter,
|
||||
PlaylistRecommendations,
|
||||
Artist,
|
||||
TrackId,
|
||||
Contest,
|
||||
OpenGraphData,
|
||||
Brand,
|
||||
Pager,
|
||||
Client,
|
||||
Contest,
|
||||
Cover,
|
||||
CustomWave,
|
||||
MadeFor,
|
||||
OpenGraphData,
|
||||
Pager,
|
||||
PlayCounter,
|
||||
PlaylistAbsence,
|
||||
PlaylistRecommendations,
|
||||
TrackId,
|
||||
TrackShort,
|
||||
User,
|
||||
)
|
||||
|
||||
|
||||
|
@ -353,24 +353,24 @@ class Playlist(YandexMusicObject):
|
|||
"""
|
||||
return (await self.client.users_playlists(self.kind, self.owner.uid, *args, **kwargs)).tracks
|
||||
|
||||
def insert_track(self, track_id: int, album_id: int, *args, **kwargs) -> Optional['Playlist']:
|
||||
def insert_track(self, track_id: int, album_id: int, **kwargs) -> Optional['Playlist']:
|
||||
"""Сокращение для::
|
||||
|
||||
client.users_playlists_insert_track(self.kind, track_id, album_id, user_id=self.owner.uid,
|
||||
revision=self.revision, *args, **kwargs)
|
||||
"""
|
||||
return self.client.users_playlists_insert_track(
|
||||
self.kind, track_id, album_id, user_id=self.owner.uid, revision=self.revision, *args, **kwargs
|
||||
self.kind, track_id, album_id, user_id=self.owner.uid, revision=self.revision, **kwargs
|
||||
)
|
||||
|
||||
async def insert_track_async(self, track_id: int, album_id: int, *args, **kwargs) -> Optional['Playlist']:
|
||||
async def insert_track_async(self, track_id: int, album_id: int, **kwargs) -> Optional['Playlist']:
|
||||
"""Сокращение для::
|
||||
|
||||
await client.users_playlists_insert_track(self.kind, track_id, album_id, user_id=self.owner.uid,
|
||||
revision=self.revision, *args, **kwargs)
|
||||
"""
|
||||
return await self.client.users_playlists_insert_track(
|
||||
self.kind, track_id, album_id, user_id=self.owner.uid, revision=self.revision, *args, **kwargs
|
||||
self.kind, track_id, album_id, user_id=self.owner.uid, revision=self.revision, **kwargs
|
||||
)
|
||||
|
||||
def delete_tracks(self, from_: int, to: int, *args, **kwargs) -> Optional['Playlist']:
|
||||
|
@ -421,19 +421,19 @@ class Playlist(YandexMusicObject):
|
|||
|
||||
data = super(Playlist, cls).de_json(data, client)
|
||||
from yandex_music import (
|
||||
User,
|
||||
MadeFor,
|
||||
Cover,
|
||||
PlayCounter,
|
||||
TrackShort,
|
||||
PlaylistAbsence,
|
||||
Artist,
|
||||
TrackId,
|
||||
Contest,
|
||||
OpenGraphData,
|
||||
Brand,
|
||||
Contest,
|
||||
Cover,
|
||||
CustomWave,
|
||||
MadeFor,
|
||||
OpenGraphData,
|
||||
Pager,
|
||||
PlayCounter,
|
||||
PlaylistAbsence,
|
||||
TrackId,
|
||||
TrackShort,
|
||||
User,
|
||||
)
|
||||
|
||||
data['owner'] = User.de_json(data.get('owner'), client)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
@ -74,7 +74,7 @@ class PlaylistId(YandexMusicObject):
|
|||
if not cls.is_valid_model_data(data, array=True):
|
||||
return []
|
||||
|
||||
playlist_ids = list()
|
||||
playlist_ids = []
|
||||
for playlist_id in data:
|
||||
playlist_ids.append(cls.de_json(playlist_id, client))
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
@ -39,7 +39,7 @@ class TagResult(YandexMusicObject):
|
|||
return None
|
||||
|
||||
data = super(TagResult, cls).de_json(data, client)
|
||||
from yandex_music import Tag, PlaylistId
|
||||
from yandex_music import PlaylistId, Tag
|
||||
|
||||
data['tag'] = Tag.de_json(data.get('tag'), client)
|
||||
data['ids'] = PlaylistId.de_list(data.get('ids'), client)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from typing import List, TYPE_CHECKING, Optional
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from yandex_music import YandexMusicObject
|
||||
from yandex_music.utils import model
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from yandex_music import Client, TrackId, Context
|
||||
from yandex_music import Client, Context, TrackId
|
||||
|
||||
|
||||
@model
|
||||
|
@ -50,7 +50,7 @@ class Queue(YandexMusicObject):
|
|||
if not cls.is_valid_model_data(data):
|
||||
return None
|
||||
|
||||
from yandex_music import TrackId, Context
|
||||
from yandex_music import Context, TrackId
|
||||
|
||||
data = super(Queue, cls).de_json(data, client)
|
||||
data['tracks'] = TrackId.de_list(data.get('tracks'), client)
|
||||
|
|
変更されたファイルが多すぎるため、一部のファイルは表示されません さらに表示
読み込み中…
新しいイシューから参照