updated to include a automatic restart script

This commit is contained in:
Niklas Kapelle 2023-11-07 18:19:27 +01:00
parent 4b6be075c1
commit 621e51c7cd
Signed by: niklas
GPG Key ID: 4EB651B36D841D16
6 changed files with 169 additions and 8 deletions

View File

@ -1,16 +1,22 @@
FROM --platform=$BUILDPLATFORM debian:bullseye-slim as build FROM --platform=$BUILDPLATFORM golang:1-bullseye as build
ENV SPOTIFYD_VERSION=v0.3.5 ENV SPOTIFYD_VERSION=v0.3.5
ENV URL=https://github.com/Spotifyd/spotifyd/releases/download/${SPOTIFYD_VERSION}/spotifyd-linux-armhf-full.tar.gz ENV URL=https://github.com/Spotifyd/spotifyd/releases/download/${SPOTIFYD_VERSION}/spotifyd-linux-armhf-full.tar.gz
RUN apt-get update && \ RUN apt-get update && \
apt-get install -yqq --no-install-recommends ca-certificates wget apt-get install -yqq --no-install-recommends ca-certificates wget
RUN wget ${URL} -O - | tar -xz && chmod +x /spotifyd WORKDIR /
RUN wget ${URL} -O - | tar -xz && chmod +x spotifyd
COPY main.go /main.go
RUN GOARCH=arm go build -o /runner /main.go
FROM --platform=$TARGETPLATFORM debian:bullseye-slim FROM --platform=$TARGETPLATFORM debian:bullseye-slim
COPY --from=build /spotifyd /app/spotifyd COPY --from=build /spotifyd /app/spotifyd
COPY --from=build /runner /app/runner
COPY start.sh /app/start.sh COPY start.sh /app/start.sh
RUN apt-get update && \ RUN apt-get update && \
@ -22,4 +28,4 @@ RUN apt-get update && \
USER spotifyd USER spotifyd
WORKDIR /app WORKDIR /app
ENTRYPOINT [ "/app/start.sh" ] ENTRYPOINT [ "/app/runner" ]

View File

@ -22,7 +22,7 @@ Following variables are available. See the [spotifyd doc](https://spotifyd.githu
`PASSWORD` Required. Spotify password. `PASSWORD` Required. Spotify password.
`DEVICE` Name of the device. Default: "Spotifyd" `DEVICE_NAME` Name of the device. Default: "Spotifyd"
`VOLUME_NORMALISATION` If set to true, enables volume normalisation between songs. `VOLUME_NORMALISATION` If set to true, enables volume normalisation between songs.

View File

@ -1,3 +1,3 @@
#!/usr/bin/env sh #!/usr/bin/env sh
docker buildx build --platform linux/arm/v7 . -t djeeberjr/spotifyd --push docker buildx build --platform linux/arm/v7 . -t djeeberjr/spotifyd $@

View File

@ -9,4 +9,4 @@ services:
environment: environment:
- USERNAME=myUsername - USERNAME=myUsername
- PASSWORD=myPassword - PASSWORD=myPassword
- DEVICE=Spotifyd - DEVICE_NAME=Spotifyd

155
main.go Normal file
View File

@ -0,0 +1,155 @@
package main
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"os"
"os/exec"
"time"
)
type headerTransport struct {
baseTransport http.RoundTripper
headers map[string]string
}
func (t *headerTransport) RoundTrip(req *http.Request) (*http.Response, error) {
for key, value := range t.headers {
req.Header.Set(key, value)
}
return t.baseTransport.RoundTrip(req)
}
type DevicesResponse struct {
Devices []struct {
ID string `json:"id"`
IsActive bool `json:"is_active"`
IsPrivateSession bool `json:"is_private_session"`
IsRestricted bool `json:"is_restricted"`
Name string `json:"name"`
SupportsVolume bool `json:"supports_volume"`
Type string `json:"type"`
VolumePercent int `json:"volume_percent"`
} `json:"devices"`
}
var API_URL string
var API_KEY string
var DEVICE_NAME string
var MAX_FAILED = 5
var CHECK_INTERVAL = 5 * time.Second
func main() {
API_URL = os.Getenv("API_URL")
API_KEY = os.Getenv("API_KEY")
DEVICE_NAME = os.Getenv("DEVICE_NAME")
if API_URL == "" {
fmt.Println("API_URL not set")
os.Exit(1)
}
if API_KEY == "" {
fmt.Println("API_KEY not set")
os.Exit(1)
}
if DEVICE_NAME == "" {
fmt.Println("DEVICE_NAME not set")
fmt.Println("Using default: Spotifyd")
DEVICE_NAME = "Spotifyd"
}
client := &http.Client{
Transport: &headerTransport{
baseTransport: http.DefaultTransport,
headers: map[string]string{
"X-API-KEY": API_KEY,
},
},
}
runLoop(client)
}
func runLoop(client *http.Client) {
proc := runSpotifyd()
go func() {
defer func() {
fmt.Println("Killing spotifyd")
proc.Process.Kill()
}()
failedCheck := 0
for {
time.Sleep(CHECK_INTERVAL)
devices, err := getDevices(client)
if err != nil {
fmt.Println("Error getting devices: " + err.Error())
continue
}
if containsDevice(devices, DEVICE_NAME) {
failedCheck = 0
continue
}
failedCheck++
fmt.Printf("Can't find device %s. Failed check %d of %d \n", DEVICE_NAME, failedCheck, MAX_FAILED)
if failedCheck >= MAX_FAILED {
return // kill handled by defer
}
}
}()
proc.Run()
}
func containsDevice(response *DevicesResponse, deviceName string) bool {
for _, device := range response.Devices {
if device.Name == DEVICE_NAME {
return true
}
}
return false
}
func getDevices(client *http.Client) (*DevicesResponse, error) {
// https://developer.spotify.com/documentation/web-api/reference/get-a-users-available-devices
resp, err := client.Get(API_URL + "/me/player/devices")
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, errors.New("Not OK. Got " + resp.Status + " instead")
}
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var devicesResponse DevicesResponse
err = json.Unmarshal(data, &devicesResponse)
if err != nil {
return nil, err
}
return &devicesResponse, nil
}
func runSpotifyd() *exec.Cmd {
proc := exec.Command("/app/start.sh")
proc.Stdout = os.Stdout
proc.Stderr = os.Stderr
return proc
}

View File

@ -32,4 +32,4 @@ if [ -n "$EXTRA_ARGS" ]; then
ARGS="${ARGS} ${EXTRA_ARGS}" ARGS="${ARGS} ${EXTRA_ARGS}"
fi fi
/app/spotifyd --no-daemon --username "$USERNAME" --password "$PASSWORD" --device-name "${DEVICE:=Spotifyd}" $ARGS /app/spotifyd --no-daemon --username "$USERNAME" --password "$PASSWORD" --device-name "${DEVICE_NAME:=Spotifyd}" $ARGS