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
|