Radio streamer (kawa drop-in compatible) https://radio.animebits.moe/player/hash/5ff661960216
Go to file
DataHoarder eec79cb3ab
continuous-integration/drone/push Build is passing Details
Expose unix timestamp on /listeners
2022-08-23 21:47:09 +02:00
.drone.yml Update to go 1.19 minimum 2022-08-02 20:58:59 +02:00
.gitignore Initial commit, WiP 2022-03-02 00:31:29 +01:00
Dockerfile Update to go 1.19 minimum 2022-08-02 20:58:59 +02:00
LICENSE Initial commit, WiP 2022-03-02 00:31:29 +01:00
MeteorLight.go Adjust read/write buffers for streamer 2022-03-07 17:33:37 +01:00
PACKET_STREAM.md Add information about the packet stream 2022-07-16 14:49:47 +02:00
README.md Expose unix timestamp on /listeners 2022-08-23 21:47:09 +02:00
api.go Retry random track, better error reporting 2022-08-01 14:47:52 +02:00
config.go Update Kirika, allow configuring queue sample format and bitdepth 2022-07-19 17:21:51 +02:00
example_config.toml Added Vorbis encoding support 2022-07-28 15:52:39 +02:00
go.mod Added now playing metadata logs, updated dependencies 2022-08-18 08:28:18 +02:00
go.sum Added now playing metadata logs, updated dependencies 2022-08-18 08:28:18 +02:00
http.go Create new client per-request 2022-08-18 10:28:46 +02:00
listener.go Use new go.19 atomic[T] 2022-08-02 21:24:23 +02:00
mount.go Expose unix timestamp on /listeners 2022-08-23 21:47:09 +02:00
queue.go Expose unix timestamp on /listeners 2022-08-23 21:47:09 +02:00

README.md

MeteorLight

Radio streamer (kawa drop-in compatible).

Improvements / differences from Kawa

  • Does not use libav (see supported formats/codecs on Kirika)
  • Supports HTTP clients that have more than 16 HTTP request headers or longer than 64 bytes per header.
  • Does not restart stream per-track, instead being a continuous stream without parameter changes.
  • Normalized channels / sample rates for all mounts.
  • Implements ICY metadata (artist, title, url).
  • Uses sample/timed packet buffers, instead of kawa byte buffers, which caused wild differences between endpoints. Mounts usually align within 0.2s of each other, depending on client.
    • Use queue.buffer_size to specify number of seconds to buffer (by default 0, automatic per client).
  • Implements queue.nr and /random (to be deprecated/changed).
  • Supports max queue length via queue.length config.
  • Supports extra encoder bitrate control settings (CBR, VBR, auto, etc.)
  • Can set custom sample rate / channel count / bitdepth / compression level per stream mount.
  • Can read and apply ReplayGain tags, or normalize audio loudness.
  • Can have audio sources over HTTP(s) URLs on path property, and supports seeking.
  • Precise metadata and timing information packet stream, trigger via x-audio-packet-stream: 1 HTTP header.
  • Workaround to allow FLAC streaming under Safari.
  • API additions to allow working with direct queue items or listeners.

Dependencies

Go >= 1.19

Kirika dependencies

Kirika is a collection of audio utilities for decoding/encoding files and streams.

Check its native dependencies that must be installed before usage.

Usage

Start by copying example_config.toml to the location of your choice and reading through it. Of importance are queue.fallback, and queue.random_song_api.

MeteorLight will search for config.toml in its working directory. Alternatively you can pass -config "/example/path/config.toml" to specify a different location.

Batteries are not included - MeteorLight needs to be paired with your own software to find songs to stream. You will have to provide an external API that MeteorLight can query for songs to play and notify as new songs being played.

Before continuing, you will need to install the dependencies listed above.

From Git repository

$ git clone https://git.gammaspectra.live/S.O.N.G/MeteorLight.git && cd MeteorLight
# create/edit config.toml
$ go run . 

From Go run

$ go run git.gammaspectra.live/S.O.N.G/MeteorLight@<commit_hash>

From Docker/Podman

Image is using golang:1.19-alpine, dependencies are built from scratch. See Dockerfile.

$ docker build -t meteorlight .
$ docker run --rm -it -v "$(pwd)/config.toml:/config.toml:ro" -v "$(pwd)/fallback.flac:/fallback.flac:ro" -p 8001:8001 -p 127.0.0.1:4040:4040 meteorlight

API

See kawa API for a general overview. Additional endpoints or changed ones are listed below.

Track blobs returned have a queue_id parameter, regardless of source.

Queue entry metadata (title, artist, album, and ReplayGain tags track_peak, track_gain, album_peak, album_gain) will be used if provided, then fallback to on-file tags where possible. These will be made available over /np and similar endpoints, and be exposed via ICY metadata and timing/metadata stream.

NEW DELETE /queue/<queue_id>

Unqueues the track with queue_id specified as a parameter.

Response

{
    "success": true,
    "reason": null
}

CHANGED POST /queue/head

Same as kawa's, but queue_id is added to response directly.

Response

{
    "success": true,
    "reason": null,
    "queue_id": 3
}

CHANGED POST /queue/tail

Same as kawa's, but queue_id is added to response directly.

Response

{
    "success": true,
    "reason": null,
    "queue_id": 5
}

NEW DELETE /listeners/<listener_id>

Drops the listener connection with listener_id specified as a parameter.

Response

{
    "success": true,
    "reason": null
}

CHANGED GET /listeners

Same as kawa's, but identifier and start is added to each listener entry.

The listener identifier is generated based on user connection address, port, user-agent and mount.

The start field denotes the unix time this listener connected.

Additionally, a x-listener-identifier header is exposed to mount response.

Response

[
  {
    "identifier": "641df131cb52f8f6381d9946cccb822e",
    "mount": "stream.flac",
    "path": "/stream.flac",
    "start": 1661283903,
    "headers": [
      {
        "name": "User-Agent",
        "value": "libmpv"
      },
      {
        "name": "Accept",
        "value": "*/*"
      },
      {
        "name": "Range",
        "value": "bytes=0-"
      },
      {
        "name": "Connection",
        "value": "close"
      },
      {
        "name": "Icy-Metadata",
        "value": "1"
      }
    ]
  }
]

Mount API

NEW GET /mounts

A simple listing of the working mounts + settings are made available.

Response

[
  {
    "mount": "/stream128.mp3",
    "mime": "audio/mpeg;codecs=mp3",
    "sampleRate": 44100,
    "channels": 2,
    "listeners": 0,
    "options": {
      "bitrate": 128
    }
  },
  {
    "mount": "/stream192.mp3",
    "mime": "audio/mpeg;codecs=mp3",
    "sampleRate": 44100,
    "channels": 2,
    "listeners": 0,
    "options": {
      "bitrate": 192
    }
  },
  {
    "mount": "/stream128.aac",
    "mime": "audio/aac",
    "sampleRate": 44100,
    "channels": 2,
    "listeners": 0,
    "options": {
      "bitrate": 128
    }
  },
  {
    "mount": "/stream128.opus",
    "mime": "audio/ogg;codecs=opus",
    "sampleRate": 48000,
    "channels": 2,
    "listeners": 0,
    "options": {
      "bitrate": 128
    }
  },
  {
    "mount": "/stream192.opus",
    "mime": "audio/ogg;codecs=opus",
    "sampleRate": 48000,
    "channels": 2,
    "listeners": 0,
    "options": {
      "bitrate": 192
    }
  },
  {
    "mount": "/stream256.opus",
    "mime": "audio/ogg;codecs=opus",
    "sampleRate": 48000,
    "channels": 2,
    "listeners": 0,
    "options": {
      "bitrate": 256
    }
  },
  {
    "mount": "/stream.flac",
    "mime": "audio/flac",
    "sampleRate": 44100,
    "channels": 2,
    "listeners": 0,
    "options": {
      "bitdepth": 16,
      "block_size": 0,
      "compression_level": 5
    }
  }
]