File: request.liq

package info (click to toggle)
liquidsoap 2.1.3-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 12,924 kB
  • sloc: ml: 73,577; javascript: 24,836; sh: 3,440; makefile: 764; xml: 114; ansic: 96; lisp: 62; python: 35; perl: 8; ruby: 8
file content (132 lines) | stat: -rw-r--r-- 4,165 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
let request.queue = ()

let stdlib_native = native

# @docof request.dynamic
# @param ~native Use native implementation.
def replaces request.dynamic(%argsof(request.dynamic), ~native=false, f) =
  if native then
    stdlib_native.request.dynamic(%argsof(request.dynamic), f)
  else
    request.dynamic(%argsof(request.dynamic), f)
  end
end

# Play a queue of requests (the first added request gets played first).
# @category Source / Track Processing
# @param ~id Force the value of the source ID.
# @param ~interactive Should the queue be controllable via telnet?
# @param ~prefetch How many requests should be queued in advance.
# @param ~native Use native implementation.
# @param ~queue Initial queue of requests.
# @param ~timeout Timeout (in sec.) for a single download.
# @method add This method is internal and should not be used. Consider using `push` instead.
# @method push Push a request on the request queue.
# @method length Length of the queue.
def request.queue(~id=null(), ~interactive=true, ~prefetch=1, ~native=false, ~queue=[], ~timeout=20.)
  id = string.id.default(default="request.queue", id)
  queue = ref(queue)
  fetch = ref(fun () -> true)
  def next() =
    if !queue != [] then
      let [r, ...q] = !queue
      queue := q
      (r:request)
    else
      null()
    end
  end
  def push(r)
    log.info(label=id, "Pushing #{r} on the queue.")
    queue := [...!queue, r]
    fn = !fetch
    ignore(fn())
  end
  def push_uri(uri)
    r = request.create(uri)
    push(r)
  end
  s =
    if native then
      stdlib_native.request.dynamic(id=id, timeout=timeout, next)
    else
      request.dynamic(id=id, prefetch=prefetch, timeout=timeout, available={not list.is_empty(!queue)}, next)
    end
  source.set_name(s, "request.queue")
  fetch := s.fetch
  if interactive then
    def push(uri)
      r = request.create(uri)
      push(r)
      "#{request.id(r)}"
    end
    s.on_get_ready(memoize({
      begin
        server.register(namespace=source.id(s), description="Flush the queue and skip the current track",
                        "flush_and_skip", fun (_) -> try
                          s.set_queue([])
                          s.skip()
                          "Done."
                        catch err do
                          "Error while flushing and skipping source: #{err}"
                        end)
        server.register(namespace=source.id(s), description="Push a new request in the queue.", usage="push <uri>", "push", push)
        def show_queue(_) =
          queue = [...s.queue(), ...(!queue)]
          string.concat(separator=" ", list.map(fun (r) -> string_of(request.id(r)), queue))
        end
        server.register(namespace=source.id(s), description="Display current queue content.", usage="queue", "queue", show_queue)
        def skip(_) = s.skip(); "Done." end
        server.register(namespace=source.id(s), description="Skip current song.", usage="skip", "skip", skip)
      end
    }))
  end

  def add(r) =
    log.severe(label=s.id(), "Please use #{s.id()}.push instead of #{s.id()}.add()")
    s.add(r)
  end

  def set_queue(q)
    queue := q
    s.set_queue([])
  end

  s.{
    add=add,
    push=push.{uri=push_uri},
    length={list.length(!queue)+list.length(s.queue())},
    set_queue=set_queue
  }
end

# Create a source on which plays immediately requests given with the `play`
# method.
# @category Source / Track Processing
# @param ~simultaneous Allow multiple requests to play simultaneously. If `false` a new request replaces the previous one.
# @method play Play a request.
# @method length Number of currently playing requests.
def request.player(~simultaneous=true)
  if simultaneous then
    l = ref([])

    # Perform some garbage collection in order to avoid that the list grows too
    # much.
    def collect()
      l := list.filter(source.is_ready, !l)
    end

    def play(r)
      collect()
      l := request.once(r)::!l
    end

    source.dynamic({add(normalize=false, !l)}).{play=play, length={collect(); list.length(!l)}}
  else
    s = source.dynamic()
    def play(r)
      s.set(request.once(r))
    end
    s.{play=play, length={1}}
  end
end