Sort_YM/sort_ym/apply.py
Andrew Pimenov 942c2d19e4 retry network errors and raise request timeout
Медленная/нестабильная сеть до api.music.yandex.net роняла весь процесс
при первом же таймауте (5с по умолчанию у библиотеки). Добавлен
with_retries с экспоненциальной паузой на всех сетевых точках входа
(fetch, language, genres, apply, client.init), таймаут запроса поднят
до 20с (настраивается в config.toml). Заодно поправлен скрытый баг:
language.py раньше кэшировал таймаут как "текста нет" навсегда -
теперь только настоящий NotFoundError трактуется так.
2026-07-06 10:05:22 +03:00

71 lines
2.2 KiB
Python

from __future__ import annotations
import time
from yandex_music import Client, Playlist
from .ymclient import with_retries
def _existing_playlists_by_title(client: Client) -> dict[str, Playlist]:
playlists = with_retries(lambda: client.users_playlists_list())
return {p.title: p for p in playlists if p.title}
def _existing_track_ids(client: Client, playlist: Playlist) -> set[str]:
full = with_retries(lambda: client.users_playlists(playlist.kind))
if full is None:
return set()
return {t.track_id for t in full.tracks}
def _get_or_create_playlist(client: Client, title: str, existing: dict[str, Playlist]) -> Playlist:
if title in existing:
return existing[title]
playlist = with_retries(lambda: client.users_playlists_create(title, visibility="private"))
existing[title] = playlist
return playlist
def apply_classification(
client: Client,
rows: list[dict],
delay: float,
limit: int | None = None,
) -> None:
if limit is not None:
rows = rows[:limit]
existing_playlists = _existing_playlists_by_title(client)
by_playlist: dict[str, list[dict]] = {}
for row in rows:
by_playlist.setdefault(row["target_playlist"], []).append(row)
for title, playlist_rows in by_playlist.items():
playlist = _get_or_create_playlist(client, title, existing_playlists)
already = _existing_track_ids(client, playlist)
revision = playlist.revision or 1
added = 0
for row in playlist_rows:
track_key = f"{row['id']}:{row['album_id']}" if row["album_id"] else str(row["id"])
if track_key in already:
continue
updated = with_retries(
lambda: client.users_playlists_insert_track(
playlist.kind,
row["id"],
row["album_id"],
revision=revision,
)
)
if updated is not None and updated.revision is not None:
revision = updated.revision
already.add(track_key)
added += 1
time.sleep(delay)
skipped = len(playlist_rows) - added
print(f"{title}: добавлено {added}, уже было {skipped}")