diff options
| author | kieran <kieran@harkin.me> | 2025-02-17 12:00:05 +0000 |
|---|---|---|
| committer | Kieran <kieran@harkin.me> | 2025-07-17 12:28:09 +0100 |
| commit | 39fbfb5ada692dcbec0a699e82bd963ebda583c5 (patch) | |
| tree | 3b2519ba4cf5a52c20b8fec901f9ff8d1122ab1c | |
| parent | 1afb6da049e57dd628ef46a3b0f90300653a66ee (diff) | |
5e
| -rw-r--r-- | 5E.md | 119 |
1 files changed, 119 insertions, 0 deletions
| @@ -0,0 +1,119 @@ | |||
| 1 | # NIP-5E | ||
| 2 | |||
| 3 | ## Censorship Resistant Live Streams | ||
| 4 | |||
| 5 | `draft` `optional` | ||
| 6 | |||
| 7 | Describes a way to distribute live video streams via nostr. | ||
| 8 | |||
| 9 | **"Live Video" in this context implies segmented video streams like HLS or DASH** | ||
| 10 | |||
| 11 | ## N94 Stream | ||
| 12 | |||
| 13 | A new `kind: 1053` event lists a single live stream. | ||
| 14 | |||
| 15 | Example: | ||
| 16 | |||
| 17 | ```jsonc | ||
| 18 | { | ||
| 19 | "kind": 1053, | ||
| 20 | "tags": [ | ||
| 21 | ["title", "<name of the event>"], | ||
| 22 | ["summary", "<description>"], | ||
| 23 | ["image", "<preview image url>"], | ||
| 24 | [ | ||
| 25 | "variant", | ||
| 26 | "dim 1920x1080", | ||
| 27 | "bitrate 5000000", | ||
| 28 | "m video/mp2t", | ||
| 29 | "d 1080p" | ||
| 30 | ], | ||
| 31 | [ | ||
| 32 | "variant", | ||
| 33 | "dim 1280x720", | ||
| 34 | "bitrate 3000000", | ||
| 35 | "m video/mp2t", | ||
| 36 | "d 720p" | ||
| 37 | ], | ||
| 38 | [ | ||
| 39 | "variant", | ||
| 40 | "dim 1920x1080", | ||
| 41 | "bitrate 6000000", | ||
| 42 | "m video/mp4", | ||
| 43 | "d 1080p-fmp4" | ||
| 44 | ], | ||
| 45 | ["t", "hashtag"] | ||
| 46 | ["starts", "<unix timestamp in seconds>"], | ||
| 47 | ["ends", "<unix timestamp in seconds>"], | ||
| 48 | ["relays", "wss://one.com", "wss://two.com", /*...*/], | ||
| 49 | ["pinned", "<event id of pinned live chat message>"], | ||
| 50 | ], | ||
| 51 | "content": "", | ||
| 52 | // other fields... | ||
| 53 | } | ||
| 54 | ``` | ||
| 55 | |||
| 56 | The `variant` tag works like `imeta` tag from [NIP-92](92.md) and defines a variant stream. | ||
| 57 | |||
| 58 | The `d` entry of the `variant` tag is used in the NIP-94 segment event for variant following. | ||
| 59 | |||
| 60 | ## N94 Segment | ||
| 61 | |||
| 62 | Each segment of the stream is a [NIP-94](94.md) event which describes where the file can be found and its hash. | ||
| 63 | |||
| 64 | ```jsonc | ||
| 65 | { | ||
| 66 | "kind": 1063, | ||
| 67 | "tags": [ | ||
| 68 | ["d", "1080p"] | ||
| 69 | ["e", "<id-of-kind-1053>"], | ||
| 70 | ["x", "<sha256>"], | ||
| 71 | ["m", "video/mp2t"], | ||
| 72 | ["dim", "1920x1080"], | ||
| 73 | ["duration", "2.033"], | ||
| 74 | ["index", "1234"], | ||
| 75 | ["url", "https://example.com/1234.ts"], | ||
| 76 | ["fallback", "https://another.com/1234.ts"], | ||
| 77 | ["service", "blossom"], | ||
| 78 | ... | ||
| 79 | ] | ||
| 80 | // other fields... | ||
| 81 | } | ||
| 82 | ``` | ||
| 83 | |||
| 84 | Aside from the standard NIP-94 tags: | ||
| 85 | |||
| 86 | - `d`: Variant stream tag. | ||
| 87 | - `index`: Segment index, a simple counter. Used of ordering. | ||
| 88 | |||
| 89 | `service` tag should be used for extended censorship resitance by looking up the appropriate server list (Blossom) of the uploader and checking for files on alternate servers. | ||
| 90 | |||
| 91 | ## Implementors | ||
| 92 | |||
| 93 | ### Consumers | ||
| 94 | |||
| 95 | Clients wishing to implement a player should use [MSE](https://developer.mozilla.org/en-US/docs/Web/API/Media_Source_Extensions_API) or similar technologies which allow appending data to the player buffer. | ||
| 96 | |||
| 97 | Other services MAY provide a compatability layer with [NIP-53](53.md) live streams by producing HLS playlists over a N94 Stream. | ||
| 98 | |||
| 99 | Clients SHOULD follow only a single variant by using a filter like this: | ||
| 100 | |||
| 101 | `{"kinds":[1063],"#e":["<id-of-kind-5053>"],"#d":["1080p"],"limit":10}` | ||
| 102 | |||
| 103 | Leaving the subscription open will allow clients to be notified immediately as segments are published and can fetch those segments and append them to the player buffer. | ||
| 104 | |||
| 105 | ### Producers | ||
| 106 | |||
| 107 | Segment length SHOULD be carefully considered as a trade off between stream delay and total number of NIP-94 events / segment files. | ||
| 108 | |||
| 109 | Using `expiration` tags on N94 segments and deleting segment files from servers SHOULD be used to cleanup streams which don't want to persist after the stream is finished. | ||
| 110 | |||
| 111 | ## Example implementations: | ||
| 112 | |||
| 113 | ### Player | ||
| 114 | |||
| 115 | [zap.stream](https://github.com/v0l/zap.stream/blob/main/src/element/stream/n94-player.tsx) | ||
| 116 | |||
| 117 | ### Producer | ||
| 118 | |||
| 119 | [zap-stream-core](https://github.com/v0l/zap-stream-core/blob/ccb2add6073e5bb68191c42613c34f66583e34fc/crates/zap-stream/src/overseer.rs#L340-L380) | ||