Skip to content
Snippets Groups Projects
functions.liq 7.09 KiB
Newer Older
  • Learn to ignore specific revisions
  • #
    # 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/>.
    
    
    David Trattnig's avatar
    David Trattnig committed
    #
    # METADATA
    #
    
    
    # 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) =
    
      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
    
      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 = json()
    
      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)
    
      if
        meta_track_type != ""
      then
        meta_track_type
      elsif track_type != "" then track_type
      else
        engine_default_track_type
      end
    end