{"id":48695101,"url":"https://github.com/saegey/dj-playlist","last_synced_at":"2026-04-11T07:13:16.235Z","repository":{"id":303118969,"uuid":"1014468086","full_name":"saegey/dj-playlist","owner":"saegey","description":null,"archived":false,"fork":false,"pushed_at":"2026-03-09T00:51:26.000Z","size":11154,"stargazers_count":5,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-09T03:30:50.085Z","etag":null,"topics":["discogs","essentia","meilisearch","music","sematic-search","vinyl"],"latest_commit_sha":null,"homepage":"https://saegey.com/project/vinyl-playlist-maker/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/saegey.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-07-05T19:34:17.000Z","updated_at":"2026-03-09T00:45:03.000Z","dependencies_parsed_at":"2025-07-14T22:10:36.719Z","dependency_job_id":"a81170d0-f721-4445-981c-89632003892f","html_url":"https://github.com/saegey/dj-playlist","commit_stats":null,"previous_names":["saegey/dj-playlist"],"tags_count":141,"template":false,"template_full_name":null,"purl":"pkg:github/saegey/dj-playlist","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saegey%2Fdj-playlist","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saegey%2Fdj-playlist/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saegey%2Fdj-playlist/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saegey%2Fdj-playlist/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/saegey","download_url":"https://codeload.github.com/saegey/dj-playlist/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saegey%2Fdj-playlist/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31671988,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T17:19:37.612Z","status":"online","status_checked_at":"2026-04-11T02:00:05.776Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["discogs","essentia","meilisearch","music","sematic-search","vinyl"],"created_at":"2026-04-11T07:13:15.105Z","updated_at":"2026-04-11T07:13:16.220Z","avatar_url":"https://github.com/saegey.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GrooveNET\n\n![screenshot](https://raw.githubusercontent.com/saegey/dj-playlist/refs/heads/main/content/grooveNetdemo.gif)\n\nA full-stack Next.js app for managing, analyzing, and syncing vinyl music collections with multiple music platforms. Seamlessly import your Discogs collection, enrich metadata with Apple Music, Spotify, and YouTube, perform audio analysis, and create intelligent playlists.\n\n## Features\n- **Modern Frontend**: Next.js 15, React 19, TypeScript, and Chakra UI v3\n- **Powerful Search**: MeiliSearch with infinite scroll, full-text search, and advanced filtering\n- **Multi-Platform Integration**: Discogs, Apple Music, Spotify, YouTube, and SoundCloud\n- **Audio Analysis**: Essentia-powered BPM, key detection, and mood analysis via FastAPI microservice\n- **Smart Playlisting**: AI-powered playlist generation using genetic algorithms\n- **Metadata Enrichment**: Bulk editing, AI-assisted metadata completion, and track linking\n- **Database Management**: PostgreSQL with pgvector for semantic search, backup/restore via web UI\n- **Collection Sync**: Share and sync collections with friends\n- **Vector Search**: Optional embedding-based similarity search using OpenAI\n- **Docker Compose**: Full orchestration for development and production environments\n\n## Project Structure\n\n```\ndj-playlist/\n├── my-collection-search/        # Main Next.js application\n│   ├── src/\n│   │   ├── app/                 # Next.js 15 app router pages + API routes\n│   │   ├── components/          # React components\n│   │   ├── hooks/               # React Query hooks and cache management\n│   │   ├── server/              # Backend-only: repositories, services\n│   │   ├── services/            # Frontend API clients\n│   │   ├── types/               # TypeScript type definitions\n│   │   └── api-contract/        # Zod schemas shared across routes\n│   ├── migrations/              # PostgreSQL migration scripts (node-pg-migrate)\n│   └── .env.example             # Environment variable template\n├── packages/\n│   ├── groovenet-client/        # Shared typed API client (@groovenet/client)\n│   └── groovenet-cli/           # CLI tool (@groovenet/cli, bin: groovenet)\n├── mcp-server/                  # MCP server for Claude Code integration\n├── essentia-api/                # Python FastAPI audio analysis microservice\n├── ga-service/                  # Python genetic algorithm playlist generator\n├── docker-compose.yml           # Base Docker Compose (local builds)\n├── docker-compose.dev.yml       # Development overrides (hot reload)\n└── docker-compose.prod.yml      # Production with pre-built images (x86_64 only)\n```\n\n## Getting Started\n\n### Prerequisites\n- **Docker \u0026 Docker Compose** (v2.x or higher)\n- **Node.js** 20+ (for local development)\n- **Discogs account** with collection data (required)\n- **API credentials** (see Environment Variables section below)\n\n### Quick Start (Development)\n\n1. **Clone the repository**:\n   ```sh\n   git clone \u003cyour-repo-url\u003e\n   cd dj-playlist\n   ```\n\n2. **Configure environment variables**:\n   ```sh\n   cd my-collection-search\n   cp .env.example .env\n   ```\n   Edit `.env` and add your API credentials (see \"Getting API Credentials\" section)\n\n3. **Start services with Docker Compose**:\n   ```sh\n   docker compose -f docker-compose.yml -f docker-compose.dev.yml up --build\n   ```\n\n   This will start:\n   - PostgreSQL database (port 5432)\n   - MeiliSearch (port 7700)\n   - Next.js app (port 3000)\n   - Essentia API for audio analysis (port 8000)\n\n4. **Run database migrations**:\n   ```sh\n   docker compose run --rm migrate\n   ```\n\n5. **Access the application**:\n   - Frontend: [http://localhost:3000](http://localhost:3000)\n   - MeiliSearch admin: [http://localhost:7700](http://localhost:7700)\n\n6. **Import your Discogs collection**:\n   - Navigate to the import page in the UI\n   - Click \"Sync from Discogs\"\n   - Your collection will be imported and indexed in MeiliSearch\n\n### Production Deployment\n\nThere are two production deployment options depending on your platform architecture:\n\n#### Option 1: Production with Pre-built Images (Linux/x86_64)\n\nThis option uses tagged container images from GitHub Container Registry. Ideal for Linux servers and deployment tools like Portainer.\n\n1. **Configure environment**:\n   ```sh\n   cd my-collection-search\n   cp .env.example .env\n   ```\n   Edit `.env` with production credentials and strong passwords\n\n2. **Start services using production compose file**:\n   ```sh\n   docker compose -f docker-compose.prod.yml up -d\n   ```\n\n   This configuration:\n   - Pulls pre-built images from `ghcr.io/saegey/myapp:v1.0.78`\n   - Includes all services: app, db, MeiliSearch, Redis, Essentia API, GA service, download worker\n   - Uses named volumes for persistence\n\n3. **Run migrations**:\n   ```sh\n   docker compose -f docker-compose.prod.yml run --rm migrate\n   ```\n\n4. **Access the app**: Navigate to your server's address on port 3000\n\n**Note**: Currently, pre-built images are only available for x86_64/amd64 architecture. ARM64 images are not yet published to the registry.\n\n#### Option 2: Production with Local Build (Mac/ARM64)\n\nFor ARM-based systems (Apple Silicon Macs, ARM servers) where pre-built images aren't available, build locally:\n\n1. **Configure environment**:\n   ```sh\n   cd my-collection-search\n   cp .env.example .env\n   ```\n   Edit `.env` with production credentials\n\n2. **Build and start services**:\n   ```sh\n   docker compose -f docker-compose.yml up --build -d\n   ```\n\n3. **Run migrations**:\n   ```sh\n   docker compose run --rm migrate\n   ```\n\n4. **Access the app**: Navigate to `http://localhost:3000`\n\n**Architecture Notes**:\n- The main `docker-compose.yml` builds images locally from source\n- Works on any architecture (ARM64, x86_64)\n- Slower initial startup due to build time\n- Recommended for Mac users until ARM64 images are published\n\n#### Deploying with Portainer\n\nIf using Portainer on a Linux server (x86_64):\n\n1. **Create a new stack** in Portainer\n2. **Upload or paste** the contents of `docker-compose.prod.yml`\n3. **Set environment variables** in Portainer's environment section:\n   - Add all variables from `.env.example`\n   - Portainer will inject these into the containers\n4. **Deploy the stack**\n5. **Run migrations**:\n   - Use Portainer's container console\n   - Select the `migrate` container\n   - Or exec into the `app` container: `npx node-pg-migrate up`\n\n**Portainer Benefits**:\n- Web UI for container management\n- Easy log viewing and monitoring\n- Automatic restarts and health checks\n- Simple environment variable management\n\n### Local Development (Without Docker)\n\n1. **Start PostgreSQL and MeiliSearch** (use Docker or install locally):\n   ```sh\n   docker compose up -d db meili\n   ```\n\n2. **Install dependencies**:\n   ```sh\n   cd my-collection-search\n   npm install\n   ```\n\n3. **Run migrations**:\n   ```sh\n   npm run migrate up\n   ```\n\n4. **Start the dev server**:\n   ```sh\n   npm run dev\n   ```\n\n5. **Access**: [http://localhost:3000](http://localhost:3000)\n\n## Database Migrations\n- Migrations are managed with [node-pg-migrate](https://github.com/salsita/node-pg-migrate).\n- Migration files are in `migrations/` and ordered by timestamp.\n- To run migrations manually:\n  ```sh\n  docker compose run migrate\n  ```\n\n## Backup \u0026 Restore\n- Backup: Use the web UI or POST `/api/backup` to create a SQL dump in `dumps/`.\n- Restore: Use the web UI or POST a SQL file to `/api/restore`.\n- For a full restore, remove the DB volume first:\n  ```sh\n  docker compose down -v\n  docker compose up db\n  # Then restore via UI or API\n  ```\n\n## Key Workflows\n\n### Importing Your Collection\n1. Set up Discogs credentials in `.env`\n2. Navigate to the import page in the UI\n3. Click \"Sync from Discogs\" to import your collection\n4. Tracks are automatically indexed in MeiliSearch for instant search\n\n### Enriching Metadata\n- **Auto-match**: Automatically find Apple Music, Spotify, and YouTube links for tracks\n- **Bulk edit**: Select multiple tracks and update fields like BPM, key, rating, tags\n- **AI assistance**: Use OpenAI to auto-complete missing metadata fields\n- **Manual editing**: Edit individual track details with inline forms\n\n### Audio Analysis\n- Upload audio files for tracks (MP3, WAV, FLAC)\n- Essentia API automatically analyzes:\n  - BPM (beats per minute)\n  - Musical key\n  - Danceability score\n  - Mood analysis (happy, sad, aggressive, relaxed)\n- Analysis results are stored and searchable\n\n### Creating Playlists\n- **Manual**: Drag and drop tracks from search results\n- **AI-powered**: Use genetic algorithm to generate playlists based on:\n  - BPM matching\n  - Key compatibility\n  - Mood progression\n  - Genre clustering\n\n### Searching \u0026 Filtering\n- **Full-text search**: Search across title, artist, album, genres, styles\n- **Advanced filters**: Filter by BPM range, key, star rating, tags, platform availability\n- **Infinite scroll**: Smooth browsing through large collections\n- **Vector similarity**: Find similar tracks using OpenAI embeddings (optional)\n\n### Friend Collections\n- Add friends by Discogs username\n- Browse and search friends' collections\n- Compare collections and find unique tracks\n- Sync updates when friends add new records\n\n## Audio Analysis\n- Audio files are processed and stored in `/audio` volume\n- Essentia microservice runs in its own container (`essentia-api`)\n- Analysis results are saved to PostgreSQL and indexed in MeiliSearch\n- Supports MP3, WAV, FLAC, and other common audio formats\n\n## USB DAC Audio Playback (Optional)\n\nGrooveNET supports USB DAC (Digital-to-Analog Converter) passthrough for high-quality audio playback directly from the containerized application. This feature is completely optional and disabled by default.\n\n### Prerequisites\n- USB DAC connected to your host system\n- Docker host must be Linux-based (required for USB device passthrough)\n- ALSA utilities installed on the host (recommended for device detection)\n\n### Setup Instructions\n\n#### Step 1: Detect Your Audio Devices\n\nRun the audio detection script on your host machine (not in a container):\n\n```sh\ncd my-collection-search/scripts\n./detect-audio-devices.sh\n```\n\nThis script will display:\n- Available `/dev/snd` devices\n- ALSA sound card information\n- USB audio devices\n- Configuration guidance\n\n**Example output**:\n```\n2. ALSA Sound Cards (from /proc/asound/cards):\n 0 [PCH            ]: HDA-Intel - HDA Intel PCH\n 1 [DAC            ]: USB-Audio - FiiO DAC\n```\n\nIn this example, the USB DAC is card 1.\n\n#### Step 2: Configure Docker Compose\n\nEdit your `docker-compose.prod.yml` or `docker-compose.yml` file:\n\n**Option A - Pass All Audio Devices (Simplest)**:\n\nUncomment these lines under the `app` service:\n\n```yaml\ndevices:\n  - /dev/snd:/dev/snd  # Pass through all audio devices\n```\n\n**Option B - Pass Specific DAC Only (More Secure)**:\n\nIf your USB DAC is card 1 (check the script output):\n\n```yaml\ndevices:\n  - /dev/snd/controlC1:/dev/snd/controlC1  # Control interface for card 1\n  - /dev/snd/pcmC1D0p:/dev/snd/pcmC1D0p    # Playback device for card 1\n```\n\nReplace `1` with your actual card number from Step 1.\n\n#### Step 3: Configure Environment Variables\n\nEdit your `.env` file:\n\n```env\n# Enable audio playback features\nENABLE_AUDIO_PLAYBACK=true\n\n# Set the ALSA device name\n# Use 'default' for the system default device\n# Or specify a card like 'hw:1,0' for card 1, device 0\nAUDIO_DEVICE=hw:1,0\n```\n\n**Device name format**:\n- `default` - System default audio device\n- `hw:X,Y` - Hardware device (card X, device Y)\n- `plughw:X,Y` - Hardware with software conversion (more compatible)\n\n#### Step 4: Restart the Stack\n\n**For Docker Compose**:\n```sh\ndocker compose down\ndocker compose up -d\n```\n\n**For Portainer**:\n1. Go to **Stacks** → Your Stack → **Editor**\n2. Uncomment the `devices:` section under the `app` service\n3. Go to **Environment variables** and add/update:\n   - `ENABLE_AUDIO_PLAYBACK=true`\n   - `AUDIO_DEVICE=hw:1,0` (adjust card number as needed)\n4. Click **Update the stack**\n\n#### Step 5: Test Audio Playback\n\nRun a test tone to verify the USB DAC is working:\n\n```sh\n# Test with speaker-test (generates a test tone)\ndocker exec -it myapp speaker-test -t wav -c 2\n\n# Test with a specific device\ndocker exec -it myapp speaker-test -D hw:1,0 -t wav -c 2\n\n# Press Ctrl+C to stop the test\n```\n\nIf you hear audio through your USB DAC, the setup is successful!\n\n### Portainer-Specific Setup\n\nIf you're using Portainer on an Intel NUC or other Linux server:\n\n1. **Edit Stack Compose File**:\n   - Navigate to **Stacks** → Your Stack → **Editor**\n   - Find the `app` service section\n   - Uncomment the device mapping:\n     ```yaml\n     devices:\n       - /dev/snd:/dev/snd\n     ```\n   - Click **Update the stack**\n\n2. **Set Environment Variables**:\n   - In the same stack editor, scroll to **Environment variables**\n   - Add or edit:\n     - `ENABLE_AUDIO_PLAYBACK` = `true`\n     - `AUDIO_DEVICE` = `hw:1,0` (or your device)\n   - Click **Update the stack**\n\n3. **Verify Deployment**:\n   - Portainer will recreate the container with the new settings\n   - Check logs: **Containers** → `myapp` → **Logs**\n\n### Troubleshooting\n\n**No audio output**:\n```sh\n# Check if the container can see audio devices\ndocker exec -it myapp ls -la /dev/snd/\n\n# List available ALSA devices inside container\ndocker exec -it myapp aplay -l\n\n# Check if the specified device exists\ndocker exec -it myapp cat /proc/asound/cards\n```\n\n**Permission denied errors**:\n- The container user may need to be in the `audio` group\n- Try passing all devices with `/dev/snd:/dev/snd` instead of specific devices\n- Check host permissions: `ls -la /dev/snd/`\n\n**Wrong device playing audio**:\n- Use `AUDIO_DEVICE=hw:X,Y` to specify the exact card number\n- Run the detection script again to verify device numbers haven't changed\n- USB device numbers can change after reboot; consider using `by-id` paths\n\n**USB DAC not detected**:\n- Ensure the USB DAC is connected before starting containers\n- Check `lsusb` on the host to verify USB connection\n- Some DACs require specific kernel drivers or firmware\n\n### Audio Playback in Your App\n\nOnce configured, your Next.js app can use the `ENABLE_AUDIO_PLAYBACK` and `AUDIO_DEVICE` environment variables to enable audio playback features in the UI.\n\n#### Quick Integration Example\n\nAdd the playback mode selector to your player UI:\n\n```typescript\nimport PlaybackModeSelector from '@/components/PlaybackModeSelector';\nimport { usePlaybackMode, useLocalPlayback } from '@/hooks/usePlaybackMode';\n\nfunction MyPlayer() {\n  const { mode, setMode } = usePlaybackMode();\n  const { play, pause, stop } = useLocalPlayback();\n  const { currentTrack, isPlaying } = usePlaylistPlayer();\n\n  // Handle play button\n  const handlePlay = async () =\u003e {\n    if (mode === 'local-dac' \u0026\u0026 currentTrack?.local_audio_url) {\n      await play(currentTrack.local_audio_url);\n    } else {\n      // Use existing browser playback\n      browserPlay();\n    }\n  };\n\n  return (\n    \u003cdiv\u003e\n      {/* Playback mode selector */}\n      \u003cPlaybackModeSelector value={mode} onChange={setMode} /\u003e\n\n      {/* Your existing player controls */}\n      \u003cbutton onClick={handlePlay}\u003ePlay\u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\nFor complete integration details, see [`docs/LOCAL_PLAYBACK.md`](my-collection-search/docs/LOCAL_PLAYBACK.md).\n\n### Platform Limitations\n\n- **Linux only**: USB device passthrough requires Linux host OS\n- **Not supported**: macOS, Windows (WSL2 has limited support)\n- **Portainer**: Works great on Linux servers (Intel NUC, Raspberry Pi, etc.)\n- **Development**: May not work in `docker-compose.dev.yml` on macOS\n\n## AirPlay Receiver (Optional)\n\nTurn your Intel NUC with USB DAC into an AirPlay receiver! Stream audio from iOS devices, Macs, and other AirPlay sources directly to your high-quality DAC.\n\n### Features\n\n- **Network Audio Endpoint**: Your server appears as \"GrooveNET Audio\" in AirPlay menus\n- **Simultaneous Playback**: Use ALSA dmix to play both AirPlay and Next.js app audio simultaneously\n- **Auto-Coordination**: Optional hooks to pause app playback when AirPlay starts\n- **High Quality**: Supports high sample rates and bit depths (96kHz/24-bit)\n\n### Quick Setup\n\n1. **Enable the service** in `docker-compose.prod.yml`:\n   ```yaml\n   # Uncomment the shairport-sync service block\n   shairport-sync:\n     image: mikebrady/shairport-sync:latest\n     network_mode: host  # Required for AirPlay discovery\n     devices:\n       - /dev/snd:/dev/snd\n   ```\n\n2. **Configure for software mixing** (recommended):\n   ```env\n   # In .env\n   AIRPLAY_NAME=GrooveNET Audio\n   AUDIO_DEVICE=dmix:CARD=DAC,DEV=0\n   ```\n\n3. **Mount ALSA config** for dmix:\n   ```yaml\n   # In docker-compose.prod.yml\n   volumes:\n     - ./config/asound.conf:/etc/asound.conf:ro\n   ```\n\n4. **Start the service**:\n   ```bash\n   docker compose -f docker-compose.prod.yml up -d shairport-sync\n   ```\n\n5. **Test**: Open AirPlay menu on your iPhone/Mac and look for \"GrooveNET Audio\"\n\n### Configuration Options\n\n**Simple Mode (First-Come-First-Served)**:\n- Only one audio source at a time (AirPlay or app)\n- Easiest setup, no mixing required\n- See [docs/AIRPLAY_RECEIVER.md](my-collection-search/docs/AIRPLAY_RECEIVER.md#option-1-simple-first-come-first-served)\n\n**dmix Mode (Recommended)**:\n- Both AirPlay and app can play simultaneously\n- Software mixing with minimal CPU overhead\n- See [docs/AIRPLAY_RECEIVER.md](my-collection-search/docs/AIRPLAY_RECEIVER.md#option-2-software-mixing-with-dmix-recommended)\n\n**Coordinated Mode**:\n- Auto-pause app when AirPlay starts\n- Managed via session hooks\n- See [docs/AIRPLAY_RECEIVER.md](my-collection-search/docs/AIRPLAY_RECEIVER.md#option-3-coordinated-playback-with-hooks)\n\nFor complete setup instructions, troubleshooting, and advanced configuration, see the [**AirPlay Receiver Guide**](my-collection-search/docs/AIRPLAY_RECEIVER.md).\n\n## Environment Variables\n\n### Required Configuration\nCopy `my-collection-search/.env.example` to `my-collection-search/.env` and configure the following variables:\n\n```env\n# Database\nDATABASE_URL=postgres://djplaylist:djplaylist@localhost:5432/djplaylist\n\n# MeiliSearch\nMEILISEARCH_API_KEY=mysupersecretkey\nMEILISEARCH_HOST=http://meili:7700\nMEILISEARCH_EXTERNAL_HOST=http://localhost:7700\nMEILI_PARENT_KEY=sample_meili_parent_key\nMEILI_PARENT_KEY_UID=sample_parentkey_uid\n\n# Discogs (Required for collection import)\nDISCOGS_USER_TOKEN=your_discogs_token\nDISCOGS_USERNAME=your_discogs_username\nDISCOGS_FOLDER_ID=0\n\n# Optional: Music Platform APIs\nAPPLE_MUSIC_TEAM_ID=your_team_id\nAPPLE_MUSIC_KEY_ID=your_key_id\nAPPLE_MUSIC_PRIVATE_KEY_PATH=./AuthKey_XXXXXXXXXX.p8\n\nSPOTIFY_CLIENT_ID=your_spotify_client_id\nSPOTIFY_CLIENT_SECRET=your_spotify_client_secret\nSPOTIFY_REDIRECT_URI=http://localhost:3000/api/spotify/callback\n\nYOUTUBE_API_KEY=your_youtube_api_key\n\n# Optional: AI Features\nOPENAI_API_KEY=your_openai_api_key\n\n# Optional: USB DAC Audio Playback\nENABLE_AUDIO_PLAYBACK=false\nAUDIO_DEVICE=default\n```\n\n### Getting API Credentials\n\n#### Discogs (Required)\nDiscogs is the primary source for importing your vinyl collection.\n\n1. **Create a Discogs Account**: Visit [discogs.com](https://www.discogs.com) and sign up\n2. **Get Your User Token**:\n   - Go to [Settings → Developers](https://www.discogs.com/settings/developers)\n   - Click \"Generate new token\"\n   - Copy the token to `DISCOGS_USER_TOKEN`\n3. **Find Your Username**: Your username appears in your profile URL: `discogs.com/user/YOUR_USERNAME`\n4. **Folder ID**: Use `0` for \"All\" or find specific folder IDs in your collection URL\n\n**Documentation**: [Discogs API Docs](https://www.discogs.com/developers)\n\n#### Apple Music Developer (Optional)\nEnables metadata enrichment, preview URLs, and Apple Music linking.\n\n1. **Apple Developer Account**: You need a paid Apple Developer account ($99/year)\n   - Sign up at [developer.apple.com](https://developer.apple.com)\n2. **Create a MusicKit Key**:\n   - Go to [Certificates, Identifiers \u0026 Profiles](https://developer.apple.com/account/resources/authkeys/list)\n   - Click \"+\" to create a new key\n   - Enable \"MusicKit\" checkbox\n   - Download the `.p8` file (you can only download once!)\n3. **Configure Environment**:\n   - `APPLE_MUSIC_TEAM_ID`: Found in the top-right of your Apple Developer account (10-character ID)\n   - `APPLE_MUSIC_KEY_ID`: The Key ID shown after creating the key (10-character ID)\n   - `APPLE_MUSIC_PRIVATE_KEY_PATH`: Path to your downloaded `.p8` file (place in project root)\n\n**Documentation**: [Apple Music API Setup](https://developer.apple.com/documentation/applemusicapi/getting_keys_and_creating_tokens)\n\n#### Spotify (Optional)\nEnables Spotify track matching, playlist import, and new release tracking.\n\n1. **Create Spotify App**:\n   - Go to [Spotify Developer Dashboard](https://developer.spotify.com/dashboard)\n   - Click \"Create app\"\n   - Fill in app name and description\n   - Add redirect URI: `http://localhost:3000/api/spotify/callback`\n2. **Get Credentials**:\n   - Click on your new app\n   - Copy \"Client ID\" to `SPOTIFY_CLIENT_ID`\n   - Click \"Show Client Secret\" and copy to `SPOTIFY_CLIENT_SECRET`\n3. **Set Redirect URI**: Must match `SPOTIFY_REDIRECT_URI` in your `.env`\n\n**Documentation**: [Spotify Web API](https://developer.spotify.com/documentation/web-api)\n\n#### YouTube Data API (Optional)\nEnables YouTube search and video linking for tracks.\n\n1. **Create Google Cloud Project**:\n   - Go to [Google Cloud Console](https://console.cloud.google.com)\n   - Create a new project or select existing\n2. **Enable YouTube Data API v3**:\n   - Navigate to \"APIs \u0026 Services\" → \"Library\"\n   - Search for \"YouTube Data API v3\"\n   - Click \"Enable\"\n3. **Create API Key**:\n   - Go to \"APIs \u0026 Services\" → \"Credentials\"\n   - Click \"Create Credentials\" → \"API Key\"\n   - Copy the key to `YOUTUBE_API_KEY`\n   - (Optional) Restrict the key to YouTube Data API v3 for security\n\n**Documentation**: [YouTube Data API](https://developers.google.com/youtube/v3/getting-started)\n\n**Note**: Free tier includes 10,000 quota units/day. Each search costs ~100 units.\n\n#### OpenAI (Optional)\nPowers AI-assisted metadata completion and semantic vector search.\n\n1. **Create OpenAI Account**: Visit [platform.openai.com](https://platform.openai.com)\n2. **Generate API Key**:\n   - Go to [API Keys](https://platform.openai.com/api-keys)\n   - Click \"Create new secret key\"\n   - Copy the key to `OPENAI_API_KEY`\n   - **Important**: Save immediately - you won't see it again!\n3. **Add Billing**: Add payment method in [Billing settings](https://platform.openai.com/account/billing)\n\n**Documentation**: [OpenAI API Quickstart](https://platform.openai.com/docs/quickstart)\n\n**Usage**: The app uses GPT models for metadata enhancement and embedding models for vector search.\n\n## Docker Compose Configurations\n\nThe project includes three Docker Compose files for different deployment scenarios:\n\n### `docker-compose.yml` (Base Configuration)\n- Builds all images locally from source\n- Works on any architecture (x86_64, ARM64)\n- Suitable for production on Mac/ARM systems\n- Can be combined with dev overrides\n\n### `docker-compose.dev.yml` (Development Overrides)\n- Extends base configuration with development features\n- Hot reload for Next.js (volume mounts source code)\n- Local development optimizations\n- Usage: `docker compose -f docker-compose.yml -f docker-compose.dev.yml up`\n\n### `docker-compose.prod.yml` (Production with Registry Images)\n- Uses pre-built images from GitHub Container Registry\n- Faster deployment (no build time)\n- Includes all production services: app, db, Redis, MeiliSearch, Essentia API, GA service, download worker\n- **Currently x86_64/amd64 only** - ARM64 images not yet published\n- Ideal for Linux servers and tools like Portainer\n- Usage: `docker compose -f docker-compose.prod.yml up -d`\n\n**Recommendation**:\n- **Linux servers (x86_64)**: Use `docker-compose.prod.yml` for fastest deployment\n- **Mac (Apple Silicon)**: Use `docker-compose.yml` (local build) until ARM images are available\n- **Development**: Use `docker-compose.yml` + `docker-compose.dev.yml` combined\n\n## Troubleshooting\n\n### Database connection issues\n```sh\n# Check if database is running\ndocker compose ps db\n\n# View database logs\ndocker compose logs db\n\n# Test connection\ndocker compose exec db psql -U djplaylist -d djplaylist -c \"SELECT 1;\"\n```\n\n### MeiliSearch not indexing\n```sh\n# Check MeiliSearch logs\ndocker compose logs meili\n\n# Verify MeiliSearch is accessible\ncurl http://localhost:7700/health\n\n# Re-index all tracks (via UI or API)\n# Navigate to /admin/reindex in the app\n```\n\n### Missing API credentials\n- Ensure `.env` file exists in `my-collection-search/` directory\n- Verify all required variables are set (especially `DISCOGS_USER_TOKEN`)\n- Check that Apple Music `.p8` file path is correct\n- Restart services after updating `.env`: `docker compose restart app`\n\n### Port conflicts\nIf ports 3000, 5432, or 7700 are already in use:\n1. Stop conflicting services\n2. Or modify ports in `docker-compose.yml` (e.g., `\"3001:3000\"`)\n\n### Audio analysis failing\n```sh\n# Check Essentia API logs\ndocker compose logs essentia-api\n\n# Verify service is running\ncurl http://localhost:8000/health\n\n# Check audio file permissions in ./audio/ volume\n```\n\n## Technology Stack\n\n### Frontend\n- Next.js 15 (App Router)\n- React 19\n- TypeScript\n- Chakra UI v3\n- TanStack Query v5 (React Query)\n- Framer Motion\n- Zustand (state management)\n\n### Backend\n- Next.js API Routes\n- PostgreSQL 16 with pgvector extension\n- MeiliSearch (search engine)\n- Redis (job queuing)\n- node-pg-migrate (database migrations)\n\n### Services\n- Essentia API (Python FastAPI) - Audio analysis\n- Docker Compose - Orchestration\n\n### External APIs\n- Discogs API\n- Apple Music API (MusicKit)\n- Spotify Web API\n- YouTube Data API v3\n- OpenAI API (GPT-4 and embeddings)\n\n## CLI (`groovenet`)\n\nA terminal client for your collection, usable from any machine on your network (e.g. over Tailscale). All commands support `--json` for scripting.\n\n### Install\n\n```bash\nnpm install -g @groovenet/cli\n```\n\nOr from source:\n\n```bash\nnpm install          # from repo root\nmake build-packages\ncd packages/groovenet-cli \u0026\u0026 npm link\n```\n\n### Configure\n\n```bash\ngroovenet config set api_base http://groovenet.tail1234.ts.net/api\ngroovenet config set api_key your-key-if-needed   # optional\ngroovenet config show\n```\n\nConfig is stored in `~/.groovenet/config.json`.\n\n### Commands\n\n**Tracks**\n```bash\ngroovenet tracks search \"acid house\" --bpm-min 120 --bpm-max 135 --limit 20\ngroovenet tracks show \u003ctrack-id\u003e\ngroovenet tracks update \u003ctrack-id\u003e --rating 5 --notes \"peak time\" --tags \"acid,classic\"\ngroovenet tracks missing-apple-music --page 1\n```\n\n**Albums**\n```bash\ngroovenet albums list                              # recently added (default)\ngroovenet albums list \"blue note\" --sort year:desc\ngroovenet albums show \u003crelease-id\u003e\ngroovenet albums update \u003crelease-id\u003e --rating 5 --condition \"NM\" --library-id LP042\ngroovenet albums download \u003crelease-id\u003e            # queues missing tracks for download\n```\n\n**Playlists**\n```bash\ngroovenet playlists list\ngroovenet playlists show \u003cid\u003e\ngroovenet playlists create \"Friday Night\"\ngroovenet playlists generate \u003cid\u003e                 # re-optimizes via genetic algorithm\n```\n\n**Playback** (routes through server → MPD)\n```bash\ngroovenet play \u003ctrack-id\u003e\ngroovenet pause\ngroovenet stop\ngroovenet now-playing\n```\n\n**Other**\n```bash\ngroovenet friends list\ngroovenet friends add \u003cusername\u003e\n```\n\n---\n\n## MCP Server (Claude Code Integration)\n\nAllows Claude to browse and manage your collection through natural language.\n\n### Setup\n\n```bash\nnpm install \u0026\u0026 make build-packages\n\n# Register with Claude Code (local)\nclaude mcp add --transport stdio --scope project groovenet \\\n  -- node /path/to/dj-playlist/mcp-server/build/index.js\n\n# Or for remote access over Tailscale\nclaude mcp add --transport stdio --scope user groovenet \\\n  -- env API_BASE=http://groovenet.tail1234.ts.net/api \\\n     node /path/to/dj-playlist/mcp-server/build/index.js\n```\n\n### Available Tools\n\n| Category | Tools |\n|---|---|\n| Tracks | `search_tracks`, `get_track_details`, `update_track`, `get_missing_apple_music` |\n| Albums | `search_albums`, `get_album`, `update_album`, `download_album` |\n| Playlists | `list_playlists`, `get_playlist`, `create_playlist`, `generate_ai_playlist`, `get_playlist_tracks` |\n| Friends | `get_friends`, `add_friend` |\n| External search | `search_apple_music`, `search_youtube` |\n\nSee [`mcp-server/README.md`](mcp-server/README.md) for full documentation.\n\n---\n\n## Contributing\nContributions are welcome! Please feel free to submit a Pull Request.\n\n### Development Guidelines\n- Follow TypeScript strict mode conventions\n- Use the existing query key patterns in `src/lib/queryKeys.ts`\n- Update cache optimistically where appropriate\n- Add migrations for schema changes\n- Test with Docker Compose before submitting\n\n## License\nMIT\n\n## Support\nFor issues, questions, or feature requests, please open an issue on GitHub.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaegey%2Fdj-playlist","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsaegey%2Fdj-playlist","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaegey%2Fdj-playlist/lists"}