import { ArrowLeftIcon, HeartFillIcon, HeartIcon } from '@primer/octicons-react' import { ChangeEvent, useEffect, WheelEvent } from 'react' import { Link, useLocation } from 'react-router-dom' import { JellyImg } from '../components/JellyImg' import { Progressbar } from '../components/Main' import { Squircle } from '../components/Squircle' import { DeletingIcon, DownloadedIcon, DownloadingIcon, LyricsIcon, MoreIcon, QueueIcon, TracksIcon, } from '../components/SvgIcons' import { useDropdownContext } from '../context/DropdownContext/DropdownContext' import { useHistoryContext } from '../context/HistoryContext/HistoryContext' import { usePlaybackContext } from '../context/PlaybackContext/PlaybackContext' import { useScrollContext } from '../context/ScrollContext/ScrollContext' import { useJellyfinTrackInfo } from '../hooks/Jellyfin/useJellyfinTrackInfo' import { useDuration } from '../hooks/useDuration' import { useFavorites } from '../hooks/useFavorites' import './NowPlayingLyrics.css' export const NowPlaying = () => { const { goBack: previousPage } = useHistoryContext() const { playlistTitle, currentTrack, bitrate } = usePlaybackContext() const location = useLocation() const playback = usePlaybackContext() const duration = useDuration() const { isOpen, selectedItem, onContextMenu } = useDropdownContext() const { addToFavorites, removeFromFavorites } = useFavorites() const { setDisabled } = useScrollContext() const handleVolumeChange = (e: ChangeEvent) => { const newVolume = parseFloat(e.target.value) playback.setVolume(newVolume) } const handleVolumeScroll = (e: WheelEvent) => { e.stopPropagation() const step = e.deltaY > 0 ? -0.02 : 0.02 const newVolume = Math.max(0, Math.min(1, playback.volume + step)) playback.setVolume(newVolume) } useEffect(() => { window.scrollTo({ top: 0, behavior: 'instant' }) }, [location.pathname]) const handleMoreClick = (e: React.MouseEvent) => { if (!currentTrack) { return } e.stopPropagation() onContextMenu(e, { item: currentTrack }, true, { add_to_favorite: true, remove_from_favorite: true }) } return ( <>
Playing From
{playlistTitle || 'No Playlist'}
{ if (currentTrack?.Id) { try { if (currentTrack?.UserData?.IsFavorite) { await removeFromFavorites(currentTrack) } else { await addToFavorites(currentTrack) } } catch (error) { console.error('Failed to update favorite status:', error) } } }} > {currentTrack?.UserData?.IsFavorite ? ( ) : ( )}
{currentTrack && ( )} {!currentTrack && (
)}
{currentTrack?.Name || 'No Track Played'}
0 ? currentTrack.Artists.join(', ') : 'No Artist' } > {currentTrack?.Artists && currentTrack.Artists.length > 0 ? currentTrack.Artists.join(', ') : 'No Artist'}
{playback.formatTime(duration.progress)}
{bitrate === 320000 ? 'High' : bitrate === 256000 ? 'Medium' : bitrate === 192000 ? 'Low' : bitrate === 128000 ? 'Minimal' : 'Source'}
{bitrate === 320000 ? ( '320' ) : bitrate === 256000 ? ( '256' ) : bitrate === 192000 ? ( '192' ) : bitrate === 128000 ? ( '128' ) : ( )} {' '} kbps
{currentTrack?.offlineState && (
{currentTrack?.offlineState === 'downloading' && (
)} {currentTrack?.offlineState === 'downloaded' && (
)} {currentTrack?.offlineState === 'deleting' && (
)} {currentTrack?.offlineState === 'accepted' && (
)} {currentTrack?.offlineState === 'processing' && (
)} {currentTrack?.offlineState === 'finished' && (
)} {currentTrack?.offlineState === 'uploading' && (
)}
)}
{playback.formatTime(duration.duration)}
Volume: {(playback.volume * 100).toFixed(0)}%
setDisabled(true)} onMouseLeave={() => setDisabled(false)} />
{currentTrack && }
) } const TrackBitrate = ({ trackId }: { trackId: string }) => { const trackInfo = useJellyfinTrackInfo(trackId) const bitrate = Math.round((trackInfo.MediaSources?.[0].Bitrate || 0) / 1000) return <>{bitrate} }