diff options
-rw-r--r-- | vlc.html | 58 | ||||
-rw-r--r-- | vlc.raku | 102 |
2 files changed, 160 insertions, 0 deletions
diff --git a/vlc.html b/vlc.html new file mode 100644 index 0000000..e33ac9a --- /dev/null +++ b/vlc.html @@ -0,0 +1,58 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta http-equiv="content-type" content="text/html; charset=utf-8"> + <title>vlc</title> + <script> + "use strict" + + function vlcCall(method,path,args) { + args ||= {}; + let url=new URL(path,location.href); + for (let a in args) { + url.searchParams.set(a,args[a]); + } + return fetch(url, { + method: method, + mode: 'no-cors', + }); + } + + function vlcCommand(command,args) { + vlcCall('post',command,args); + } + + async function updateView() { + const status = (await (await vlcCall('get','status')).json()).status; + const currentPos = document.querySelector('#current-pos'); + + if (status.state != 'playing') { + currentPos.disabled=true; + return; + } + + currentPos.disabled=false; + const length = parseInt(status.length); + + if (!length) { return } + + const time = parseInt(status.time); + currentPos.max=length; + currentPos.value=time; + } + + document.addEventListener('readystatechange', (event) => { + if (document.readyState == 'complete') { + setInterval(updateView, 1000); + } + }) + </script> + </head> + <body> + <button onclick="vlcCommand('play')">play</button> + <button onclick="vlcCommand('pause')">pause</button> + <button onclick="vlcCommand('stop')">stop</button> + <button onclick="updateView()">update</button> + <input type="range" id="current-pos"> + </body> +</html> diff --git a/vlc.raku b/vlc.raku new file mode 100644 index 0000000..1e66776 --- /dev/null +++ b/vlc.raku @@ -0,0 +1,102 @@ +#!/usr/bin/env rakudo +use v6.d; +use Cro::HTTP::Server; +use Cro::HTTP::Router; +use Cro::HTTP::Client; +use Cro::Uri::HTTP; +use XML; +use XML::XPath; +use MIME::Base64; + +class VlcXMLParser does Cro::BodyParser { + method is-applicable(Cro::HTTP::Message $message --> Bool) { + with $message.content-type { + .type eq 'application'|'text' && .subtype eq 'xml' || .suffix eq 'json' + } + else { + False + } + } + + method parse(Cro::HTTP::Message $message --> Promise) { + Promise( + supply { + my $payload = Blob.new; + + whenever $message.body-byte-stream -> $blob { + $payload ~= $blob; + LAST emit from-xml($payload.decode('utf-8')); + } + + # if we had LibXML + + # my LibXML::PushParser $parser .= new(); + # + # whenever $message.body-byte-stream -> $blob { + # $parser.push($blob); + # $payload ~= $blob; + # LAST emit $parser.finish-push; + # } + } + ) + } +} + +multi sub maybe-bool('true') { True } +multi sub maybe-bool('false') { False } +multi sub maybe-bool($x) { $x } + +sub xml-to-hash(XML::Element $elem) { + if $elem.elements() -> @children { + return %( @children.map: { .name => xml-to-hash($_) } ) + } + + return maybe-bool($elem.contents().join('').trim) +} + +sub call-vlc(Str $path, *%args) { + my Cro::HTTP::Client $vlc .= new( + auth => { :username(), :password('ginopino') }, + add-body-parsers => [ VlcXMLParser ], + ); + + state Cro::Uri::HTTP $base-uri .= parse('http://192.168.1.111:8080/requests/'); + + return $vlc.get( + $base-uri.add($path).add-query(|%args) + ); +} + +sub vlc-command(Str $command, *%args) { + return call-vlc('status.xml', :$command, |%args); +} + +sub vlc-status() { + my $res = await call-vlc('status.xml'); + my XML::Document $status = await $res.body; + return Promise.kept({:status(xml-to-hash($status.root))}) +} + +my $application = route { + get -> { static 'vlc.html' } + + post -> 'play' { await vlc-command('pl_play') } + post -> 'pause' { await vlc-command('pl_pause') } + post -> 'stop' { await vlc-command('pl_stop') } + + get -> 'status' { + my $status = await vlc-status(); + content 'application/json', $status; + } +}; + +my Cro::Service $service = Cro::HTTP::Server.new( + :port(8080), :$application, +); + +$service.start; + +react whenever signal(SIGINT) { + $service.stop; + exit; +} |