mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-22 06:25:41 +00:00
feat(player-stats): local listening history tab with heatmap and summaries (#849)
* feat(player-stats): local listening history tab with heatmap and summaries Record play sessions in library.sqlite when the library index is enabled, add Rust read APIs and Tauri commands for year/day aggregates, and ship the Player stats UI with session clustering, event-driven live refresh, and a notice when some servers are excluded from indexing. * test(player-stats): split play_session repo and expand test coverage Move the repository into play_session/ (completion, cluster, integration tests), add remap/purge/FK coverage in Rust, and cover ingestion gates plus live-refresh hooks on the frontend per spec v0.3. * docs(release): CHANGELOG and credits for player stats (PR #849) * fix(player-stats): satisfy tsc and clippy CI gates Use InternetRadioStation field names in the radio skip test and replace manual month/day range checks with RangeInclusive::contains.
This commit is contained in:
@@ -62,4 +62,33 @@ export const statistics = {
|
||||
exportSaving: 'Speichere…',
|
||||
exportSaved: 'Gespeichert.',
|
||||
exportSaveFailed: 'Bild konnte nicht gespeichert werden.',
|
||||
tabServer: 'Server-Statistik',
|
||||
tabPlayer: 'Player-Statistik',
|
||||
playerEmpty: 'Hör zu — dein lokaler Verlauf erscheint hier, sobald der Library-Index aktiv ist.',
|
||||
playerSummaryTime: 'Hörzeit',
|
||||
playerListeningDayShort: '{{count}}d',
|
||||
playerListeningHourShort: '{{count}}h',
|
||||
playerListeningMinuteShort: '{{count}}min',
|
||||
playerSummarySessions: 'Sitzungen',
|
||||
playerSummaryTracks: 'Titel',
|
||||
playerSummaryUniqueTracks: 'Einzigartige Titel',
|
||||
playerSummaryDays: 'Days',
|
||||
playerPartialIndexNotice: 'Einige Server sind vom lokalen Bibliotheksindex ausgeschlossen. Wiedergaben auf diesen Servern werden nicht in der Player-Statistik erfasst.',
|
||||
playerPartialIndexSettings: 'Bibliothekseinstellungen',
|
||||
playerSummaryCompletion: 'Voll / teilweise',
|
||||
playerYearPrev: 'Vorheriges Jahr',
|
||||
playerYearNext: 'Nächstes Jahr',
|
||||
playerHeatmapLegend: 'Dunkler = mehr gehörte Titel an diesem Tag.',
|
||||
playerHeatmapLess: 'Weniger',
|
||||
playerHeatmapMore: 'Mehr',
|
||||
playerDaySessions: '{{count}} Sitzungen',
|
||||
playerDayTrackPlays: '{{count}} Titel',
|
||||
playerDayFullPartial: '{{full}} voll · {{partial}} teilweise',
|
||||
playerRecentDaysTitle: 'Letzte Tage',
|
||||
playerDayToday: 'Heute',
|
||||
playerDayYesterday: 'Gestern',
|
||||
playerListenedSecShort: '{{seconds}} s',
|
||||
playerListenedMinDecimal: '{{minutes}} Min.',
|
||||
completionFull: 'Vollständig',
|
||||
completionPartial: 'Teilweise',
|
||||
};
|
||||
|
||||
@@ -62,4 +62,33 @@ export const statistics = {
|
||||
exportSaving: 'Saving…',
|
||||
exportSaved: 'Saved.',
|
||||
exportSaveFailed: 'Could not save the image.',
|
||||
tabServer: 'Server stats',
|
||||
tabPlayer: 'Player stats',
|
||||
playerEmpty: 'Start listening — your local play history will appear here once the library index is enabled.',
|
||||
playerSummaryTime: 'Listening time',
|
||||
playerListeningDayShort: '{{count}}d',
|
||||
playerListeningHourShort: '{{count}}h',
|
||||
playerListeningMinuteShort: '{{count}}m',
|
||||
playerSummarySessions: 'Sessions',
|
||||
playerSummaryTracks: 'Track plays',
|
||||
playerSummaryUniqueTracks: 'Unique tracks',
|
||||
playerSummaryDays: 'Days',
|
||||
playerPartialIndexNotice: 'Some servers are excluded from the local library index. Listening on those servers is not recorded in player statistics.',
|
||||
playerPartialIndexSettings: 'Library settings',
|
||||
playerSummaryCompletion: 'Full / partial',
|
||||
playerYearPrev: 'Previous year',
|
||||
playerYearNext: 'Next year',
|
||||
playerHeatmapLegend: 'Darker cells = more tracks played that day.',
|
||||
playerHeatmapLess: 'Less',
|
||||
playerHeatmapMore: 'More',
|
||||
playerDaySessions: '{{count}} sessions',
|
||||
playerDayTrackPlays: '{{count}} tracks',
|
||||
playerDayFullPartial: '{{full}} full · {{partial}} partial',
|
||||
playerRecentDaysTitle: 'Recent days',
|
||||
playerDayToday: 'Today',
|
||||
playerDayYesterday: 'Yesterday',
|
||||
playerListenedSecShort: '{{seconds}}s',
|
||||
playerListenedMinDecimal: '{{minutes}} min',
|
||||
completionFull: 'Full listen',
|
||||
completionPartial: 'Partial',
|
||||
};
|
||||
|
||||
@@ -44,4 +44,33 @@ export const statistics = {
|
||||
topRatedArtists: 'Artistas Mejor Calificados',
|
||||
noRatedSongs: 'Aún no hay canciones calificadas. Califica canciones en la vista de álbum o playlist.',
|
||||
noRatedArtists: 'Aún no hay artistas calificados.',
|
||||
tabServer: 'Estadísticas del servidor',
|
||||
tabPlayer: 'Estadísticas del reproductor',
|
||||
playerEmpty: 'Empieza a escuchar — tu historial local aparecerá aquí con el índice de biblioteca activo.',
|
||||
playerSummaryTime: 'Tiempo de escucha',
|
||||
playerListeningDayShort: '{{count}}d',
|
||||
playerListeningHourShort: '{{count}}h',
|
||||
playerListeningMinuteShort: '{{count}}m',
|
||||
playerSummarySessions: 'Sesiones',
|
||||
playerSummaryTracks: 'Pistas',
|
||||
playerSummaryUniqueTracks: 'Pistas únicas',
|
||||
playerSummaryDays: 'Days',
|
||||
playerPartialIndexNotice: 'Algunos servidores están excluidos del índice local de biblioteca. La escucha en esos servidores no se registra en las estadísticas del reproductor.',
|
||||
playerPartialIndexSettings: 'Ajustes de biblioteca',
|
||||
playerSummaryCompletion: 'Completas / parciales',
|
||||
playerYearPrev: 'Año anterior',
|
||||
playerYearNext: 'Año siguiente',
|
||||
playerHeatmapLegend: 'Más oscuro = más pistas escuchadas ese día.',
|
||||
playerHeatmapLess: 'Menos',
|
||||
playerHeatmapMore: 'Más',
|
||||
playerDaySessions: '{{count}} sesiones',
|
||||
playerDayTrackPlays: '{{count}} pistas',
|
||||
playerDayFullPartial: '{{full}} completas · {{partial}} parciales',
|
||||
playerRecentDaysTitle: 'Días recientes',
|
||||
playerDayToday: 'Hoy',
|
||||
playerDayYesterday: 'Ayer',
|
||||
playerListenedSecShort: '{{seconds}} s',
|
||||
playerListenedMinDecimal: '{{minutes}} min',
|
||||
completionFull: 'Escucha completa',
|
||||
completionPartial: 'Parcial',
|
||||
};
|
||||
|
||||
@@ -44,4 +44,33 @@ export const statistics = {
|
||||
topRatedArtists: 'Artistes les mieux notés',
|
||||
noRatedSongs: 'Aucun morceau noté. Notez des morceaux dans la vue album ou playlist.',
|
||||
noRatedArtists: 'Aucun artiste noté.',
|
||||
tabServer: 'Stats serveur',
|
||||
tabPlayer: 'Stats lecteur',
|
||||
playerEmpty: 'Commencez à écouter — l’historique local apparaîtra ici avec l’index bibliothèque activé.',
|
||||
playerSummaryTime: 'Temps d’écoute',
|
||||
playerListeningDayShort: '{{count}}j',
|
||||
playerListeningHourShort: '{{count}}h',
|
||||
playerListeningMinuteShort: '{{count}}m',
|
||||
playerSummarySessions: 'Sessions',
|
||||
playerSummaryTracks: 'Morceaux',
|
||||
playerSummaryUniqueTracks: 'Morceaux uniques',
|
||||
playerSummaryDays: 'Days',
|
||||
playerPartialIndexNotice: 'Certains serveurs sont exclus de l’index local de bibliothèque. L’écoute sur ces serveurs n’est pas enregistrée dans les statistiques du lecteur.',
|
||||
playerPartialIndexSettings: 'Paramètres bibliothèque',
|
||||
playerSummaryCompletion: 'Complets / partiels',
|
||||
playerYearPrev: 'Année précédente',
|
||||
playerYearNext: 'Année suivante',
|
||||
playerHeatmapLegend: 'Plus foncé = plus de morceaux écoutés ce jour-là.',
|
||||
playerHeatmapLess: 'Moins',
|
||||
playerHeatmapMore: 'Plus',
|
||||
playerDaySessions: '{{count}} sessions',
|
||||
playerDayTrackPlays: '{{count}} morceaux',
|
||||
playerDayFullPartial: '{{full}} complets · {{partial}} partiels',
|
||||
playerRecentDaysTitle: 'Jours récents',
|
||||
playerDayToday: "Aujourd'hui",
|
||||
playerDayYesterday: 'Hier',
|
||||
playerListenedSecShort: '{{seconds}} s',
|
||||
playerListenedMinDecimal: '{{minutes}} min',
|
||||
completionFull: 'Écoute complète',
|
||||
completionPartial: 'Partiel',
|
||||
};
|
||||
|
||||
@@ -44,4 +44,33 @@ export const statistics = {
|
||||
topRatedArtists: 'Høyest vurderte artister',
|
||||
noRatedSongs: 'Ingen vurderte spor ennå. Vurder spor i album- eller spillelistevisning.',
|
||||
noRatedArtists: 'Ingen vurderte artister ennå.',
|
||||
tabServer: 'Serverstatistikk',
|
||||
tabPlayer: 'Spillerstatistikk',
|
||||
playerEmpty: 'Begynn å lytte — lokal historikk vises her når bibliotekindeks er aktivert.',
|
||||
playerSummaryTime: 'Lyttetid',
|
||||
playerListeningDayShort: '{{count}}d',
|
||||
playerListeningHourShort: '{{count}}t',
|
||||
playerListeningMinuteShort: '{{count}}m',
|
||||
playerSummarySessions: 'Økter',
|
||||
playerSummaryTracks: 'Spor',
|
||||
playerSummaryUniqueTracks: 'Unike spor',
|
||||
playerSummaryDays: 'Days',
|
||||
playerPartialIndexNotice: 'Noen servere er ekskludert fra det lokale biblioteksindeks. Lytting på disse serverne registreres ikke i spillerstatistikken.',
|
||||
playerPartialIndexSettings: 'Bibliotekinnstillinger',
|
||||
playerSummaryCompletion: 'Full / delvis',
|
||||
playerYearPrev: 'Forrige år',
|
||||
playerYearNext: 'Neste år',
|
||||
playerHeatmapLegend: 'Mørkere = flere spor den dagen.',
|
||||
playerHeatmapLess: 'Mindre',
|
||||
playerHeatmapMore: 'Mer',
|
||||
playerDaySessions: '{{count}} økter',
|
||||
playerDayTrackPlays: '{{count}} spor',
|
||||
playerDayFullPartial: '{{full}} full · {{partial}} delvis',
|
||||
playerRecentDaysTitle: 'Siste dager',
|
||||
playerDayToday: 'I dag',
|
||||
playerDayYesterday: 'I går',
|
||||
playerListenedSecShort: '{{seconds}} s',
|
||||
playerListenedMinDecimal: '{{minutes}} min',
|
||||
completionFull: 'Full lytting',
|
||||
completionPartial: 'Delvis',
|
||||
};
|
||||
|
||||
@@ -44,4 +44,33 @@ export const statistics = {
|
||||
topRatedArtists: 'Best beoordeelde artiesten',
|
||||
noRatedSongs: 'Nog geen beoordeelde nummers. Beoordeel nummers in album- of afspeellijstweergave.',
|
||||
noRatedArtists: 'Nog geen beoordeelde artiesten.',
|
||||
tabServer: 'Serverstatistieken',
|
||||
tabPlayer: 'Spelerstatistieken',
|
||||
playerEmpty: 'Begin te luisteren — je lokale geschiedenis verschijnt hier zodra de bibliotheekindex aan staat.',
|
||||
playerSummaryTime: 'Luistertijd',
|
||||
playerListeningDayShort: '{{count}}d',
|
||||
playerListeningHourShort: '{{count}}u',
|
||||
playerListeningMinuteShort: '{{count}}m',
|
||||
playerSummarySessions: 'Sessies',
|
||||
playerSummaryTracks: 'Nummers',
|
||||
playerSummaryUniqueTracks: 'Unieke nummers',
|
||||
playerSummaryDays: 'Days',
|
||||
playerPartialIndexNotice: 'Sommige servers zijn uitgesloten van de lokale bibliotheekindex. Luisteren op die servers wordt niet vastgelegd in de playerstatistieken.',
|
||||
playerPartialIndexSettings: 'Bibliotheekinstellingen',
|
||||
playerSummaryCompletion: 'Volledig / gedeeltelijk',
|
||||
playerYearPrev: 'Vorig jaar',
|
||||
playerYearNext: 'Volgend jaar',
|
||||
playerHeatmapLegend: 'Donkerder = meer nummers geluisterd op die dag.',
|
||||
playerHeatmapLess: 'Minder',
|
||||
playerHeatmapMore: 'Meer',
|
||||
playerDaySessions: '{{count}} sessies',
|
||||
playerDayTrackPlays: '{{count}} nummers',
|
||||
playerDayFullPartial: '{{full}} volledig · {{partial}} gedeeltelijk',
|
||||
playerRecentDaysTitle: 'Recente dagen',
|
||||
playerDayToday: 'Vandaag',
|
||||
playerDayYesterday: 'Gisteren',
|
||||
playerListenedSecShort: '{{seconds}} s',
|
||||
playerListenedMinDecimal: '{{minutes}} min',
|
||||
completionFull: 'Volledig geluisterd',
|
||||
completionPartial: 'Gedeeltelijk',
|
||||
};
|
||||
|
||||
@@ -62,4 +62,33 @@ export const statistics = {
|
||||
exportSaving: 'Se salvează…',
|
||||
exportSaved: 'Salvat.',
|
||||
exportSaveFailed: 'Nu s-a putut salva imaginea.',
|
||||
tabServer: 'Statistici server',
|
||||
tabPlayer: 'Statistici player',
|
||||
playerEmpty: 'Începe să asculți — istoricul local va apărea aici când indexul bibliotecii este activ.',
|
||||
playerSummaryTime: 'Timp de ascultare',
|
||||
playerListeningDayShort: '{{count}}z',
|
||||
playerListeningHourShort: '{{count}}h',
|
||||
playerListeningMinuteShort: '{{count}}m',
|
||||
playerSummarySessions: 'Sesiuni',
|
||||
playerSummaryTracks: 'Piese',
|
||||
playerSummaryUniqueTracks: 'Piese unice',
|
||||
playerSummaryDays: 'Days',
|
||||
playerPartialIndexNotice: 'Unele servere sunt excluse din indexul local al bibliotecii. Ascultarea pe aceste servere nu este înregistrată în statisticile playerului.',
|
||||
playerPartialIndexSettings: 'Setări bibliotecă',
|
||||
playerSummaryCompletion: 'Complete / parțiale',
|
||||
playerYearPrev: 'Anul anterior',
|
||||
playerYearNext: 'Anul următor',
|
||||
playerHeatmapLegend: 'Mai închis = mai multe piese ascultate în acea zi.',
|
||||
playerHeatmapLess: 'Mai puțin',
|
||||
playerHeatmapMore: 'Mai mult',
|
||||
playerDaySessions: '{{count}} sesiuni',
|
||||
playerDayTrackPlays: '{{count}} piese',
|
||||
playerDayFullPartial: '{{full}} complete · {{partial}} parțiale',
|
||||
playerRecentDaysTitle: 'Zile recente',
|
||||
playerDayToday: 'Astăzi',
|
||||
playerDayYesterday: 'Ieri',
|
||||
playerListenedSecShort: '{{seconds}} s',
|
||||
playerListenedMinDecimal: '{{minutes}} min',
|
||||
completionFull: 'Ascultare completă',
|
||||
completionPartial: 'Parțial',
|
||||
};
|
||||
|
||||
@@ -55,4 +55,33 @@ export const statistics = {
|
||||
topRatedArtists: 'Лучшие по рейтингу исполнители',
|
||||
noRatedSongs: 'Нет оценённых треков. Ставьте оценки в альбомах или плейлистах.',
|
||||
noRatedArtists: 'Нет оценённых исполнителей.',
|
||||
tabServer: 'Статистика сервера',
|
||||
tabPlayer: 'Статистика плеера',
|
||||
playerEmpty: 'Начните слушать — локальная история появится здесь при включённом индексе библиотеки.',
|
||||
playerSummaryTime: 'Время прослушивания',
|
||||
playerListeningDayShort: '{{count}}д',
|
||||
playerListeningHourShort: '{{count}}ч',
|
||||
playerListeningMinuteShort: '{{count}}мин',
|
||||
playerSummarySessions: 'Сессии',
|
||||
playerSummaryTracks: 'Треки',
|
||||
playerSummaryUniqueTracks: 'Уникальные треки',
|
||||
playerSummaryDays: 'Days',
|
||||
playerPartialIndexNotice: 'Не все серверы включены в локальный индекс библиотеки. Прослушивание с выключенных серверов не попадает в эту статистику.',
|
||||
playerPartialIndexSettings: 'Настройки библиотеки',
|
||||
playerSummaryCompletion: 'Полные / частичные',
|
||||
playerYearPrev: 'Предыдущий год',
|
||||
playerYearNext: 'Следующий год',
|
||||
playerHeatmapLegend: 'Темнее — больше прослушанных треков за день.',
|
||||
playerHeatmapLess: 'Меньше',
|
||||
playerHeatmapMore: 'Больше',
|
||||
playerDaySessions: '{{count}} сессий',
|
||||
playerDayTrackPlays: '{{count}} треков',
|
||||
playerDayFullPartial: '{{full}} полных · {{partial}} частичных',
|
||||
playerRecentDaysTitle: 'Недавние дни',
|
||||
playerDayToday: 'Сегодня',
|
||||
playerDayYesterday: 'Вчера',
|
||||
playerListenedSecShort: '{{seconds}} с',
|
||||
playerListenedMinDecimal: '{{minutes}} мин',
|
||||
completionFull: 'Прослушано',
|
||||
completionPartial: 'Частично',
|
||||
};
|
||||
|
||||
@@ -44,4 +44,33 @@ export const statistics = {
|
||||
topRatedArtists: '最高评分艺人',
|
||||
noRatedSongs: '暂无已评分歌曲。请在专辑或播放列表中为歌曲评分。',
|
||||
noRatedArtists: '暂无已评分艺人。',
|
||||
tabServer: '服务器统计',
|
||||
tabPlayer: '播放器统计',
|
||||
playerEmpty: '开始收听 — 启用媒体库索引后,本地播放历史将显示在这里。',
|
||||
playerSummaryTime: '收听时长',
|
||||
playerListeningDayShort: '{{count}}天',
|
||||
playerListeningHourShort: '{{count}}小时',
|
||||
playerListeningMinuteShort: '{{count}}分钟',
|
||||
playerSummarySessions: '会话数',
|
||||
playerSummaryTracks: '曲目',
|
||||
playerSummaryUniqueTracks: '独立曲目',
|
||||
playerSummaryDays: 'Days',
|
||||
playerPartialIndexNotice: '部分服务器未纳入本地库索引,在这些服务器上的收听不会计入播放器统计。',
|
||||
playerPartialIndexSettings: '库设置',
|
||||
playerSummaryCompletion: '完整 / 部分',
|
||||
playerYearPrev: '上一年',
|
||||
playerYearNext: '下一年',
|
||||
playerHeatmapLegend: '颜色越深表示当天收听的曲目越多。',
|
||||
playerHeatmapLess: '少',
|
||||
playerHeatmapMore: '多',
|
||||
playerDaySessions: '{{count}} 次会话',
|
||||
playerDayTrackPlays: '{{count}} 首曲目',
|
||||
playerDayFullPartial: '{{full}} 完整 · {{partial}} 部分',
|
||||
playerRecentDaysTitle: '最近几天',
|
||||
playerDayToday: '今天',
|
||||
playerDayYesterday: '昨天',
|
||||
playerListenedSecShort: '{{seconds}} 秒',
|
||||
playerListenedMinDecimal: '{{minutes}} 分钟',
|
||||
completionFull: '完整收听',
|
||||
completionPartial: '部分',
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user