/
/
/
1"""Constants for the Yandex Music provider."""
2
3from __future__ import annotations
4
5from typing import Final
6
7# Configuration Keys
8CONF_TOKEN = "token"
9CONF_QUALITY = "quality"
10CONF_BASE_URL = "base_url"
11
12# Actions
13CONF_ACTION_AUTH = "auth"
14CONF_ACTION_CLEAR_AUTH = "clear_auth"
15
16# Labels
17LABEL_TOKEN = "token_label"
18LABEL_AUTH_INSTRUCTIONS = "auth_instructions_label"
19
20# API defaults
21DEFAULT_LIMIT: Final[int] = 50
22DEFAULT_BASE_URL: Final[str] = "https://api.music.yandex.net"
23
24# Quality options (matching reference implementation)
25QUALITY_EFFICIENT = "efficient" # Low quality, efficient bandwidth (~64kbps AAC)
26QUALITY_BALANCED = "balanced" # Medium quality, balanced performance (~192kbps AAC)
27QUALITY_HIGH = "high" # High quality, lossy (~320kbps MP3)
28QUALITY_SUPERB = "superb" # Highest quality, lossless (FLAC)
29
30# Configuration keys for My Wave behavior (kept)
31CONF_MY_WAVE_MAX_TRACKS: Final[str] = "my_wave_max_tracks"
32
33# Configuration keys for Liked Tracks behavior (kept)
34CONF_LIKED_TRACKS_MAX_TRACKS: Final[str] = "liked_tracks_max_tracks"
35
36# Hardcoded default values for removed config entries
37MY_WAVE_BATCH_SIZE: Final[int] = 3
38TRACK_BATCH_SIZE: Final[int] = 50
39DISCOVERY_INITIAL_TRACKS: Final[int] = 20
40BROWSE_INITIAL_TRACKS: Final[int] = 15
41
42# Image sizes
43IMAGE_SIZE_SMALL = "200x200"
44IMAGE_SIZE_MEDIUM = "400x400"
45IMAGE_SIZE_LARGE = "1000x1000"
46
47# Locale-aware provider display names for owner normalization
48PROVIDER_DISPLAY_NAME_RU: Final[str] = "Ð¯Ð½Ð´ÐµÐºÑ ÐÑзÑка"
49PROVIDER_DISPLAY_NAME_EN: Final[str] = "Yandex Music"
50
51# Known API-returned system owner name variants (all locales/capitalizations)
52# All entries are lowercase; compare with owner_name.lower() for case-insensitive lookup
53YANDEX_SYSTEM_OWNER_NAMES: Final[frozenset[str]] = frozenset(
54 {
55 "ÑÐ½Ð´ÐµÐºÑ Ð¼ÑзÑка",
56 "ÑндекÑ.мÑзÑка",
57 "yandex.music",
58 "yandexmusic",
59 "yandex music",
60 }
61)
62
63# ID separators
64PLAYLIST_ID_SPLITTER: Final[str] = ":"
65
66# Rotor (radio) station identifiers
67ROTOR_STATION_MY_WAVE: Final[str] = "user:onyourwave"
68
69# Virtual playlist ID for My Wave (used in get_playlist / get_playlist_tracks; not owner_id:kind)
70MY_WAVE_PLAYLIST_ID: Final[str] = "my_wave"
71
72# Virtual playlist ID for Liked Tracks
73LIKED_TRACKS_PLAYLIST_ID: Final[str] = "liked_tracks"
74
75# Composite item_id for My Wave tracks: track_id + separator + station_id (for rotor feedback)
76RADIO_TRACK_ID_SEP: Final[str] = "@"
77
78# Browse folder names by locale (item_id -> display name)
79BROWSE_NAMES_RU: Final[dict[str, str]] = {
80 "my_wave": "ÐÐ¾Ñ Ð²Ð¾Ð»Ð½Ð°",
81 "artists": "Ðои иÑполниÑели",
82 "albums": "Ðои алÑбомÑ",
83 "tracks": "Ðне нÑавиÑÑÑ",
84 "playlists": "Ðои плейлиÑÑÑ",
85 "feed": "ÐÐ»Ñ Ð²Ð°Ñ",
86 "chart": "ЧаÑÑ",
87 "new_releases": "Ðовинки",
88 "new_playlists": "ÐовÑе плейлиÑÑÑ",
89 # Picks & Mixes
90 "picks": "ÐодбоÑки",
91 "mixes": "ÐикÑÑ",
92 "mood": "ÐаÑÑÑоение",
93 "activity": "ÐкÑивноÑÑÑ",
94 "era": "ÐпоÑ
а",
95 "genres": "ÐанÑÑ",
96 # Mood tags
97 "chill": "РаÑÑлаблÑÑÑее",
98 "sad": "ÐÑÑÑÑное",
99 "romantic": "РоманÑиÑеÑкое",
100 "party": "ÐеÑеÑинка",
101 "relax": "РелакÑ",
102 # Activity tags
103 "workout": "ТÑениÑовка",
104 "focus": "ÐонÑенÑÑаÑиÑ",
105 "morning": "УÑÑо",
106 "evening": "ÐеÑеÑ",
107 "driving": "РдоÑоге", # noqa: RUF001
108 # Era tags
109 "80s": "80-е", # noqa: RUF001
110 "90s": "90-е", # noqa: RUF001
111 "2000s": "2000-е", # noqa: RUF001
112 "retro": "РеÑÑо",
113 # Genre tags
114 "rock": "Рок",
115 "jazz": "Ðжаз",
116 "classical": "ÐлаÑÑика",
117 "electronic": "ÐлекÑÑоника",
118 "rnb": "R&B",
119 "hiphop": "Хип-Ñ
оп",
120 "top": "Топ",
121 "newbies": "Ðо жанÑÑ",
122 # Landing-discovered tags
123 "in the mood": "РнаÑÑÑоение", # noqa: RUF001
124 "background": "ÐоÑлÑÑаÑÑ Ñоном",
125 # Seasonal tags
126 "winter": "Ðима",
127 "summer": "ÐеÑо",
128 "autumn": "ÐÑенÑ",
129 "spring": "ÐеÑна",
130 "newyear": "ÐовÑй год",
131 # Liked Tracks
132 "liked_tracks": "Ðне нÑавиÑÑÑ",
133 # Discovery
134 "top_picks": "Топ подбоÑки",
135 "mood_mix": "ÐаÑÑÑоение",
136 "activity_mix": "ÐкÑивноÑÑÑ",
137 "seasonal_mix": "Сезонное",
138 # Top-level browse groups
139 "for_you": "ÐÐ»Ñ Ð²Ð°Ñ",
140 "collection": "ÐоллекÑиÑ",
141 # Waves / Radio (rotor station categories)
142 "waves": "Радио",
143 "radio": "Радио",
144 "my_waves": "ÐеÑÑоналÑнÑе",
145 "my_waves_set": "AI СеÑÑ",
146 "waves_landing": "ÐзбÑаннÑе волнÑ",
147 "genre": "ÐанÑÑ",
148 "epoch": "ÐпоÑ
а",
149 "local": "ÐеÑÑное",
150}
151BROWSE_NAMES_EN: Final[dict[str, str]] = {
152 "my_wave": "My Wave",
153 "artists": "My Artists",
154 "albums": "My Albums",
155 "tracks": "My Favorites",
156 "playlists": "My Playlists",
157 "feed": "Made for You",
158 "chart": "Chart",
159 "new_releases": "New Releases",
160 "new_playlists": "New Playlists",
161 # Picks & Mixes
162 "picks": "Picks",
163 "mixes": "Mixes",
164 "mood": "Mood",
165 "activity": "Activity",
166 "era": "Era",
167 "genres": "Genres",
168 # Mood tags
169 "chill": "Chill",
170 "sad": "Sad",
171 "romantic": "Romantic",
172 "party": "Party",
173 "relax": "Relax",
174 # Activity tags
175 "workout": "Workout",
176 "focus": "Focus",
177 "morning": "Morning",
178 "evening": "Evening",
179 "driving": "Driving",
180 # Era tags
181 "80s": "80s",
182 "90s": "90s",
183 "2000s": "2000s",
184 "retro": "Retro",
185 # Genre tags
186 "rock": "Rock",
187 "jazz": "Jazz",
188 "classical": "Classical",
189 "electronic": "Electronic",
190 "rnb": "R&B",
191 "hiphop": "Hip-Hop",
192 "top": "Top",
193 "newbies": "By Genre",
194 # Landing-discovered tags
195 "in the mood": "In the Mood",
196 "background": "Background",
197 # Seasonal tags
198 "winter": "Winter",
199 "summer": "Summer",
200 "autumn": "Autumn",
201 "spring": "Spring",
202 "newyear": "New Year",
203 # Liked Tracks
204 "liked_tracks": "My Favorites",
205 # Discovery
206 "top_picks": "Top Picks",
207 "mood_mix": "Mood Mix",
208 "activity_mix": "Activity Mix",
209 "seasonal_mix": "Seasonal",
210 # Top-level browse groups
211 "for_you": "For You",
212 "collection": "Collection",
213 # Waves / Radio (rotor station categories)
214 "waves": "Radio",
215 "radio": "Radio",
216 "my_waves": "Personal",
217 "my_waves_set": "AI Wave Sets",
218 "waves_landing": "Featured Waves",
219 "genre": "Genres",
220 "epoch": "Era",
221 "local": "Local",
222}
223
224# Tag categories for Picks and Recommendations
225# Used by _get_valid_tags_for_category to validate tags at runtime.
226TAG_CATEGORY_MOOD: Final[list[str]] = [
227 "chill",
228 "sad",
229 "romantic",
230 "party",
231 "relax",
232 "in the mood",
233]
234TAG_CATEGORY_ACTIVITY: Final[list[str]] = [
235 "workout",
236 "focus",
237 "morning",
238 "evening",
239 "driving",
240 "background",
241]
242TAG_CATEGORY_ERA: Final[list[str]] = ["80s", "90s", "2000s", "retro"]
243TAG_CATEGORY_GENRES: Final[list[str]] = [
244 "rock",
245 "jazz",
246 "classical",
247 "electronic",
248 "rnb",
249 "hiphop",
250 "top",
251 "newbies",
252]
253
254# Tag slug -> display category mapping
255# Used to categorize dynamically discovered tags into browse folders.
256# Tags not in this mapping default to "mood" category.
257TAG_SLUG_CATEGORY: Final[dict[str, str]] = {
258 # Mood
259 "chill": "mood",
260 "sad": "mood",
261 "romantic": "mood",
262 "party": "mood",
263 "relax": "mood",
264 "in the mood": "mood",
265 # Activity
266 "workout": "activity",
267 "focus": "activity",
268 "morning": "activity",
269 "evening": "activity",
270 "driving": "activity",
271 "background": "activity",
272 # Era
273 "80s": "era",
274 "90s": "era",
275 "2000s": "era",
276 "retro": "era",
277 # Genres
278 "rock": "genres",
279 "jazz": "genres",
280 "classical": "genres",
281 "electronic": "genres",
282 "rnb": "genres",
283 "hiphop": "genres",
284 "top": "genres",
285 "newbies": "genres",
286 # Seasonal (for mixes)
287 "winter": "seasonal",
288 "spring": "seasonal",
289 "summer": "seasonal",
290 "autumn": "seasonal",
291 "newyear": "seasonal",
292}
293
294# Preferred tag order within categories (discovered tags sorted by this)
295TAG_CATEGORY_ORDER: Final[dict[str, list[str]]] = {
296 "mood": ["chill", "sad", "romantic", "party", "relax", "in the mood"],
297 "activity": ["workout", "focus", "morning", "evening", "driving", "background"],
298 "era": ["80s", "90s", "2000s", "retro"],
299 "genres": ["rock", "jazz", "classical", "electronic", "rnb", "hiphop", "top", "newbies"],
300}
301
302# Seasonal tags mapped to months (month number -> tag)
303TAG_SEASONAL_MAP: Final[dict[int, str]] = {
304 1: "winter", # January
305 2: "winter", # February
306 3: "spring", # March (validated at runtime; falls back to autumn if unavailable)
307 4: "spring", # April
308 5: "spring", # May
309 6: "summer", # June
310 7: "summer", # July
311 8: "summer", # August
312 9: "autumn", # September
313 10: "autumn", # October
314 11: "autumn", # November
315 12: "winter", # December
316}
317
318# Tags for Mixes (seasonal collections)
319TAG_MIXES: Final[list[str]] = ["winter", "spring", "summer", "autumn", "newyear"]
320
321# Waves by tag (rotor stations) â canonical ID is "waves", "radio" is an alias
322WAVES_FOLDER_ID: Final[str] = "waves"
323RADIO_FOLDER_ID: Final[str] = "radio"
324
325# Personalized waves subfolder (rotor/stations/dashboard)
326MY_WAVES_FOLDER_ID: Final[str] = "my_waves"
327
328# AI Wave Sets subfolder (from /landing-blocks/mixes-waves)
329MY_WAVES_SET_FOLDER_ID: Final[str] = "my_waves_set"
330
331# Featured Waves subfolder inside Radio (from /landing-blocks/waves)
332WAVES_LANDING_FOLDER_ID: Final[str] = "waves_landing"
333
334# Top-level browse group folders
335FOR_YOU_FOLDER_ID: Final[str] = "for_you"
336COLLECTION_FOLDER_ID: Final[str] = "collection"
337
338# Preferred display order for wave categories (rotor station types)
339WAVE_CATEGORY_DISPLAY_ORDER: Final[list[str]] = [
340 "genre",
341 "mood",
342 "activity",
343 "epoch",
344 "local",
345]
346