feat(seekbar+ratings): 5 new seekbar styles and entity/mix rating system (PR #130)

Seekbar styles (5 new, by Psychotoxical):
- Neon Glow: transparent track, played section as multi-layer glowing neon tube
- Pulse Wave: flat line with animated gaussian sine pulse at playhead (rAF)
- Particle Trail: particles spawn at playhead and drift with glow (rAF)
- Liquid Fill: glass tube fills with liquid and animated wave surface (rAF)
- Retro Tape: two spinning reels connected by tape, shrink/grow with progress (rAF)

Ratings system (PR #130 by cucadmuh):
- Shared StarRating component with pulse/clear animations, disabled/locked states
- Entity ratings for albums and artists via OpenSubsonic probe (setEntityRatingSupport)
- Skip→1★: after N consecutive manual skips, set unrated track to 1★ (persisted per server)
- Mix rating filter: exclude low-rated songs/albums/artists from RandomMix, RandomAlbums, Hero, Home
- Batch refill in fetchRandomMixSongsUntilFull to fill list despite strict filters
- Prefetch artist/album ratings via getArtist/getAlbum for incomplete list payloads
- Settings: new Ratings section for skip threshold and per-axis mix filter stars
- i18n: all 7 languages (en, de, fr, nl, zh, nb, ru)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Psychotoxical
2026-04-08 10:29:21 +02:00
30 changed files with 1806 additions and 126 deletions
+27
View File
@@ -147,6 +147,13 @@ export const ruTranslation = {
ratingLabel: 'Оценка',
enlargeCover: 'Увеличить обложку',
},
entityRating: {
albumShort: 'Оценка альбома',
artistShort: 'Оценка исполнителя',
albumAriaLabel: 'Оценка альбома',
artistAriaLabel: 'Оценка исполнителя',
saveFailed: 'Не удалось сохранить оценку.',
},
artistDetail: {
back: 'Назад',
albums: 'Альбомы',
@@ -464,6 +471,9 @@ export const ruTranslation = {
showTrayIconDesc: 'Показывать Psysonic в области уведомлений / строке меню.',
minimizeToTray: 'Сворачивать в трей',
minimizeToTrayDesc: 'При закрытии окна не выходить из приложения, а оставаться в трее.',
useCustomTitlebar: 'Своя строка заголовка',
useCustomTitlebarDesc:
'Заменить системную строку заголовка встроенной, в стиле темы приложения. Отключите, чтобы использовать родную строку GNOME/GTK.',
discordRichPresence: 'Статус в Discord',
discordRichPresenceDesc:
'Показывать текущий трек в профиле и статусе Discord. Нужен запущенный клиент Discord.',
@@ -515,6 +525,18 @@ export const ruTranslation = {
tabServer: 'Сервер',
tabSystem: 'Система',
tabGeneral: 'Общие',
ratingsSectionTitle: 'Рейтинги',
ratingsSkipStarTitle: 'Скипнуть для 1 звезды',
ratingsSkipStarDesc:
'При N скипов подряд ставить 1★ треку. Только для не оцененных ранее.',
ratingsSkipStarThresholdLabel: 'Скипов',
ratingsMixFilterTitle: 'Фильтрация по рейтингу',
ratingsMixFilterDesc:
'Фильтровать с низким рейтингом в «{{mix}}» и «{{albums}}». Повторный клик по выбранной звезде отключает порог.',
ratingsMixMinSong: 'Песни',
ratingsMixMinAlbum: 'Альбомы',
ratingsMixMinArtist: 'Исполнители',
ratingsMixMinThresholdAria: 'Минимум звёзд: {{label}}',
backupTitle: 'Резервная копия',
backupExport: 'Экспорт настроек',
backupExportDesc:
@@ -571,6 +593,11 @@ export const ruTranslation = {
seekbarBar: 'Полоса',
seekbarThick: 'Толстая полоса',
seekbarSegmented: 'Сегменты',
seekbarNeon: 'Неон',
seekbarPulsewave: 'Пульс-волна',
seekbarParticletrail: 'Частицы',
seekbarLiquidfill: 'Жидкость',
seekbarRetrotape: 'Ретро-лента',
},
changelog: {
modalTitle: 'Что нового',