(*****************************************************************************

  Liquidsoap, a programmable stream generator.
  Copyright 2003-2024 Savonet team

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 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 General Public License for more details, fully stated in the COPYING
  file at the root of the liquidsoap distribution.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA

 *****************************************************************************)

let audioscrobbler = Lang.add_module "audioscrobbler"
let log = Log.make ["lastfm"; "submit"]

let () =
  let f name stype descr =
    let proto =
      [
        ("user", Lang.string_t, None, None);
        ("password", Lang.string_t, None, None);
        ( "host",
          Lang.string_t,
          Some (Lang.string !Liqfm.Audioscrobbler.base_host),
          Some "Host for audioscrobbling submissions." );
        ( "port",
          Lang.int_t,
          Some (Lang.int !Liqfm.Audioscrobbler.base_port),
          Some "Port for audioscrobbling submissions." );
        ( "length",
          Lang.bool_t,
          Some (Lang.bool false),
          Some
            "Try to submit length information. This operation can be CPU \
             intensive. Value forced to true when used with the \"user\" \
             source type." );
        ("", Lang.metadata_t, None, None);
      ]
    in
    let proto =
      if stype = Liqfm.Played then
        ( "source",
          Lang.string_t,
          Some (Lang.string "broadcast"),
          Some
            "Source for tracks. Should be one of: \"broadcast\", \"user\", \
             \"recommendation\" or \"unknown\". Since liquidsoap is intended \
             for radio broadcasting, this is the default. Sources other than \
             user don't need duration to be set." )
        :: proto
      else proto
    in
    let tasks = Hashtbl.create 1 in
    ignore
      (Lang.add_builtin ~base:audioscrobbler name
         ~category:`Interaction (* TODO better cat *) ~descr proto Lang.unit_t
         (fun p ->
           let user = Lang.to_string (List.assoc "user" p) in
           let password = Lang.to_string (List.assoc "password" p) in
           let metas = Lang.to_metadata (Lang.assoc "" 1 p) in
           let host = Lang.to_string (List.assoc "host" p) in
           let port = Lang.to_int (List.assoc "port" p) in
           let host = (host, port) in
           let mode =
             if stype = Liqfm.Played then (
               match Lang.to_string (List.assoc "source" p) with
                 | "broadcast" -> Liqfm.Broadcast
                 | "user" -> Liqfm.User
                 | "recommendation" -> Liqfm.Recommendation
                 | "unknown" -> Liqfm.Unknown
                 | _ ->
                     raise
                       (Error.Invalid_value
                          ( List.assoc "source" p,
                            "unknown lastfm submission mode" )))
             else Liqfm.Unknown
           in
           let length = Lang.to_bool (List.assoc "length" p) in
           let length =
             if length = false && mode = Liqfm.User then (
               log#severe
                 "length information is required for \"user\" sources, setting \
                  to true.";
               true)
             else length
           in
           let task =
             try Hashtbl.find tasks host
             with Not_found ->
               let t = Liqfm.init host in
               Hashtbl.replace tasks host t;
               t
           in
           Liqfm.submit (user, password) task length mode stype [metas];
           Lang.unit))
  in
  f "submit" Liqfm.Played
    "Submit a played song using the audioscrobbler protocol.";
  f "nowplaying" Liqfm.NowPlaying
    "Submit a now playing song using the audioscrobbler protocol."
