feat(most-played): add dedicated Most Played page (#86)

New sidebar item (TrendingUp icon, /most-played route) with:

- Top Artists section: derived by grouping frequent albums by artistId
  and summing playCount — no extra API calls needed. Shows up to 10
  artists as a responsive grid with avatar, rank and total play count.
- Top Albums section: paginated list using getAlbumList('frequent'),
  50 albums per batch with a "Load more" button. Each row shows rank,
  cover thumbnail (44px), album name, artist (navigates to artist
  page), year and play count.
- Sort toggle (most plays first / fewest plays first).

Also adds playCount?: number to SubsonicAlbum — Navidrome returns this
field in getAlbumList2?type=frequent but it was missing from the type.

Closes #86

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Psychotoxical
2026-04-07 20:00:07 +02:00
parent 9319c40fde
commit 4b8b6ae797
13 changed files with 477 additions and 5 deletions
+6 -5
View File
@@ -9,7 +9,7 @@ import { useTranslation } from 'react-i18next';
import {
Disc3, Users, Music4, Radio, Settings, Heart, BarChart3, Shuffle,
PanelLeftClose, PanelLeft, HelpCircle, Dices, AudioLines, HardDriveDownload, Tags, ListMusic, Cast,
ChevronDown, Check, Music2,
ChevronDown, Check, Music2, TrendingUp,
} from 'lucide-react';
import PsysonicLogo from './PsysonicLogo';
import PSmallLogo from './PSmallLogo';
@@ -24,10 +24,11 @@ export const ALL_NAV_ITEMS: Record<string, { icon: React.ElementType; labelKey:
artists: { icon: Users, labelKey: 'sidebar.artists', to: '/artists', section: 'library' },
genres: { icon: Tags, labelKey: 'sidebar.genres', to: '/genres', section: 'library' },
randomMix: { icon: Shuffle, labelKey: 'sidebar.randomMix', to: '/random-mix', section: 'library' },
favorites: { icon: Heart, labelKey: 'sidebar.favorites', to: '/favorites', section: 'library' },
playlists: { icon: ListMusic, labelKey: 'sidebar.playlists', to: '/playlists', section: 'library' },
radio: { icon: Cast, labelKey: 'sidebar.radio', to: '/radio', section: 'library' },
statistics: { icon: BarChart3, labelKey: 'sidebar.statistics', to: '/statistics', section: 'system' },
favorites: { icon: Heart, labelKey: 'sidebar.favorites', to: '/favorites', section: 'library' },
playlists: { icon: ListMusic, labelKey: 'sidebar.playlists', to: '/playlists', section: 'library' },
mostPlayed: { icon: TrendingUp, labelKey: 'sidebar.mostPlayed', to: '/most-played', section: 'library' },
radio: { icon: Cast, labelKey: 'sidebar.radio', to: '/radio', section: 'library' },
statistics: { icon: BarChart3, labelKey: 'sidebar.statistics', to: '/statistics', section: 'system' },
help: { icon: HelpCircle, labelKey: 'sidebar.help', to: '/help', section: 'system' },
};