commit 39073d8f3a2ed83abc8efd39d71f67931242c347 Author: Tobias Reisinger Date: Tue Aug 8 19:29:03 2023 +0200 Init diff --git a/README.md b/README.md new file mode 100644 index 0000000..847afe3 --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# Home Assistant add-on repository + +Add-on documentation: + +[![Open your Home Assistant instance and show the add add-on repository dialog with a specific repository URL pre-filled.](https://my.home-assistant.io/badges/supervisor_add_addon_repository.svg)](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgit.serguzim.me%2Fserguzim%2Fhome-assistant-addons) + +## Add-ons + +This repository contains the following add-ons + +### [Snapcast](./snapcast) + +![Supports aarch64 Architecture][aarch64-shield] +![Supports amd64 Architecture][amd64-shield] +![Supports armhf Architecture][armhf-shield] +![Supports armv7 Architecture][armv7-shield] +![Supports i386 Architecture][i386-shield] + +[aarch64-shield]: https://img.shields.io/badge/aarch64-yes-green.svg +[amd64-shield]: https://img.shields.io/badge/amd64-yes-green.svg +[armhf-shield]: https://img.shields.io/badge/armhf-yes-green.svg +[armv7-shield]: https://img.shields.io/badge/armv7-yes-green.svg +[i386-shield]: https://img.shields.io/badge/i386-yes-green.svg diff --git a/repository.yml b/repository.yml new file mode 100644 index 0000000..a69c49f --- /dev/null +++ b/repository.yml @@ -0,0 +1,4 @@ +# https://developers.home-assistant.io/docs/add-ons/repository#repository-configuration +name: serguzim.net Home Assistant Addons +url: 'https://git.serguzim.me/serguzim/home-assistant-addons' +maintainer: Tobias Reisinger diff --git a/snapcast/.gitignore b/snapcast/.gitignore new file mode 100644 index 0000000..4c49bd7 --- /dev/null +++ b/snapcast/.gitignore @@ -0,0 +1 @@ +.env diff --git a/snapcast/Dockerfile b/snapcast/Dockerfile new file mode 100644 index 0000000..79dfa5c --- /dev/null +++ b/snapcast/Dockerfile @@ -0,0 +1,39 @@ +ARG BUILD_FROM +FROM $BUILD_FROM + +RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \ + apk update && \ + apk add \ + gst-plugins-good \ + gst-plugins-bad \ + librespot \ + mopidy \ + nginx \ + py3-pip \ + snapcast-server \ + supervisor && \ + python3 -m pip install Mopidy-Mobile && \ + echo "daemon off;" >> /etc/nginx/nginx.conf + +COPY data/supervisord.conf /etc/supervisord.conf + +COPY data/snapserver.conf /etc/snapserver.conf +COPY data/config.js /usr/share/snapserver/snapweb/config.js + +COPY data/mopidy-extra.conf /etc/mopidy/extra.conf + +COPY data/Radios.m3u8.gtpl /templates/Radios.m3u8.gtpl +COPY data/nginx-site.gtpl /templates/nginx-site.gtpl + +COPY data/run.sh /run.sh +RUN chmod a+x /run.sh + +EXPOSE 1704 1705 6680 + +ENV LIBRESPOT_BACKEND=pipe +ENV LIBRESPOT_DEVICE=/tmp/snapfifo_librespot +ENV LIBRESPOT_NAME=Snapcast +ENV LIBRESPOT_AUTOPLAY=true +ENV LIBRESPOT_VOLUME=100 + +CMD [ "/run.sh" ] diff --git a/snapcast/config.yaml b/snapcast/config.yaml new file mode 100644 index 0000000..cec633a --- /dev/null +++ b/snapcast/config.yaml @@ -0,0 +1,31 @@ +name: "Snapcast" +description: "Snapcast server with librespot and mopidy" +version: "0.0.8" +slug: "snapcast" +init: false +ingress: true +startup: application +panel_icon: mdi:cast-audio +arch: + - aarch64 + - amd64 + - armhf + - armv7 + - i386 +ports: + 1704/tcp: 1704 + 1705/tcp: 1705 + 6680/tcp: 6680 +options: + spotify_username: null + spotify_password: null + radios: + - name: null + url: null +schema: + spotify_username: str + spotify_password: password + radios: + - name: str + url: str + diff --git a/snapcast/data/Radios.m3u8.gtpl b/snapcast/data/Radios.m3u8.gtpl new file mode 100644 index 0000000..4cafa09 --- /dev/null +++ b/snapcast/data/Radios.m3u8.gtpl @@ -0,0 +1,5 @@ +#EXTM3U +{{- range fromJson .radios}} +#EXTINF:-1,{{.name}} +{{.url}} +{{- end}} diff --git a/snapcast/data/config.js b/snapcast/data/config.js new file mode 100644 index 0000000..e2523d7 --- /dev/null +++ b/snapcast/data/config.js @@ -0,0 +1,18 @@ +"use strict"; + +let base_url = window.location.pathname.replace(/\/$/, ''); + +let config = { + baseUrl: (window.location.protocol === 'https:' ? 'wss://' : 'ws://') + window.location.host + base_url, +}; + + +window.addEventListener("DOMContentLoaded", (event) => { + let mopidy_link = document.createElement('a'); + //mopidy_link.href = window.location.protocol + '//' + window.location.host + base_url + '/mobile/'; + mopidy_link.href = window.location.protocol + '//' + window.location.hostname + ':6680/mobile/'; + mopidy_link.target = '_blank'; + mopidy_link.innerHTML = 'Mopidy'; + + document.getElementById('show').parentNode.appendChild(mopidy_link); +}); diff --git a/snapcast/data/mopidy-extra.conf b/snapcast/data/mopidy-extra.conf new file mode 100644 index 0000000..9af5390 --- /dev/null +++ b/snapcast/data/mopidy-extra.conf @@ -0,0 +1,9 @@ +[audio] +output = audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! wavenc ! tcpclientsink host=127.0.0.1 port=4953 + +[http] +enabled = true +hostname = 0.0.0.0 +port = 6680 +csrf_protection = true +default_app = mobile diff --git a/snapcast/data/nginx-site.gtpl b/snapcast/data/nginx-site.gtpl new file mode 100644 index 0000000..d318734 --- /dev/null +++ b/snapcast/data/nginx-site.gtpl @@ -0,0 +1,39 @@ +server { + listen {{ .interface }}:8099 default_server; + + allow 172.30.32.2; + deny all; + + absolute_redirect off; + + location /mobile/ { + if ($request_uri ~ ^([^.\?]*[^/])$) { + return 301 {{ .entry }}$1/; + } + + proxy_pass http://localhost:6680; + + sub_filter_once off; + sub_filter_types *; + sub_filter '/mobile/' '{{ .entry }}/mobile/'; + sub_filter '/mopidy/ws' '{{ .entry }}/mopidy/ws'; + } + location /mopidy/ws { + proxy_pass http://localhost:6680; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $http_connection; + proxy_set_header Host $host; + } + + location / { + proxy_pass http://localhost:1780; + } + location ~ ^/(jsonrpc|stream) { + proxy_pass http://localhost:1780; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $http_connection; + proxy_set_header Host $host; + } +} diff --git a/snapcast/data/run.sh b/snapcast/data/run.sh new file mode 100644 index 0000000..d2b1e69 --- /dev/null +++ b/snapcast/data/run.sh @@ -0,0 +1,20 @@ +#!/usr/bin/with-contenv bashio + +_librespot_username=$(bashio::config 'spotify_username') +export LIBRESPOT_USERNAME="$_librespot_username" +_librespot_password=$(bashio::config 'spotify_password') +export LIBRESPOT_PASSWORD="$_librespot_password" + +bashio::var.json \ + interface "$(bashio::addon.ip_address)" \ + entry "$(bashio::addon.ingress_entry)" \ + | tempio \ + -template "/templates/nginx-site.gtpl" \ + -out "/etc/nginx/http.d/default.conf" + +bashio::var.json radios "$(bashio::config 'radios' | jq -cMs .)" \ + | tempio \ + -template "/templates/Radios.m3u8.gtpl" \ + -out "/var/lib/mopidy/playlists/Radios.m3u8" + +supervisord -c /etc/supervisord.conf diff --git a/snapcast/data/snapserver.conf b/snapcast/data/snapserver.conf new file mode 100644 index 0000000..c2bfde8 --- /dev/null +++ b/snapcast/data/snapserver.conf @@ -0,0 +1,14 @@ +[stream] +source = pipe:///tmp/snapfifo?name=Default +source = tcp://127.0.0.1:4953?name=Mopidy +#source = librespot:///usr/bin/librespot?name=Spotify&devicename=Snapcast&autoplay=true&volume=90 +source = pipe:///tmp/snapfifo_librespot?name=Spotify&sampleformat=44100:16:2 + +[logging] +filter = debug + +[http] +doc_root = /usr/share/snapserver/snapweb/ + +[streaming_client] +initial_volume = 10 diff --git a/snapcast/data/supervisord.conf b/snapcast/data/supervisord.conf new file mode 100644 index 0000000..cf609fe --- /dev/null +++ b/snapcast/data/supervisord.conf @@ -0,0 +1,58 @@ +[supervisord] +nodaemon=true +logfile=/dev/null +logfile_maxbytes=0 +pidfile=/run/supervisord.pid +user=root + +[program:nginx] +command=nginx +priority=1 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 + +redirect_stderr=true +killasgroup=true +stopasgroup=true +autostart=true +autorestart=true +user=root + +[program:snapcast-server] +command=snapserver +priority=1 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 + +redirect_stderr=true +killasgroup=true +stopasgroup=true +autostart=true +autorestart=true +user=root + +[program:mopidy] +command=mopidy --config /etc/mopidy/ +priority=1 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 + +redirect_stderr=true +killasgroup=true +stopasgroup=true +autostart=true +autorestart=true +user=root + +[program:librespot] +command=librespot +priority=1 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 + +redirect_stderr=true +killasgroup=true +stopasgroup=true +autostart=true +autorestart=true +user=root diff --git a/snapcast/docker-bake.hcl b/snapcast/docker-bake.hcl new file mode 100644 index 0000000..02093cf --- /dev/null +++ b/snapcast/docker-bake.hcl @@ -0,0 +1,22 @@ +variable "REG" { + default = "registry.serguzim.me" +} +variable "REPO" { + default = "smarthome/audio" +} +variable "TAG" { + default = "latest" +} + +group "default" { + targets = ["production"] +} + +target "production" { + dockerfile = "./Dockerfile" + output = ["type=docker"] + tags = ["${REG}/${REPO}:latest", "${REG}/${REPO}:${TAG}"] + args = { + BUILD_FROM = "ghcr.io/home-assistant/amd64-base" + } +} diff --git a/snapcast/docker-compose.yml b/snapcast/docker-compose.yml new file mode 100644 index 0000000..dde15df --- /dev/null +++ b/snapcast/docker-compose.yml @@ -0,0 +1,14 @@ +services: + app: + build: + context: . + image: registry.serguzim.me/smarthome/audio + restart: always + env_file: + - .env + ports: + - "8099:8099" + - "6680:6680" + - "1704:1704" + - "1705:1705" + - "1780:1780" diff --git a/snapcast/icon.png b/snapcast/icon.png new file mode 100644 index 0000000..875c1e2 Binary files /dev/null and b/snapcast/icon.png differ