Add NIP-XX: Nostr Internet Radio#1975
Conversation
staab
left a comment
There was a problem hiding this comment.
Overall this looks good, and I like the idea. Most of my comments are oriented at brevity, it's not necessary to re-define stuff common to the entire protocol or advise on security/privacy stuff. I have a few suggestions related to data modeling, most important being indexable tags — on nostr only single-character tags are indexable, so if you want location or language to be indexed you need to use l or g (or something).
| "tags": [ | ||
| ["d", "<station-identifier>"], | ||
| ["name", "<station-name>"], | ||
| ["t", "<genre>"], |
There was a problem hiding this comment.
Interesting, i'll definitely contemplate that.
| ["d", "<station-identifier>"], | ||
| ["name", "<station-name>"], | ||
| ["t", "<genre>"], | ||
| ["language", "<ISO-639-1-code>"], |
There was a problem hiding this comment.
It might be nice to search by language, l is already used elsewhere for language
| ["t", "<genre>"], | ||
| ["language", "<ISO-639-1-code>"], | ||
| ["countryCode", "<ISO-3166-2-code>"], | ||
| ["location", "<human-readable-location>"], |
There was a problem hiding this comment.
g might be a useful addition for locating stations by geohash
| ["location", "<human-readable-location>"], | ||
| ["thumbnail", "<image-url>"], | ||
| ["website", "<station-website>"], | ||
| ["client", "<client-name>", "<handler-address>", "<relay-hint>"] |
There was a problem hiding this comment.
This should be left out of the nip, since this tag is defined elsewhere and can be applied as needed by the implementation.
|
|
||
| ### Content Format | ||
|
|
||
| The `content` field MUST contain a JSON string with the following structure: |
There was a problem hiding this comment.
Data modeling is conventionally done with tags; content should generally be human readable (kind 0 notwithstanding). Moving streams to tags might be done using something like imeta, for example:
"tags": [
["stream", "url https://stream.example.com/radio.mp3", "format audio/mpeg", "bitrate 12800", "codec mp3", "sampleRate 44100"]
]
Idiosyncratic, I know. But it requires less json-in-json, and you can include multiple stream tags.
| ## Rationale | ||
|
|
||
| Traditional internet radio directories are centralized services controlled by single entities, making them vulnerable to censorship, takedowns, and service discontinuation. Radio stations and listeners lack data portability between different platforms and applications. | ||
|
|
||
| This specification leverages Nostr's decentralized infrastructure to create an open, censorship-resistant radio ecosystem where: | ||
|
|
||
| - Radio stations can publish their metadata and streaming information directly | ||
| - Users maintain portable favorites lists across applications | ||
| - Developers can build interoperable radio clients without vendor lock-in | ||
| - Communities can engage around stations through comments and live chat | ||
| - Discovery happens through the network rather than centralized algorithms | ||
| - Organic, decentralized maintenance of station entries helps keep quality high and mitigate broken links | ||
| - Direct listener-to-station monetization becomes possible through Nostr's native micropayment capabilities | ||
|
|
||
| ## Overview | ||
|
|
||
| This specification defines radio station events and describes how existing Nostr protocols can be used to create a complete radio ecosystem: | ||
|
|
||
| - **Radio Station Events** (`kind:31237`) - Station metadata and streaming information (defined in this NIP) | ||
| - **Live Chat Messages** - Real-time chat during streaming using existing live chat protocols | ||
| - **Station Comments** - Persistent discussion threads using existing comment protocols | ||
| - **Favorites Management** - Personal and curated station collections using [NIP-78](78.md) | ||
| - **Application Discovery** - Handler registration using [NIP-89](89.md) |
There was a problem hiding this comment.
This should all be removed, NIPs are better when they're terse
|
|
||
| - The `d` tag value SHOULD be descriptive and stable for the station | ||
| - Multiple stations can be published by the same pubkey using different `d` tags | ||
| - Clients SHOULD use the station name as a fallback identifier |
There was a problem hiding this comment.
The fallback for an event with no d tag is an empty string
| ### Streaming Compatibility | ||
|
|
||
| - Support multiple stream formats for broader client compatibility | ||
| - Include quality metadata to enable adaptive streaming | ||
| - Mark one stream as `primary` for default selection |
There was a problem hiding this comment.
This is too vague, it's better to just define expected metadata tags as they become necessary. primary is fine, but I would just assume the first stream is the default
| ### Privacy Considerations | ||
|
|
||
| - The `client` tag has privacy implications - clients SHOULD allow opt-out | ||
| - Station owners can moderate chat/comments by maintaining block lists | ||
| - Consider rate limiting for chat messages to prevent spam | ||
|
|
||
| ## Security Considerations | ||
|
|
||
| - Validate stream URLs before playback to prevent malicious redirects | ||
| - Sanitize station descriptions when rendering markdown content | ||
| - Implement reasonable limits on metadata size to prevent DoS attacks | ||
| - Verify signatures on all events before processing | ||
|
|
||
| ## Backwards Compatibility | ||
|
|
||
| This specification introduces new event kinds that do not conflict with existing NIPs. Clients that don't understand `kind:31237` can safely ignore these events without affecting other functionality. |
There was a problem hiding this comment.
This is all out of scope or defined elsewhere in the protocol
| ## Conclusion | ||
|
|
||
| This specification enables a decentralized internet radio ecosystem built on Nostr's foundation of censorship resistance and data portability. By standardizing station metadata, social features, and application discovery, it creates interoperability between radio clients while preserving user autonomy and freedom of choice. |
…ity and privacy considerations.
…usion from XX.md to streamline content and focus on essential specifications.
…ty; change example value to a random identifier and clarify default behavior.
…protocol documentation.
…nd clarity in stream object specifications.
…ocument and focus on the core specifications of the radio station events.
…equirements and enhance document clarity.
… stream object specifications and discovery requirements.
Change tag name from 't' to 'c' for station categories and add facet parameter. Update example to demonstrate new tag format and correct website URL.
What this adds
A standard for publishing internet radio stations on Nostr as
kind:31237events, enabling decentralized radio directories and cross-app compatibility. Current open solutions use awkward semi-community driven flows to maintain quality of their registries leading to broken streams and outdated metadata. The direct monetization could incentivize station runners and listeners to maintain station entries ensuring a cleaner registry.Why we need this
Current radio directories are centralized platforms that control discovery and can deplatform stations. Users lose their favorites when services shut down, and there's no interoperability between radio apps.
How it works
Key benefits
Implementation
Builds on proven Nostr patterns:
Working reference implementation: WaveFunc
Request for feedback
This introduces
kind:31237without conflicting with existing NIPs. Looking for community input on the event structure and integration approach.