Feature: Audio Player Overview
Relevant source files
The following files were used as context for generating this wiki page:The Audio Player is a core feature of the Endfield Pomodoro application, designed to provide an immersive audio experience for users during their work and break sessions. It functions as a dual-mode "Audio Feed" terminal, supporting both local file playback and online music streaming. This allows users to either load their own audio files or connect to popular music platforms to listen to playlists.
The system is architected to be modular, with a main controller component that switches between two distinct playback logic hooks (useLocalPlayer and useOnlinePlayer), while sharing a common user interface (PlayerInterface). The selected audio source mode is persisted in localStorage to maintain user preference across sessions.
Sources: README.md, src/components/AudioPlayer.tsx:16-27
Architecture
The audio player's architecture is centered around the AudioPlayer component, which acts as a high-level controller. It determines which playback mode is active ('local' or 'online') and renders the appropriate logic and UI.
The diagram below illustrates the component hierarchy and data flow for the audio player feature.
Core Components
| Component | File | Description |
|---|---|---|
AudioPlayer | src/components/AudioPlayer.tsx | The main container and controller. It manages the audioSource state ('local' vs. 'online'), handles network status changes, and renders either the local player UI or the MusicPlayer component. |
PlayerInterface | src/components/PlayerInterface.tsx | A reusable, stateless UI component that displays track information, progress, and controls. It receives all its state and callbacks as props, making it adaptable for both local and online modes. |
MusicPlayer | src/components/MusicPlayer.tsx | A component dedicated to the online playback experience. It uses the useMusicData hook to fetch playlist data and the useOnlinePlayer hook to manage playback state, then passes the necessary props to PlayerInterface. |
Sources: src/components/AudioPlayer.tsx, src/components/PlayerInterface.tsx, src/components/MusicPlayer.tsx
State Management Hooks
The core logic for playback is encapsulated in custom React hooks, separating the concerns of state management from the UI components.
| Hook | File | Description |
|---|---|---|
useLocalPlayer | src/hooks/useLocalPlayer.ts | Manages all aspects of local audio playback, including adding files, parsing metadata, creating/revoking Blob URLs, and controlling the <audio> element. |
useOnlinePlayer | src/hooks/useOnlinePlayer.ts | Manages online audio playback. It takes a playlist of song objects and controls the <audio> element for streaming. |
useMusicData | src/hooks/useMusicData.ts | Responsible for fetching and parsing online music data from the Meting API. It includes logic for API failover and request cancellation. |
Sources: src/hooks/useLocalPlayer.ts, src/hooks/useOnlinePlayer.ts, src/hooks/useMusicData.ts
Playback Modes
The player supports two mutually exclusive modes: Local and Online. The user can toggle between them, and the choice is persisted in localStorage under the key origin_terminal_audio_source.
Sources: src/components/AudioPlayer.tsx:21-27, src/constants.ts:13
Local Playback
In local mode, users can upload audio files from their device. The useLocalPlayer hook manages the entire lifecycle.
Key Features:
- File Handling: Users can add multiple files via a file input. The hook processes each file to prevent duplicates based on name, size, and last modified date.
- Metadata Parsing: Uses the
music-metadatalibrary to parse ID3 tags from audio files, extracting the track title, artist, and cover art. - Blob URL Management: Creates
BlobURLs for audio files and cover art to be used by the<audio>element and<img>tags. These URLs are carefully revoked when a track is removed or the component unmounts to prevent memory leaks. - Playlist Management: Provides functions to add, remove, and clear tracks from the playlist.
The following diagram shows the process of adding a local file.
Online Playback
In online mode, the player streams music from external platforms via the Meting API. This mode is only available when the user has an active internet connection.
Key Features:
- Data Fetching: The
useMusicDatahook fetches playlist data based on the configuration (server,type,id) provided from the application settings. - API Abstraction: The system uses an adapter pattern (
getAdapters) to support multiple API endpoints, providing failover if the primary API is unavailable. - State Management: The
useOnlinePlayerhook receives the fetched playlist and manages the playback state, including the current track, play/pause status, and playback mode (sequence, loop, random). - Error Handling: Includes timeouts (
API_TIMEOUT_MS) and retry logic (NEXT_TRACK_RETRY_DELAY_MS) for a more resilient streaming experience.
The sequence diagram below details the flow for fetching and playing an online playlist.
Data Models
The player uses distinct data structures for local and online tracks.
LocalTrack
This interface defines the structure for a track loaded from the user's local machine.
| Field | Type | Description |
|---|---|---|
id | string | A unique identifier generated from file properties (name, size, lastModified). |
file | File | The original File object. |
name | string | The track name, parsed from metadata or derived from the filename. |
artist | string (optional) | The artist name, parsed from metadata. |
blobUrl | string | A Blob URL pointing to the audio file data for playback. |
coverUrl | string (optional) | A Blob URL pointing to the embedded cover art image data. |
Sources: src/hooks/useLocalPlayer.ts:6-14
Online Song/MusicTrack
This interface defines the structure for a track fetched from the Meting API.
| Field | Type | Description |
|---|---|---|
name | string | The name of the song. |
artist | string | The name of the artist. |
url | string | The direct streaming URL for the audio. |
cover | string | The URL for the album cover art. |
lrc | string | The URL or content of the song lyrics. |
Sources: src/hooks/useOnlinePlayer.ts:6-12, src/hooks/useMusicData.ts:7-14
Shared UI: PlayerInterface
The PlayerInterface component is the common visual front-end for both playback modes. It is a controlled component that receives its entire state and all event handlers via props.
PlayerInterfaceProps
| Prop | Type | Description |
|---|---|---|
isPlaying | boolean | Whether the audio is currently playing. |
currentTime | number | The current playback time in seconds. |
duration | number | The total duration of the track in seconds. |
volume | number | The current volume level (0.0 to 1.0). |
currentTrackName | string | null | The name of the currently loaded track. |
currentArtist | string (optional) | The artist of the current track. |
coverUrl | string (optional) | URL for the track's cover art. |
playlistCount | number | Total number of tracks in the playlist. |
currentIndex | number | The index of the current track in the playlist. |
playMode | AudioMode | The current playback mode (SEQUENTIAL, REPEAT_ONE, SHUFFLE). |
language | Language | The current application language for i18n. |
isLoading | boolean (optional) | Indicates if the track is currently loading. |
onPlayPause | () => void | Callback to toggle play/pause. |
onNext | () => void | Callback to skip to the next track. |
onPrev | () => void | Callback to go to the previous track. |
onSeek | (time: number) => void | Callback for when the user seeks on the progress bar. |
onVolumeChange | (volume: number) => void | Callback for when the volume is changed. |
onModeToggle | () => void | Callback to toggle the playback mode. |
onPlaylistToggle | () => void | Callback to show/hide the playlist view. |
Sources: src/components/PlayerInterface.tsx:5-29
Summary
The Audio Player feature is a well-structured and robust system that enhances the Endfield Pomodoro application by providing a flexible, dual-mode audio experience. By separating UI (PlayerInterface) from logic (useLocalPlayer, useOnlinePlayer) and abstracting data fetching (useMusicData), the architecture is modular, maintainable, and easily extensible. Its ability to handle both local files and online streams, complete with metadata parsing and resilient error handling, makes it a significant and user-centric part of the application.
Sources: README.md, src/components/AudioPlayer.tsx