Initial CarPlay audio server implementation with file management, playlists, and album/single classification

This commit is contained in:
2025-12-07 22:27:47 +00:00
commit 58bb44dfb0
14 changed files with 1164 additions and 0 deletions

180
README.md Normal file
View File

@@ -0,0 +1,180 @@
# CarPlay Audio Server
A Node.js server application for managing and streaming audio files to CarPlay-compatible clients.
## Features
### Audio Management
- 🎵 Automatic library scanning with metadata extraction
- 📁 Folder-based organization
- 🎼 Album vs Single classification
- 🎨 Artwork extraction and serving
- 📝 ID3 tag parsing (title, artist, album, year, genre, etc.)
- 📤 File upload support
### Organization
- 📀 Album management with track grouping
- 🎯 Singles collection
- 📋 Custom playlists
- 🗂️ Folder browsing
### Streaming
- 🚗 CarPlay-compatible REST API
- 🎧 Direct audio file streaming
- 🖼️ Album artwork delivery
- ⚡ Efficient file serving
## Requirements
- Node.js 16+
- npm or yarn
## Installation
```bash
# Install dependencies
npm install
# Create audio library directory
mkdir -p audio_library
# Copy your audio files to audio_library/
# Organize them in folders as you like
```
## Usage
### 1. Scan Your Library
```bash
# Scan default library (./audio_library)
npm run scan
# Scan custom path
node src/scripts/scanLibrary.js /path/to/your/music
```
This will:
- Find all audio files (mp3, m4a, flac, wav, aac, ogg)
- Extract metadata from ID3 tags
- Detect albums vs singles
- Extract and save artwork
- Create database entries
### 2. Start the Server
```bash
# Production
npm start
# Development (with auto-reload)
npm run dev
```
Server runs on `http://localhost:3000`
## API Endpoints
### Tracks
- `GET /api/tracks` - Get all tracks
- Query params: `?album=`, `?artist=`, `?folder=`, `?single=true/false`
- `GET /api/tracks/:id` - Get single track
- `PATCH /api/tracks/:id` - Update track metadata
- `GET /api/tracks/folders/list` - List all folders
### Albums
- `GET /api/albums` - Get all albums
- `GET /api/albums/:id` - Get album with tracks
- `GET /api/albums/singles/list` - Get all singles
### Playlists
- `GET /api/playlists` - Get all playlists
- `POST /api/playlists` - Create playlist
- `GET /api/playlists/:id` - Get playlist with tracks
- `POST /api/playlists/:id/tracks` - Add track to playlist
- `DELETE /api/playlists/:id/tracks/:trackId` - Remove track
- `DELETE /api/playlists/:id` - Delete playlist
### Upload
- `POST /api/upload` - Upload audio file
- Form data: `audio` (file), `isSingle` (boolean)
### Static Files
- `/audio/*` - Stream audio files
- `/artwork/*` - Serve album artwork
## Library Organization
The server supports flexible organization:
```
audio_library/
├── Artist Name/
│ ├── Album Name/
│ │ ├── 01 - Track.mp3
│ │ └── 02 - Track.mp3
│ └── Singles/
│ └── Single Track.mp3
└── Various Artists/
└── Compilation Album/
```
### Album vs Single Detection
Files are marked as singles if:
- Located in a folder named "singles" or "single"
- No album tag in metadata
- You manually mark them via API
Update track classification:
```bash
curl -X PATCH http://localhost:3000/api/tracks/:id \
-H "Content-Type: application/json" \
-d '{"isSingle": true}'
```
## CarPlay Client Integration
Your CarPlay client should:
1. Fetch tracks: `GET /api/tracks`
2. Get stream URL from response
3. Play using AVPlayer with the `streamURL`
4. Display artwork from `artworkURL`
Example response:
```json
{
"tracks": [
{
"id": "abc123",
"title": "Song Title",
"artist": "Artist Name",
"album": "Album Name",
"duration": 180,
"streamURL": "http://localhost:3000/audio/path/to/file.mp3",
"artworkURL": "http://localhost:3000/artwork/abc123.jpg"
}
]
}
```
## Project Structure
```
├── src/
│ ├── server.js # Main server
│ ├── database/
│ │ └── db.js # SQLite database
│ ├── routes/
│ │ ├── tracks.js # Track endpoints
│ │ ├── albums.js # Album endpoints
│ │ ├── playlists.js # Playlist endpoints
│ │ └── upload.js # Upload endpoint
│ ├── services/
│ │ └── audioScanner.js # Library scanner
│ └── scripts/
│ └── scanLibrary.js # CLI scanner
├── audio_library/ # Your audio files
├── artwork/ # Extracted artwork
└── audio_server.db # SQLite database
```