Newer
Older
#
# Aura Engine (https://gitlab.servus.at/aura/engine)
#
# Copyright (C) 2017-2020 - The Aura Engine Team.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# Merge with previous metadata, avoid duplicates
def merge_meta(last_meta, meta) =
log(level=5, label="metadata", "Merge | last metadata: #{last_meta}")
log(level=5, label="metadata", "Merge | current metadata: #{meta}")
merged = ref(last_meta)
def add_meta_entry(entry) =
let (k, _) = entry
if list.assoc.mem(k, !merged) then
log(level=5, label="metadata", "Remove existing entry #{entry}")
merged := list.assoc.remove(k, !merged)
end
merged := list.add(entry, !merged)
end
list.iter(add_meta_entry, (meta))
log(level=5, label="metadata", "Merge | resulting metadata: #{!merged}")
!merged
end
# Checks for the existence of show-specific metadata
def has_show_meta(meta) =
list.assoc.mem(engine_meta_key_show_id, meta) ? true : false
end
# Checks if the show ID in two metadata objects matches
def is_same_show(last_meta, current_meta) =
last_meta[engine_meta_key_show_id] == current_meta[engine_meta_key_show_id] ? true : false
end
# Checks if the current show metadata is same as the previous one
def is_same_show(last_meta, current_meta) =
if has_show_meta(last_meta) then
if not has_show_meta(current_meta) then
# No current show meta: handle as same show
true
elsif is_same_show(last_meta, current_meta) then
true
else
# A new show has started
false
end
else
# Last show has no show meta
if not has_show_meta(current_meta) then
# And the current one either: handle as same show
true
else
# Treat missing last show info as the same show
true
end
end
end
# Handles either insert or merge & insert of metadata, depending on the show ID
def do_meta_insert(last_meta_callback, insert_meta_callback, meta) =
lm = (last_meta_callback() ?? [])
if is_same_show(lm, meta) then
lm = (last_meta_callback() ?? [])
merged = merge_meta(lm, meta)
insert_meta_callback(merged)
else
insert_meta_callback(meta)
end
end
# Builds a metadata object from data passed as JSON
def build_metadata(json_string) =
let json.parse (data : {
show_name: string,
show_id: int,
timeslot_id: int,
playlist_id: int,
playlist_item: string,
track_type: int,
track_start: string?,
track_duration: int?,
track_title: string?,
track_album: string?,
track_artist: string?
}) = json_string
[
("show_name", data.show_name),
("show_id", "#{data.show_id}"),
("timeslot_id", "#{data.timeslot_id}"),
("playlist_id", "#{data.playlist_id}"),
("playlist_item", "#{data.playlist_item}"),
("track_type", "#{data.track_type}"),
("track_duration", "#{data.track_duration}"),
("track_title", "#{data.track_title}"),
("track_album", "#{data.track_album}"),
("track_artist", "#{data.track_artist}"),
# Reads the track duration
# a.) when available from the file
# b.) as a fallback from the meta field "track_duration"
#
# Returns
# (int) duration in seconds
def get_meta_track_duration(meta) =
track_duration = int_of_float(request.duration(meta["filename"]))
if track_duration != -1 then
track_duration
else
int_of_string(meta["track_duration"])
end
end
# Posts a playlog to the Engine API
def post_playlog(api_url, data) =
json_data = json()
json_data.add("log_source", int_of_string(list.assoc("log_source", data)))
json_data.add("show_name", list.assoc("show_name", data))
json_data.add("show_id", int_of_string(list.assoc("show_id", data)))
json_data.add("timeslot_id", int_of_string(list.assoc("timeslot_id", data)))
json_data.add("playlist_id", int_of_string(list.assoc("playlist_id", data)))
json_data.add("track_type", int_of_string(list.assoc("track_type", data)))
json_data.add("track_start", list.assoc("track_start", data))
json_data.add("track_duration", int_of_string(list.assoc("track_duration", data)))
json_data.add("track_title", list.assoc("track_title", data))
json_data.add("track_album", list.assoc("track_album", data))
json_data.add("track_artist", list.assoc("track_artist", data))
if list.assoc("track_num", data) != "" then
json_data.add("track_num", int_of_string(list.assoc("track_num", data)))
end
playlog = json.stringify(json_data)
log("Posting playlog to '#{api_url}': #{playlog}")
headers = [("Content-Type","application/json")]
result = http.post(headers=headers, data="#{playlog}", "#{api_url}")
if result.status_code < 400 then
log("Successfully posted playlog to Engine API.")
else
log("ERROR during playlog POST: #{result.status_code} | #{result.status_message}")
end
end
# Evaluate the type of source
#
# Returns
# "fallback", "queue", "stream", "analog_in", "unknown_source"
def eval_source_type(source_id) =
type_mapping = [
("fallback_folder", "fallback"),
("fallback_playlist", "fallback"),
("in_queue_0", "queue"),
("in_queue_1", "queue"),
("in_stream_0", "stream"),
("in_stream_1", "stream"),
("in_line_0", "analog_in"),
("in_line_1", "analog_in"),
("in_line_2", "analog_in"),
("in_line_3", "analog_in"),
("in_line_4", "analog_in")
]
let source_type = list.assoc(
default="unknown_source",
source_id,
type_mapping
)
source_type
end
# Evaluates the track type based on the given:
# a.) "meta.track_type" passed as annotation, and if not available on
# b.) "engine_current_track_type" passed via server function
# c.) "meta.source" and if not available on
# d.) configured default track type setting
#
# Returns:
# 0=QUEUE/FILE, 1=STREAM, 2=LIVE ANALOG, 3=PLAYLIST
#
def eval_track_type(meta_track_type, meta_source) =
type_mapping = [
("fallback_folder", "0"),
("fallback_playlist", "3"),
("in_queue_0", "0"),
("in_queue_1", "0"),
("in_stream_0", "1"),
("in_stream_1", "1"),
("in_line_0", "2"),
("in_line_1", "2"),
("in_line_2", "2"),
("in_line_3", "2"),
("in_line_4", "2")
]
track_type = list.assoc(
default=engine_default_track_type,
meta_source,
type_mapping
)
if meta_track_type != "" then
meta_track_type
elsif track_type != "" then
track_type
else
engine_default_track_type
end
end