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/>.
# 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())
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
# A new show has started
false
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
# Builds a metadata object from data passed as JSON
def build_metadata(json_string) =
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
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: float?,
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_start", "#{data.track_start}"),
("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
# (float) duration in seconds
def get_meta_track_duration(meta) =
track_duration = request.duration(meta["filename"])
if
track_duration > 0.0
then
track_duration
else
float_of_string(meta["track_duration"])
end
# Posts a playlog to the Engine API
def post_playlog(api_url, data) =
json_data.add("showId", int_of_string(list.assoc("show_id", data)))
json_data.add("showName", list.assoc("show_name", data))
json_data.add("timeslotId", int_of_string(list.assoc("timeslot_id", data)))
json_data.add("playlistId", int_of_string(list.assoc("playlist_id", data)))
json_data.add("trackType", int_of_string(list.assoc("track_type", data)))
json_data.add("trackStart", list.assoc("track_start", data))
json_data.add(
"trackDuration", float_of_string(list.assoc("track_duration", data))
)
json_data.add("trackTitle", list.assoc("track_title", data))
json_data.add("trackAlbum", list.assoc("track_album", data))
json_data.add("trackArtist", list.assoc("track_artist", data))
if
list.assoc("track_num", data) != ""
then
json_data.add("trackNum", int_of_string(list.assoc("track_num", data)))
end
json_data.add("logSource", int_of_string(list.assoc("log_source", data)))
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}"
# 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)