# Gruuv Music Events Specification
This document details how Gruuv uses Nostr events for decentralized music library management, playlist synchronization, and real-time status updates. Adhering to these conventions allows other applications to interoperate seamlessly with the Gruuv ecosystem.
## Overview
Gruuv leverages Nostr's decentralized relay network to store and synchronize music metadata. By using Parameterized Replaceable Events (NIP-33), users can maintain a consistent music library across different devices and applications without a central server.
## Event Kinds
Gruuv primarily utilizes the following Nostr event kinds:
| Kind | Description | NIP / Specification |
|------|-------------|---------------------|
| `36787` | **Addressable Music Track** | Primary metadata for a single audio track. |
| `34139` | **Music Playlist** | A collection of references to music tracks. |
| `30315` | **User Status** | Real-time "Now Playing" status (NIP-38). |
| `1063` | **File Metadata** | Alternative/Legacy metadata format (NIP-94). |
| `5` | **Event Deletion** | Hard deletion of events (NIP-09). |
| `10063` | **Blossom Server List** | User's preferred Blossom storage servers. |
| `10002` | **Relay List Metadata** | User's preferred relays for discovery (NIP-65). |
---
## 1. Music Track (Kind 36787)
The `36787` event is a Parameterized Replaceable Event representing a single music track.
### Tags
| Tag | Description | Required | Example |
|-----|-------------|----------|---------|
| `d` | Unique identifier for the track (usually a random string or hash). | Yes | `["d", "5f2a1b9c..."]` |
| `url` | Direct link to the audio file (typically on a Blossom server). | Yes | `["url", "
https://blossom.example.com/abcd...mp3"]` |
| `title` | The name of the track. | Yes | `["title", "Neon Lights"]` |
| `artist` | The performing artist. | Yes | `["artist", "The Groovers"]` |
| `album` | The album name. | No | `["album", "Night City"]` |
| `duration` | Total length in seconds. | Yes | `["duration", "240"]` |
| `size` | File size in bytes. | No | `["size", "5242880"]` |
| `image` | URL to the cover art. | No | `["image", "
https://.../cover.jpg"]` |
| `x` | SHA-256 hash of the audio file. | Recommended | `["x", "sha256-hex-hash..."]` |
| `released` | Release date (YYYY-MM-DD format). | No | `["released", "2024-05-30"]` |
| `genre` | Musical genre. | No | `["genre", "Synthwave"]` |
| `track_number` | Position in the album. | No | `["track_number", "3"]` |
| `disc_number` | Disc index for multi-disc sets. | No | `["disc_number", "1"]` |
| `format` | Audio encoding format. | No | `["format", "mp3"]` |
| `t` | Application identifier and genres. | Yes | `["t", "gruuv"], ["t", "synthwave"]` |
| `deleted` | Presence indicates a "soft-deleted" track. | No | `["deleted"]` |
### Example Event
```json
{
"kind": 36787,
"content": "Listen to my song - Neon Lights by The Groovers",
"tags": [
["d", "track-xyz-123"],
["url", "
https://blossom.primal.net/hash.mp3"],
["title", "Neon Lights"],
["artist", "The Groovers"],
["album", "Night City"],
["duration", "240"],
["t", "gruuv"],
["t", "synthwave"],
["image", "
https://example.com/cover.png"],
["alt", "Song: Neon Lights - The Groovers"]
],
"pubkey": "...",
"id": "...",
"sig": "..."
}
```
---
## 2. Music Playlist (Kind 34139)
The `34139` event represents a curated list of music tracks.
### Tags
| Tag | Description | Required | Example |
|-----|-------------|----------|---------|
| `d` | Unique identifier for the playlist. | Yes | `["d", "summer-vibes-2024"]` |
| `title` | Playlist name. | Yes | `["title", "Summer Vibes"]` |
| `description` | A short description of the playlist. | No | `["description", "Best tracks for summer."]` |
| `image` | Playlist cover art. | No | `["image", "
https://.../playlist.jpg"]` |
| `a` | References to tracks in `kind:pubkey:d` format. | Yes | `["a", "36787:<pubkey>:<d-tag>"]` |
| `t` | Application identifier. | Yes | `["t", "gruuv"]` |
| `deleted` | Presence indicates a "soft-deleted" playlist. | No | `["deleted"]` |
### Example Event
```json
{
"kind": 34139,
"content": "A collection of my favorite tracks",
"tags": [
["d", "my-favorites"],
["title", "My Favorites"],
["description", "Curated by me"],
["a", "36787:pubkey_1:track_d_tag_1"],
["a", "36787:pubkey_1:track_d_tag_2"],
["t", "gruuv"]
],
"pubkey": "...",
"id": "...",
"sig": "..."
}
```
---
## 3. Now Playing Status (Kind 30315)
Gruuv uses NIP-38 User Status events to broadcast what a user is currently listening to.
### Tags
| Tag | Description | Required | Example |
|-----|-------------|----------|---------|
| `d` | Category of status (always `music` for Gruuv). | Yes | `["d", "music"]` |
| `a` | Reference to the track being played. | Recommended | `["a", "36787:<pubkey>:<d-tag>"]` |
| `r` | URL of the track. | No | `["r", "
https://.../song.mp3"]` |
| `expiration` | When this status expires. | Recommended | `["expiration", "1717084800"]` |
| `t` | Application identifier. | Yes | `["t", "gruuv"]` |
### Example Event
```json
{
"kind": 30315,
"content": "Neon Lights - The Groovers",
"tags": [
["d", "music"],
["a", "36787:pubkey:track-xyz-123"],
["r", "
https://blossom.primal.net/hash.mp3"],
["t", "gruuv"],
["alt", "Now playing: Neon Lights by The Groovers on Gruuv"]
],
"pubkey": "...",
"id": "...",
"sig": "..."
}
```
---
## 4. Interoperability Conventions
### Application Discovery
To filter for events created or managed by Gruuv (or compatible apps), clients should look for the `t` tag with the value `gruuv` or `grooveblossom`.
### Soft Deletion
Instead of immediately issuing a Kind 5 deletion, Gruuv often performs a "soft delete" by publishing a new version of the replaceable event (`36787` or `34139`) with a `["deleted"]` tag. This allows for better synchronization across clients that might miss a specific deletion event.
### Audio Storage (Blossom)
Gruuv prioritizes the use of **Blossom** (a decentralized file storage protocol) for hosting audio files. Users can specify their preferred Blossom servers in a `Kind 10063` event. Authentication for uploads is performed via NIP-98 (`Kind 24242`).
### Metadata Synchronization
When a user "clones" a track or playlist to their library, the app creates a new `Kind 36787` or `Kind 34139` event under the user's own pubkey, referencing the original content. This ensures the user's library remains independent of the original creator's event persistence.