1
0
Fork 0

Fix duration/progress parsing.

liquidsoap-2.2
Icedream 2023-05-19 12:30:47 +02:00
parent 0356616566
commit 7825744006
Signed by: icedream
GPG Key ID: 468BBEEBB9EC6AEA
2 changed files with 118 additions and 60 deletions

View File

@ -4,17 +4,18 @@
metadata_api_hostname = environment.get(default="icedream-bitwave", "METADATA_API_HOSTNAME") metadata_api_hostname = environment.get(default="icedream-bitwave", "METADATA_API_HOSTNAME")
def http_export_meta(%argsof(json.stringify), m) = def setup_harbor_metadata_api(~metadata_api_port=21338, ~id="", s) =
j = json() # HACK - work around https://github.com/savonet/liquidsoap/issues/2996
list.iter((fun (v) -> j.add(fst(v), (snd(v):string))), m) id = if id != "" then id else s.id() end
json.stringify(%argsof(json.stringify), j)
end
def setup_harbor_metadata_api(~metadata_api_port=21338, s) =
id = s.id()
s = drop_metadata(s) # stream metadata wipes out own data s = drop_metadata(s) # stream metadata wipes out own data
s = insert_metadata(s) s = insert_metadata(s)
# holder for dynamic meta (things we don't want to go out over icecast
# because they change a LOT like duration)
dynamic_duration = ref(null())
dynamic_progress = ref(null())
# Handler for fetching metadata # Handler for fetching metadata
def on_http_get_metadata(request) = def on_http_get_metadata(request) =
http_version = request.http_version http_version = request.http_version
@ -36,7 +37,19 @@ def setup_harbor_metadata_api(~metadata_api_port=21338, s) =
# data = metadata.json.stringify(compact=true, m) # data = metadata.json.stringify(compact=true, m)
m = metadata.cover.remove(m) m = metadata.cover.remove(m)
data = http_export_meta(compact=true, m)
j = json()
list.iter((fun (v) -> j.add(fst(v), (snd(v):string))), m)
# add dynamic metadata
if null.defined(dynamic_duration()) then
j.add("duration", null.get(dynamic_duration()))
end
if null.defined(dynamic_progress()) then
j.add("progress", null.get(dynamic_progress()))
end
data = json.stringify(compact=true, j)
http.response(http_version=http_version, status_code=200, headers=[ http.response(http_version=http_version, status_code=200, headers=[
("access-control-allow-origin","*"), ("access-control-allow-origin","*"),
@ -81,14 +94,40 @@ def setup_harbor_metadata_api(~metadata_api_port=21338, s) =
# Handler for receiving metadata # Handler for receiving metadata
def on_http_metadata(request) = def on_http_metadata(request) =
http_version = request.http_version http_version = request.http_version
data = request.data() raw_data = request.body()
headers = request.headers headers = request.headers
let json.parse (data : { # log.info("New data for #{id}: #{data}")
data: [(string * string)] as json.object
}) = data
m = data.data let json.parse ({
data = {
duration,
progress,
},
} : {
data: {
duration: int?,
progress: int?,
}
}) = raw_data
let json.parse ({
data
} : {
data: [(string * string?)] as json.object
}) = raw_data
m = data
# old artist and title
oldm = s.last_metadata() ?? []
old_artist = if list.assoc.mem("artist", oldm) then oldm["artist"] else "" end
old_title = if list.assoc.mem("title", oldm) then oldm["title"] else "" end
new_artist = if list.assoc.mem("artist", m) then list.assoc("artist", m) ?? "" else "" end
new_title = if list.assoc.mem("title", m) then list.assoc("title", m) ?? "" else "" end
if old_artist != new_artist or old_title != new_title then
# filter dynamic metadata
m = if list.assoc.mem("progress", m) then list.assoc.remove("progress", m) else m end
m = if list.assoc.mem("duration", m) then list.assoc.remove("duration", m) else m end
# TODO - we remove cover art for now as it disturbs REKT, this needs fixing # TODO - we remove cover art for now as it disturbs REKT, this needs fixing
# m = metadata.cover.remove(m) # m = metadata.cover.remove(m)
@ -96,7 +135,6 @@ def setup_harbor_metadata_api(~metadata_api_port=21338, s) =
new_track = if list.assoc.mem("new_track", m) then bool_of_string(string_of(list.assoc("new_track", m))) else false end new_track = if list.assoc.mem("new_track", m) then bool_of_string(string_of(list.assoc("new_track", m))) else false end
# merge old metadata except for the ones we expect to change # merge old metadata except for the ones we expect to change
oldm = s.last_metadata() ?? []
oldm = if list.assoc.mem("artist", oldm) then list.assoc.remove("artist", oldm) else oldm end oldm = if list.assoc.mem("artist", oldm) then list.assoc.remove("artist", oldm) else oldm end
oldm = if list.assoc.mem("title", oldm) then list.assoc.remove("title", oldm) else oldm end oldm = if list.assoc.mem("title", oldm) then list.assoc.remove("title", oldm) else oldm end
oldm = if list.assoc.mem("album", oldm) then list.assoc.remove("album", oldm) else oldm end oldm = if list.assoc.mem("album", oldm) then list.assoc.remove("album", oldm) else oldm end
@ -116,7 +154,18 @@ def setup_harbor_metadata_api(~metadata_api_port=21338, s) =
m = list.append(oldm ?? [], m) m = list.append(oldm ?? [], m)
# set metadata on stream # set metadata on stream
m = list.assoc.filter(fun (_, v) -> null.defined(v), m)
m = list.map(fun (v) -> (fst(v), null.get(snd(v))), m)
log.info("New metadata for #{id}: #{json.stringify(m)}")
s.insert_metadata(new_track=new_track, m) s.insert_metadata(new_track=new_track, m)
else
log.info("No new metadata for #{id}")
end
# set new dynamic meta
log.info("Updating dynamic meta for #{id}")
dynamic_duration.set(duration)
dynamic_progress.set(progress)
http.response(http_version=http_version, status_code=200, headers=[ http.response(http_version=http_version, status_code=200, headers=[
("allow","POST"), ("allow","POST"),
@ -125,7 +174,7 @@ def setup_harbor_metadata_api(~metadata_api_port=21338, s) =
("access-control-allow-methods","GET,POST"), ("access-control-allow-methods","GET,POST"),
("access-control-allow-headers","Origin,X-Requested-With,Content-Type,Accept,Authorization,access-control-allow-headers,access-control-allow-origin"), ("access-control-allow-headers","Origin,X-Requested-With,Content-Type,Accept,Authorization,access-control-allow-headers,access-control-allow-origin"),
("content-type","application/json"), ("content-type","application/json"),
], data=json.stringify(data)) ], data=raw_data)
end end
# Just in case we use a browser to send data to this (for example while emulating Tuna) # Just in case we use a browser to send data to this (for example while emulating Tuna)

View File

@ -7,6 +7,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"image" "image"
"image/jpeg"
"io" "io"
"log" "log"
"net" "net"
@ -16,7 +17,6 @@ import (
"strings" "strings"
"time" "time"
"image/jpeg"
_ "image/jpeg" _ "image/jpeg"
_ "image/png" _ "image/png"
@ -42,6 +42,8 @@ type liquidsoapMetadata struct {
Title string `json:"title"` Title string `json:"title"`
Publisher string `json:"publisher,omitempty"` Publisher string `json:"publisher,omitempty"`
Year string `json:"year,omitempty"` Year string `json:"year,omitempty"`
Duration uint64 `json:"duration,omitempty"`
Progress uint64 `json:"progress,omitempty"`
} }
func (lm *liquidsoapMetadata) SetCover(r io.Reader, compressToJPEG bool) (err error) { func (lm *liquidsoapMetadata) SetCover(r io.Reader, compressToJPEG bool) (err error) {
@ -147,9 +149,12 @@ func main() {
tunaData := new(tuna.TunaData) tunaData := new(tuna.TunaData)
if err = json.NewDecoder(resp.Body).Decode(tunaData); err == nil { if err = json.NewDecoder(resp.Body).Decode(tunaData); err == nil {
// skip empty or same metadata // skip empty or same metadata
differentDataReceived := oldTunaData == nil || differentSongReceived := oldTunaData == nil ||
oldTunaData.Title != tunaData.Title || oldTunaData.Title != tunaData.Title ||
len(oldTunaData.Artists) != len(tunaData.Artists) len(oldTunaData.Artists) != len(tunaData.Artists)
differentDataReceived := differentSongReceived ||
oldTunaData.Progress != tunaData.Progress ||
oldTunaData.Duration != tunaData.Duration
if !differentDataReceived { if !differentDataReceived {
for i, artist := range oldTunaData.Artists { for i, artist := range oldTunaData.Artists {
differentDataReceived = differentDataReceived || artist != tunaData.Artists[i] differentDataReceived = differentDataReceived || artist != tunaData.Artists[i]
@ -161,6 +166,8 @@ func main() {
CoverURL: tunaData.CoverURL, CoverURL: tunaData.CoverURL,
Publisher: tunaData.Label, Publisher: tunaData.Label,
Title: tunaData.Title, Title: tunaData.Title,
Duration: tunaData.Duration,
Progress: tunaData.Progress,
} }
if tunaData.Year > 0 { if tunaData.Year > 0 {
@ -168,6 +175,7 @@ func main() {
} }
// transfer cover to liquidsoap metadata // transfer cover to liquidsoap metadata
if differentSongReceived {
if coverURL, err := url.Parse(tunaData.CoverURL); err == nil { if coverURL, err := url.Parse(tunaData.CoverURL); err == nil {
if strings.EqualFold(coverURL.Scheme, "http") || if strings.EqualFold(coverURL.Scheme, "http") ||
strings.EqualFold(coverURL.Scheme, "https") { strings.EqualFold(coverURL.Scheme, "https") {
@ -193,6 +201,7 @@ func main() {
} }
} }
} }
}
liquidsoapData := &liquidsoapMetadataRequest{ liquidsoapData := &liquidsoapMetadataRequest{
Data: *liquidsoapMetadata, Data: *liquidsoapMetadata,