A matterbridge bot that detects music links (Spotify, YouTube, Apple Music, etc.) in chat messages and responds with equivalent links on other platforms. Features: - Connects to matterbridge via WebSocket API - Detects links from 7 music services (Spotify, YouTube, Apple, Deezer, etc.) - Uses idonthavespotify API for conversion (no API credentials required) - Automatic reconnection with exponential backoff - Platform setup guide for NixOS deployment Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
11 KiB
MusicLink Bot - Platform Setup Guide
Overview
MusicLink is a bot that detects music links (Spotify, YouTube, Apple Music, etc.) in chat messages and responds with equivalent links on other streaming services.
It uses the idonthavespotify API for link conversion, so no Spotify/YouTube API credentials are required.
Architecture
┌─────────────────────────── jrz1 (NixOS VPS) ───────────────────────────┐
│ │
│ ┌─────────────────────────┐ ┌─────────────────────────────┐ │
│ │ matterbridge.service │ │ musiclink.service │ │
│ │ │ │ │ │
│ │ Bridges chat platforms │ WS │ Detects music links and │ │
│ │ and exposes local API │◄─────►│ responds with alternatives │ │
│ │ │ │ │ │
│ │ - Slack bridge │ │ - Link detection (regex) │ │
│ │ - API bridge (:4242) │ │ - Calls idonthavespotify │ │
│ │ - (Discord, Matrix │ │ API for conversion │ │
│ │ can be added later) │ │ │ │
│ └────────────┬────────────┘ └──────────────┬──────────────┘ │
│ │ │ │
└───────────────┼────────────────────────────────────┼────────────────────┘
│ │
▼ ▼
┌───────────┐ ┌────────────────────┐
│ Slack │ │ idonthavespotify │
└───────────┘ │ (external API) │
└────────────────────┘
How It Works
- User posts a music link in Slack (e.g.,
https://open.spotify.com/track/abc123) - Matterbridge forwards the message to musiclink via WebSocket
- MusicLink detects the music URL and calls the idonthavespotify API
- The API returns equivalent links for Spotify, YouTube, Apple Music, Tidal, Deezer, etc.
- MusicLink formats and sends the response back through matterbridge to Slack
Why Matterbridge?
Matterbridge acts as a universal adapter. Instead of writing platform-specific code for each chat service, we:
- Run matterbridge (connects to Slack, Discord, Matrix, etc.)
- Matterbridge exposes a simple WebSocket API locally
- Our bot connects to that API and receives/sends messages as JSON
This means:
- Adding a new platform = config change in matterbridge (no code changes)
- Bot code stays simple = just WebSocket + JSON, works from any language
- Already in nixpkgs =
services.matterbridgemodule ready to use
Why idonthavespotify API?
- No API credentials needed - No Spotify Developer account, no YouTube API keys
- Supports 8 platforms - Spotify, YouTube, Apple Music, Deezer, Tidal, SoundCloud, Qobuz, Bandcamp
- Simple integration - Single HTTP POST, returns all platform links
- Open source - Can self-host if needed later
Components
1. Matterbridge (existing nixpkgs module)
Package: pkgs.matterbridge (v1.26.0)
Module: services.matterbridge
Docs: https://github.com/42wim/matterbridge/wiki
2. MusicLink Bot (this repo)
Language: Go
Location: /home/dan/proj/musiclink
Connects to: Matterbridge API via WebSocket
Uses: idonthavespotify API for link conversion
NixOS Configuration
Matterbridge Service
{ config, pkgs, ... }:
{
services.matterbridge = {
enable = true;
configPath = "/var/lib/matterbridge/matterbridge.toml";
};
# Ensure config directory exists
systemd.tmpfiles.rules = [
"d /var/lib/matterbridge 0750 matterbridge matterbridge -"
];
}
MusicLink Service
{ config, pkgs, ... }:
let
musiclink = pkgs.buildGoModule {
pname = "musiclink";
version = "0.1.0";
src = /home/dan/proj/musiclink; # or fetchFromGitHub
vendorHash = null; # update after first build
};
in
{
systemd.services.musiclink = {
description = "MusicLink Bot";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" "matterbridge.service" ];
requires = [ "matterbridge.service" ];
serviceConfig = {
Type = "simple";
ExecStart = "${musiclink}/bin/musiclink -config /var/lib/musiclink/config.toml";
Restart = "always";
RestartSec = "5s";
# Hardening
DynamicUser = true;
StateDirectory = "musiclink";
ProtectSystem = "strict";
ProtectHome = true;
NoNewPrivileges = true;
};
};
systemd.tmpfiles.rules = [
"d /var/lib/musiclink 0750 musiclink musiclink -"
];
}
Configuration Files
Matterbridge (/var/lib/matterbridge/matterbridge.toml)
# =============================================================================
# Matterbridge Configuration
# Bridges Slack to local API for musiclink bot
# =============================================================================
# -----------------------------------------------------------------------------
# Slack Connection
# -----------------------------------------------------------------------------
[slack.workspace]
# Bot User OAuth Token (starts with xoxb-)
# Get from: https://api.slack.com/apps → Your App → OAuth & Permissions
Token = "xoxb-YOUR-SLACK-BOT-TOKEN"
# Show username before messages
PrefixMessagesWithNick = true
# Optional: customize how remote users appear
RemoteNickFormat = "[{PROTOCOL}] {NICK}"
# -----------------------------------------------------------------------------
# Local API Bridge (for musiclink bot)
# -----------------------------------------------------------------------------
[api.musiclink]
# Only bind to localhost (not exposed externally)
BindAddress = "127.0.0.1:4242"
# Shared secret for bot authentication
Token = "GENERATE-A-RANDOM-TOKEN-HERE"
# Message buffer size
Buffer = 1000
# -----------------------------------------------------------------------------
# Gateway Configuration
# Routes messages between bridges
# -----------------------------------------------------------------------------
[[gateway]]
name = "main"
enable = true
# Slack channels to bridge
[[gateway.inout]]
account = "slack.workspace"
channel = "music" # Change to your channel name
# API endpoint for musiclink bot
[[gateway.inout]]
account = "api.musiclink"
channel = "api"
MusicLink (/var/lib/musiclink/config.toml)
# =============================================================================
# MusicLink Bot Configuration
#
# Uses idonthavespotify API - no external API credentials needed!
# =============================================================================
[matterbridge]
# Must match matterbridge API bridge config
url = "ws://127.0.0.1:4242/api/websocket"
token = "GENERATE-A-RANDOM-TOKEN-HERE" # Same as matterbridge [api.musiclink].Token
gateway = "main"
# Bot identity
username = "MusicLink"
avatar = "" # Optional URL
That's the entire config - no Spotify/YouTube API keys required!
Secrets Management
The only secrets needed are:
- Slack bot token (
xoxb-...) - Matterbridge↔MusicLink shared token (generate a random string)
Options for managing secrets:
- sops-nix - Encrypted secrets in repo, decrypted at deploy time
- agenix - Age-encrypted secrets
- Environment files -
EnvironmentFile=in systemd service
Example with environment file:
systemd.services.matterbridge.serviceConfig = {
EnvironmentFile = "/run/secrets/matterbridge.env";
};
# /run/secrets/matterbridge.env
MATTERBRIDGE_SLACK_TOKEN=xoxb-...
Then in matterbridge.toml:
[slack.workspace]
Token = "${MATTERBRIDGE_SLACK_TOKEN}"
Slack App Setup
- Go to https://api.slack.com/apps
- Create New App → From scratch
- App name: "MusicLink", select workspace
- OAuth & Permissions:
- Bot Token Scopes needed:
channels:history- Read messageschannels:read- See channel listchat:write- Send messagesusers:read- Get user info
- Bot Token Scopes needed:
- Install to Workspace
- Copy Bot User OAuth Token (
xoxb-...) - Invite bot to channel:
/invite @MusicLink
Deployment Checklist
- Slack app created and bot token obtained
- Generate random token for matterbridge↔musiclink auth
- Add matterbridge NixOS config
- Create
/var/lib/matterbridge/matterbridge.toml - Add musiclink NixOS config
- Create
/var/lib/musiclink/config.toml - Deploy NixOS config (
nixos-rebuild switch) - Verify services:
systemctl status matterbridge musiclink - Test: Post a Spotify link in the configured Slack channel
Logs & Debugging
# Check service status
systemctl status matterbridge
systemctl status musiclink
# View logs
journalctl -u matterbridge -f
journalctl -u musiclink -f
# Test matterbridge API directly
curl -H "Authorization: Bearer YOUR-TOKEN" http://localhost:4242/api/health
# Test idonthavespotify API directly
curl -X POST 'https://idonthavespotify.sjdonado.com/api/search?v=1' \
-H 'Content-Type: application/json' \
-d '{"link":"https://open.spotify.com/track/4iV5W9uYEdYUVa79Axb7Rh"}'
Adding More Platforms Later
To add Discord, Matrix, or other platforms, just update matterbridge.toml:
# Add Discord
[discord.myserver]
Token = "discord-bot-token"
Server = "server-id"
# Add to gateway
[[gateway.inout]]
account = "discord.myserver"
channel = "music"
No changes needed to musiclink bot - matterbridge handles the bridging.
Self-Hosting idonthavespotify (Optional)
If you want to avoid the external API dependency, idonthavespotify can be self-hosted:
- Repo: https://github.com/sjdonado/idonthavespotify
- Requires: Docker or Bun runtime
- Note: Self-hosting still requires Spotify/Tidal API credentials
For most use cases, the hosted API at idonthavespotify.sjdonado.com is sufficient.
Questions?
- Matterbridge docs: https://github.com/42wim/matterbridge/wiki
- idonthavespotify: https://github.com/sjdonado/idonthavespotify
- MusicLink repo:
/home/dan/proj/musiclink