HEX
Server: Apache/2.4.57 (Unix) OpenSSL/1.0.2k-fips
System: Linux golden.server-sky-dns.com 3.10.0-1160.59.1.el7.x86_64 #1 SMP Mon Mar 7 01:49:29 EST 2022 x86_64
User: arkitgroups (1041)
PHP: 8.2.8
Disabled: NONE
Upload Files
File: //lib/liquidsoap/1.3.7/protocols.liq
register(name="Protocol Settings","protocol",())

register(name="Replay_gain protocol settings","protocol.replay_gain",())
register(name="Replay_gain path","protocol.replay_gain.path","#{configure.libdir}/extract-replaygain")

# Register the replaygain protocol.
# @flag hidden
def replaygain_protocol(~rlog,~maxtime,arg)
 delay = maxtime - gettimeofday()
 # The extraction program
 extract_replaygain =
   get(default="#{configure.libdir}/extract-replaygain","protocol.replay_gain.path")
 x = get_process_lines(timeout=delay,"#{extract_replaygain} #{quote(arg)}")
 if list.hd(default="",x) != "" then
  ["annotate:replay_gain=\"#{list.hd(default='',x)}\":#{arg}"]
 else
  [arg]
 end
end
add_protocol("replay_gain", replaygain_protocol,
             syntax="replay_gain:uri",
             doc="Compute replaygain value using the extract-replaygain script. \
                  Adds returned value as @\"replay_gain\"@ metadata")

register(name="Process protocol settings","protocol.process",())
register(name="Process Environment",
         descr="List of environment variables \
                passed down to the executed process.",
         "protocol.process.env",
         [])
register(name="Inherit Environment",
         descr="Inherit calling process's environment when @env@ parameter is empty.",
         "protocol.process.inherit_env",
         true)

# Register the process protocol. Syntax:
# process:<output ext>,<cmd>:uri where <cmd> is interpolated with:
# [("input",<input file>),("output",<output file>),("colon",":")]
# See say: protocol for an example.
# @flag hidden
def process_protocol(~rlog,~maxtime,arg)
  log = log(label="protocol.process")

  def log(~level,s) =
    rlog(s)
    log(level=level,s)
  end

  log(level=4,"Processing #{arg}")

  x = string.split(separator=":",arg)
  uri = string.concat(separator=":",list.tl(x))
  x = string.split(separator=",",list.hd(default="",x))
  extname = list.hd(default="liq",x)
  cmd = string.concat(separator=",",list.tl(x))

  output = file.temp("liq-process", ".#{extname}")

  def resolve(input) =
    cmd = cmd % [("input",quote(input)),
                 ("output",quote(output)),
                 ("colon",":")]

    log(level=4,"Executing #{cmd}")

    env_vars = get(default=[],"protocol.process.env")
    env = environment()
    def get_env(k) =
      (k,env[k])
    end
    env = list.map(get_env,env_vars)
    inherit_env = get(default=true,"protocol.process.inherit_env")

    delay = maxtime - gettimeofday()
    ret = run_process(timeout=delay,env=env,inherit_env=inherit_env,cmd)
    if snd(ret) == ("exit","0") then
      [output]
    else
      log(level=3,"Failed to execute #{cmd}: #{snd(ret)}")
      []
    end
  end

  if uri == "" then
    resolve("")
  else
    r = request.create.raw(uri)
    delay = maxtime - gettimeofday()
    if request.resolve(timeout=delay,r) then
      res = resolve(request.filename(r))
      request.destroy(r)
      res
    else
      log(level=3,"Failed to resolve #{uri}")
      []
    end
  end
end
add_protocol(temporary=true, "process", process_protocol,
             doc="Resolve a request using an arbitrary process. \
                  @<cmd>@ is interpolated with: \
                  @[(\"input\",<input>),(\"output\",<output>),\
                  (\"colon\",\":\")]@. @uri@ is an optional child request, \
                  @<output>@ is the name of a fresh temporary file and has \
                  extension @.<extname>@. @<input>@ is an optional input \
                  file name as returned while resolving @uri@.",
             syntax="process:<extname>,<cmd>[:uri]")

# Create a process: uri, replacing @:@ with @$(colon)@
# @category Liquidsoap
# @param cmd Command line to execute
# @param ~extname Output file extension (with no leading '.')
# @param ~uri Input uri
def process_uri(~extname,~uri="",cmd) =
  cmd = string.replace(pattern=":",fun (_) -> "$(colon)",cmd)
  uri = if uri != "" then ":#{uri}" else "" end
  "process:#{extname},#{cmd}#{uri}"
end

register(name="External download protocol","protocol.external",true)
register(name="Path to curl","protocol.external.curl","curl")
register(name="External protocols","protocol.external.protocols",["http","https","ftp"])

# Resolve download protocols using curl
# @flag hidden
def download_protocol(proto,~rlog,~maxtime,arg) =
  curl = get(default="curl","protocol.external.curl")
  uri = "#{proto}:#{arg}"

  log = log(label="procol.external")

  def log(~level,s) =
    rlog(s)
    log(level=level,s)
  end

  env_vars = get(default=[],"protocol.process.env")
  env = environment()
  def get_env(k) =
    (k,env[k])
  end
  env = list.map(get_env,env_vars)
  inherit_env = get(default=true,"protocol.process.inherit_env")

  timeout = maxtime - gettimeofday()

  # First define using curl.
  def get_mime() =
    cmd = "#{curl} -sLI -X HEAD #{quote(uri)} | grep -i '^content-type' | tail -n 1 | cut -d':' -f 2 | cut -d';' -f 1"
    log(level=4,"Running #{cmd}")
    x = run_process(timeout=timeout,env=env,inherit_env=inherit_env,cmd)
    if fst(snd(x)) != "exit" or snd(snd(x)) != "0" then
      log(level=3,"Failed to fetch mime-type for #{uri} via curl.")
      log(level=4,"Process return status: #{x}")
      ""
    else
      lines = string.split(separator="\\n",fst(fst(x)))
      string.case(lower=true,string.trim(list.hd(default="",lines)))
    end
  end

  def head_mime(~name, ret) =
    def get_mime() =
      status = fst(fst(ret))
      headers = snd(fst(ret))
      code = snd(fst(status))
      if 200 <= code and code < 300 then
        headers["content-type"]
      else
        log(level=3,"Failed to fetch mime-type for #{uri}.")
        log(level=4,"Request response: #{ret}")
        ""
      end
    end
    get_mime
  end

  sub = string.sub(uri,start=0,length=5)

%ifdef https.head
  get_mime =
    if sub == "https" then
      log(level=4,"Fetching https head for #{uri}")
      head_mime(name="https",https.head(timeout=timeout,uri))
    else
      get_mime
    end
%endif

  get_mime =
    if sub != "https" then
      log(level=4,"Fetching http head for #{uri}")
      head_mime(name="http",http.head(timeout=timeout,uri))
    else
      get_mime
    end

  mime = get_mime()

  extname =
    if list.mem(mime, ["audio/mpeg", "audio/mp3"]) then
      "mp3"
    elsif list.mem(mime,["application/ogg", "application/x-ogg",
                         "audio/x-ogg", "audio/ogg", "video/ogg"]) then
      "ogg"
    elsif mime == "audio/x-flac" then
      "flac"
    elsif list.mem(mime,["audio/mp4", "application/mp4"]) then
      "mp4"
    elsif list.mem(mime,["audio/vnd.wave", "audio/wav",
                         "audio/wave", "audio/x-wav"]) then
      "wav"
    else
      log(level=3,"No known file extension for mime: #{mime}")
      "osb"
    end
  [process_uri(extname=extname,"#{curl} -sL #{quote(uri)} -o $(output)")]
end

# Register download protocol
# @flag hidden
def add_download_protocol(proto) =
  add_protocol(syntax="#{proto}://...",doc="Download files using curl",proto,download_protocol(proto))
end
if get(default=true,"protocol.external") then
  list.iter(add_download_protocol,get(default=["http","https","ftp"],"protocol.external.protocols"))
end

register(name="Youtube_dl protocol settings","protocol.youtube-dl",())
register(name="Youtube-dl path","protocol.youtube-dl.path","youtube-dl")

# Register the youtube-dl protocol, using youtube-dl.
# Syntax: youtube-dl:<ID>
# @flag hidden
def youtube_dl_protocol(~rlog,~maxtime,arg)
  binary = get(default="youtube-dl","protocol.youtube-dl.path")

  log = log(label="protocol.youtube-dl")

  def log(~level,s) =
    rlog(s)
    log(level=level,s)
  end

  delay = maxtime - gettimeofday()
  cmd = "#{binary} --get-title --get-filename -- #{quote(arg)}"
  log(level=4,"Executing #{cmd}")
  x = get_process_lines(timeout=delay,cmd)

  x =
    if list.length(x) >= 2 then
      x
    else
      ["",".osb"]
    end

  title = list.hd(default="",x)
  ext   = file.extension(list.nth(default="",x,1))
  ext   = string.sub(ext,start=1,length=string.length(ext)-1)

  cmd   = "rm -f $(output) && #{binary} -q -f best --no-playlist -o $(output) -- #{quote(arg)}"
  process = process_uri(extname=ext,cmd)

  if title != "" then
    ["annotate:title=#{quote(title)}:#{process}"]
  else
    [process]
  end
end
add_protocol("youtube-dl", youtube_dl_protocol,
              doc="Resolve a request using youtube-dl.",
              syntax="youtube-dl:uri")

# Register tmp
# @flag hidden
def tmp_protocol(~rlog,~maxtime,arg) =
  [arg]
end
add_protocol("tmp",tmp_protocol,
             doc="Mark the given uri as temporary. Useful when chaining protocols",
             temporary=true,syntax="tmp:uri")

register(name="ffmpeg2wav protocol settings","protocol.ffmpeg2wav",())
register(name="Path to ffmpeg","protocol.ffmpeg2wav.path","ffmpeg")
register(name="Number of channels","protocol.ffmpeg2wav.channels",2)
register(name="Extract metadata","protocol.ffmpeg2wav.metadata",true)

# Register ffmpeg2wav
# @flag hidden
def ffmpeg2wav_protocol(~rlog,~maxtime,arg) =
  ffmpeg   = get(default="ffmpeg","protocol.ffmpeg2wav.path")
  channels = get(default=2,"protocol.ffmpeg2wav.channels")
  metadata = get(default=true,"protocol.ffmpeg2wav.metadata")

  log = log(label="protocol.ffmpeg2wav")

  def log(~level,s) =
    rlog(s)
    log(level=level,s)
  end

  def parse_metadata(file) =
    cmd = "#{ffmpeg} -i #{quote(file)} -f ffmetadata - 2>/dev/null | grep -v '^;'"
    delay = maxtime - gettimeofday()
    log(level=4,"Executing #{cmd}")
    lines = get_process_lines(timeout=delay,cmd)
    def f(cur,line) =
      m = string.split(separator="=",line)
      if list.length(m) >= 2 then
        key = list.hd(default="",m)
        value = string.concat(separator="=",list.tl(m))
        list.add("#{key}=#{quote(value)}",cur)
      else
        cur
      end
    end
    m = string.concat(separator=",",list.fold(f,[],lines))
    if string.length(m) > 0 then
      "annotate:#{m}:"
    else
      ""
    end
  end

  r = request.create.raw(arg)
  delay = maxtime - gettimeofday()
  if request.resolve(timeout=delay,r) then
    res = request.filename(r)

    annotate = if metadata then
      parse_metadata(res)
    else
      ""
    end
   
    # Now parse the audio
    wav = file.temp("liq-process", ".wav")
    cmd = "#{ffmpeg} -y -i $(input) -ac #{channels} #{quote(wav)}"
    uri = process_uri(extname="wav",uri=res,cmd)

    wav_r = request.create.raw(uri)
    delay = maxtime - gettimeofday()
    if request.resolve(timeout=delay,wav_r) then
      request.destroy(r)
      request.destroy(wav_r)
      ["#{annotate}tmp:#{wav}"]
    else
      log(level=3,"Failed to resolve #{uri}")
      request.destroy(r)
      []
    end
  else
    log(level=3,"Failed to resolve #{arg}")
    []
  end
end
add_protocol("ffmpeg2wav",ffmpeg2wav_protocol,
             doc="Decode any file to wave using ffmpeg",
             syntax="ffmpeg2wav:uri")

register(name="Text2wave protocol settings","protocol.text2wave",())
register(name="Text2wave path","protocol.text2wave.path","text2wave")

# Register the text2wave: protocol using text2wav
# @flag hidden
def text2wave_protocol(~rlog,~maxtime,arg) =
  binary = get(default="text2wave","protocol.text2wave.path")
  [process_uri(extname="wav","echo #{quote(arg)} | #{binary} -scale 1.9 > $(output)")]
end
add_protocol(static=true,"text2wave",text2wave_protocol,
             doc="Generate speech synthesis using text2wave. Result may be mono.",
             syntax="text2wav:Text to read")

register(name="Say protocol settings","protocol.say",())
register(name="Sox path","protocol.say.sox_path","sox")

# Register the legacy say: protocol using text2wav and sox
# @flag hidden
def say_protocol(~rlog,~maxtime,arg) =
  sox = get(default="sox","protocol.say.sox_path")
  [process_uri(extname="wav",uri="text2wave:#{arg}","#{sox} $(input) -c 2 $(output)")]
end
add_protocol(static=true,"say",say_protocol,
             doc="Generate speech synthesis using text2wave and sox. Result is always stereo.",
             syntax="say:Text to read")

register(name="AWS protocols settings","protocol.aws",())
register(name="Profile",descr="Use a specific profile from your credential file.",
         "protocol.aws.profile","")
register(name="Region",descr="AWS Region",
         "protocol.aws.region","")
register(name="Binary",descr="Path to aws CLI binary",
         "protocol.aws.path","aws")
register(name="Polly protocol settings","protocol.aws.polly",())
register(name="Format",descr="Output format",
         "protocol.aws.polly.format","mp3")
register(name="Voice",descr="Voice ID",
         "protocol.aws.polly.voice","Joanna")

# Build a aws base call
# @flag hidden
def aws_base() =
  aws = get(default="aws","protocol.aws.path")

  region = get(default="","protocol.aws.region")

  aws =
    if region !="" then
      "#{aws} --region #{region}"
    else
      aws
    end

  profile = get(default="","protocol.aws.profile")

  if profile !="" then
    "#{aws} --profile #{quote(profile)}"
  else
    aws
  end
end

# Register the s3:// protocol 
# @flag hidden
def s3_protocol(~rlog,~maxtime,arg) =
  extname = file.extension(dir_sep="/",arg)
  [process_uri(extname=extname,"#{aws_base()} s3 cp s3:#{arg} $(output)")]
end
add_protocol("s3",s3_protocol,doc="Fetch files from s3 using the AWS CLI",
             syntax="s3://uri")

# Register the polly: protocol using AWS Polly
# speech synthesis services. Syntax: polly:<text>
# @flag hidden
def polly_protocol(~rlog,~maxtime,text) =
  aws = aws_base()

  format = get(default="mp3","protocol.aws.polly.format")

  extname =
    if format == "mp3" then
      "mp3"
    elsif format == "ogg_vorbis" then
      "ogg"
    else
      "wav"
    end

  aws = "#{aws} polly synthesize-speech --output-format #{format}"

  voice_id = get(default="Joanna","protocol.aws.polly.voice")

  cmd = "#{aws} --text #{quote(text)} --voice-id #{quote(voice_id)} $(output)"

  [process_uri(extname=extname,cmd)]
end
add_protocol(static=true,"polly",polly_protocol,
             doc="Generate speech synthesis using AWS polly service. \
                  Result might be mono, needs aws binary in the path.",
             syntax="polly:Text to read")