Addon Developer Guide

Build addons that extend Eclipse Music with new music sources. Your addon is a simple HTTP server that provides search results and stream URLs. Eclipse handles everything else — playback, UI, queue management, playlists, lyrics, and more.

How It Works

An addon is a web server (Node.js, Python, Go, Rust — any language) that exposes these endpoints:

EndpointRequiredPurpose
GET /manifest.jsonYesDescribes your addon
GET /search?q={query}YesReturns search results
GET /stream/{id}YesReturns a playable stream URL
GET /album/{id}NoReturns album tracks (for browsing)
GET /artist/{id}NoReturns artist top tracks + albums
GET /playlist/{id}NoReturns playlist tracks

Users install your addon by pasting its URL into Eclipse. Your addon appears in the search dropdown, and Eclipse routes playback through it. If you implement the optional detail endpoints, users can browse albums, artists, and playlists natively inside Eclipse.


Quick Start

1. Create the manifest

Your server must respond to GET /manifest.json:

{
  "id": "com.yourname.myaddon",
  "name": "My Music Addon",
  "version": "1.0.0",
  "description": "Streams music from my service",
  "icon": "https://your-cdn.com/addon-icon.png",
  "resources": ["search", "stream"],
  "types": ["track", "album", "artist"]
}

Required fields:

FieldTypeDescription
idStringUnique identifier (reverse domain, e.g. com.yourname.myaddon)
nameStringDisplay name shown in Eclipse's search dropdown
versionStringSemver version (e.g. 1.0.0)
resourcesArrayWhat your addon provides: "search", "stream", or both

Optional fields:

FieldTypeDescription
descriptionStringBrief description
iconStringURL to your addon's icon (PNG/JPEG, square, recommended 128x128 or larger). Shown in the search provider dropdown, addon management, and anywhere your addon is referenced. Falls back to a puzzle piece icon if not provided.
typesArrayContent types: "track", "album", "artist"

Respond to GET /search?q={query} with:

{
  "tracks": [
    {
      "id": "track_123",
      "title": "Song Title",
      "artist": "Artist Name",
      "album": "Album Name",
      "duration": 240,
      "artworkURL": "https://example.com/cover.jpg",
      "isrc": "USRC12345678",
      "format": "mp3"
    }
  ],
  "albums": [
    {
      "id": "album_456",
      "title": "Album Title",
      "artist": "Artist Name",
      "artworkURL": "https://example.com/album.jpg",
      "trackCount": 12,
      "year": "2024"
    }
  ],
  "artists": [
    {
      "id": "artist_789",
      "name": "Artist Name",
      "artworkURL": "https://example.com/artist.jpg",
      "genres": ["Pop", "Rock"]
    }
  ],
  "playlists": [
    {
      "id": "playlist_123",
      "title": "Best of 2024",
      "creator": "Curator Name",
      "artworkURL": "https://example.com/playlist.jpg",
      "trackCount": 50
    }
  ]
}

All four arrays are optional — return only what you have.

Track fields:

FieldTypeRequiredDescription
idStringYesUnique ID within your addon
titleStringYesSong title
artistStringYesArtist name
albumStringNoAlbum name
durationIntNoDuration in seconds
artworkURLStringNoCover art URL
isrcStringNoISRC code — highly recommended (enables MusicKit metadata enrichment)
formatStringNoAudio format: "mp3", "flac", "aac", "m4a"
streamURLStringNoDirect stream URL (if provided, Eclipse skips the /stream call)

Playlist fields (in search response):

FieldTypeRequiredDescription
idStringYesUnique playlist ID
titleStringYesPlaylist name
descriptionStringNoPlaylist description
artworkURLStringNoCover image URL
creatorStringNoPlaylist creator name
trackCountIntNoNumber of tracks

3. Implement stream resolution

Respond to GET /stream/{id} with:

{
  "url": "https://cdn.example.com/audio/track_123.mp3",
  "format": "mp3",
  "quality": "320kbps"
}

Response fields:

FieldTypeRequiredDescription
urlStringYesDirect HTTP/HTTPS URL to the audio file
formatStringNoAudio format
qualityStringNoQuality description (e.g. "320kbps", "lossless")
expiresAtNumberNoUnix timestamp when the URL expires

The URL must be a direct link to an audio file — no HTML pages, no redirects to login pages. Eclipse supports MP3, AAC, M4A, FLAC, WAV, and OGG.

4. Album details (optional)

If your addon returns albums in search results, implement GET /album/{id} so users can browse album tracks:

{
  "id": "album_456",
  "title": "Album Title",
  "artist": "Artist Name",
  "artworkURL": "https://example.com/album.jpg",
  "year": "2024",
  "description": "Optional album description",
  "trackCount": 12,
  "tracks": [
    {
      "id": "track_1",
      "title": "Track One",
      "artist": "Artist Name",
      "duration": 240,
      "artworkURL": "https://example.com/cover.jpg",
      "streamURL": "https://cdn.example.com/track1.mp3"
    }
  ]
}

Without this endpoint, Eclipse falls back to searching Apple Music by album name. If your content isn't on Apple Music (unreleased music, remixes, etc.), you need this endpoint.

5. Artist details (optional)

If your addon returns artists in search results, implement GET /artist/{id} so users can see top tracks and albums:

{
  "id": "artist_789",
  "name": "Artist Name",
  "artworkURL": "https://example.com/artist.jpg",
  "bio": "Optional artist biography",
  "genres": ["Hip-Hop", "R&B"],
  "topTracks": [
    {
      "id": "track_1",
      "title": "Hit Song",
      "artist": "Artist Name",
      "duration": 200,
      "streamURL": "https://cdn.example.com/hit.mp3"
    }
  ],
  "albums": [
    {
      "id": "album_1",
      "title": "Album Name",
      "artist": "Artist Name",
      "artworkURL": "https://example.com/album.jpg",
      "trackCount": 14,
      "year": "2024"
    }
  ]
}

Without this endpoint, Eclipse falls back to searching Apple Music by artist name.

6. Playlist details (optional)

If your addon provides playlists, implement GET /playlist/{id}:

{
  "id": "playlist_123",
  "title": "Playlist Name",
  "description": "Curated collection",
  "artworkURL": "https://example.com/playlist.jpg",
  "creator": "Curator Name",
  "tracks": [
    {
      "id": "track_1",
      "title": "Track One",
      "artist": "Artist Name",
      "duration": 240,
      "streamURL": "https://cdn.example.com/track1.mp3"
    }
  ]
}

Complete Example (Node.js)

const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());

// Manifest
app.get('/manifest.json', (req, res) => {
  res.json({
    id: 'com.example.demo',
    name: 'Demo Addon',
    version: '1.0.0',
    description: 'A demo addon for Eclipse Music',
    resources: ['search', 'stream'],
    types: ['track']
  });
});

// Search
app.get('/search', (req, res) => {
  const query = req.query.q || '';
  // Replace with your actual search logic
  res.json({
    tracks: [
      {
        id: 'demo_1',
        title: `Demo: ${query}`,
        artist: 'Demo Artist',
        duration: 180,
        format: 'mp3'
      }
    ]
  });
});

// Stream resolution
app.get('/stream/:id', (req, res) => {
  const trackId = req.params.id;
  // Replace with your actual stream URL logic
  res.json({
    url: `https://your-cdn.com/audio/${trackId}.mp3`,
    format: 'mp3',
    quality: '320kbps'
  });
});

app.listen(3000, () => {
  console.log('Addon running on http://localhost:3000');
});
npm init -y
npm install express cors
node index.js

Complete Example (Python)

from flask import Flask, request, jsonify
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route('/manifest.json')
def manifest():
    return jsonify({
        'id': 'com.example.demo',
        'name': 'Demo Addon',
        'version': '1.0.0',
        'description': 'A demo addon for Eclipse Music',
        'resources': ['search', 'stream'],
        'types': ['track']
    })

@app.route('/search')
def search():
    query = request.args.get('q', '')
    # Replace with your actual search logic
    return jsonify({
        'tracks': [{
            'id': 'demo_1',
            'title': f'Demo: {query}',
            'artist': 'Demo Artist',
            'duration': 180,
            'format': 'mp3'
        }]
    })

@app.route('/stream/<track_id>')
def stream(track_id):
    # Replace with your actual stream URL logic
    return jsonify({
        'url': f'https://your-cdn.com/audio/{track_id}.mp3',
        'format': 'mp3',
        'quality': '320kbps'
    })

if __name__ == '__main__':
    app.run(port=3000)
pip install flask flask-cors
python app.py

Hosting

Your addon must be accessible via HTTPS. Options:

PlatformFree TierNotes
Cloudflare Workers100k req/dayServerless, global CDN
VercelGenerousServerless functions
Railway$5/moFull server
Fly.io3 shared VMsDocker containers
Your own serverAny VPS with HTTPS

For local development, use http://localhost:3000 — Eclipse accepts HTTP for local network addresses.

Testing on a real iPhone/iPad: Use your Mac's local IP instead of localhost (e.g. http://192.168.1.100:3000/). Run ipconfig getifaddr en0 on your Mac to get it. Phone must be on the same WiFi. Make sure your server binds to 0.0.0.0 (all interfaces), not just 127.0.0.1.


How Eclipse Uses Your Addon

Search Flow

  1. User selects your addon in the search dropdown
  2. User types a query
  3. Eclipse calls GET /search?q={query} on your server
  4. Your results appear in Eclipse's search UI (same layout as Apple Music/Tidal results)
  5. If tracks have ISRC codes, Eclipse enriches them with MusicKit metadata (high-quality artwork, genre, lyrics availability)

Playback Flow

  1. User taps play on a track from your addon
  2. Eclipse calls GET /stream/{trackId} on your server
  3. Your server returns the stream URL
  4. Eclipse plays it through its audio engine (supports MP3, AAC, FLAC, etc.)
  5. All audio features work automatically — EQ, reverb, speed control, lock screen, AirPlay, CarPlay

Album/Artist/Playlist Browsing

When a user taps an album, artist, or playlist from your search results:

Default Playback

Users can set your addon as the Default Playback source in Settings → Addon Management. When set:

Playlist/Library Integration

When a user saves your addon's tracks to a playlist or their library:

Playlist Import

When your addon is installed, it appears as a match service in the Import Playlist flow. Users can import Spotify/Apple Music playlists and match songs through your addon's search endpoint.

Collaborative Playlists

Addon tracks work in collaborative playlists. Both users need the same addon installed for playback (unless the track has a permanent stream URL stored in sourceUrl).


ISRC: The Secret Weapon

Highly recommended — include ISRC whenever possible.

If your tracks include ISRC (International Standard Recording Code), Eclipse can:


Requirements


Installing Your Addon in Eclipse

  1. Open Eclipse Music
  2. Go to SettingsConnectionsAdd ConnectionAddon
  3. Paste your addon's URL (e.g. https://your-addon.com/ or https://your-addon.com/manifest.json)
  4. Eclipse fetches the manifest and shows a preview
  5. Tap Install

Your addon appears in the search dropdown. If it supports streaming, it also appears in SettingsAddon ManagementDefault Playback picker.


Capabilities Reference

Resources

ValueDescription
"search"Your addon can search for music (shows in search dropdown)
"stream"Your addon can resolve playable URLs (shows in playback picker)
"catalog"Your addon supports detail endpoints (/album/{id}, /artist/{id}, /playlist/{id})

Types

ValueDescription
"track"Individual songs
"album"Albums/collections
"artist"Artists
"playlist"Curated playlists
"file"Generic audio files

FAQ

Can I build an addon in any language?

Yes — any language that can serve HTTP with JSON responses works. Node.js, Python, Go, Rust, PHP, Ruby, Java, C#, etc.

Does my addon need a database?

No — your addon just needs to respond to HTTP requests. How you source the data is up to you.

Can my addon require authentication?

Yes — you can include tokens in your addon URL (e.g. https://my-addon.com/{user_token}/manifest.json). Eclipse stores the full URL.

What happens if my addon is offline?

Eclipse falls back gracefully — tracks from your addon won't play, but the rest of the app works fine. Downloaded/offline tracks still play from local files.

Can I update my addon without users reinstalling?

Yes — just update your server. Eclipse fetches the manifest each time. Users don't need to reinstall unless the URL changes.

What audio formats are supported?

MP3, AAC, M4A, FLAC, WAV, OGG. FLAC streams instantly via Eclipse's native FLAC streaming engine.

Can my addon provide album/artist detail pages?

Yes! Implement GET /album/{id} and GET /artist/{id} endpoints, and add "catalog" to your manifest's resources array. When users tap an album or artist from your search results, Eclipse will load the details from your addon. Without these endpoints, Eclipse falls back to Apple Music (MusicKit) for album/artist browsing — which won't work for content not on Apple Music (unreleased music, remixes, etc.).

How do I group content into albums/eras?

Return them as albums in your /search response, then implement /album/{id} to return the tracks for each group. For example, an unreleased music addon could group songs by "era" and return each era as an album.

Can users save addon tracks offline?

Yes — tracks with a streamURL (direct URL) can be downloaded for offline listening. Users can save individual tracks or bulk-download entire playlists. Offline playback works without your addon server.

Can my addon be set as the default playback source?

Yes — if your manifest includes "stream" in resources, your addon appears in Settings → Addon Management → Default Playback. When selected, Eclipse searches your addon for songs played from Home, Radio, DJ, editorial playlists, etc. Return the best match from your search endpoint.

What if my addon uses token-based URLs?

Include the token in your base URL: https://my-addon.com/{user_token}/manifest.json. Eclipse strips /manifest.json and uses the rest as the base URL. All subsequent calls (/search, /stream, /album, etc.) include the token prefix automatically.

Can I return year as a number instead of a string?

Yes — Eclipse accepts "year": 2024 (number) or "year": "2024" (string) for albums. Both work.

Do I need to return all search result types?

No. Return only what you have. A podcast addon might return only tracks. A music library addon might return tracks, albums, and artists. Eclipse handles missing arrays gracefully.

Can users import playlists through my addon?

Yes — your addon appears as a match service in the Import Playlist flow. When importing a Spotify or Apple Music playlist, Eclipse searches your addon for each track and creates a local playlist with matches.