AnyEvent-MPV
view release on metacpan or search on metacpan
=over
=item uses AnyEvent, so integrates well into most event-based programs
=item supports asynchronous and synchronous operation
=item allows you to properly pass binary filenames
=item accepts data encoded in any way (does not crash when mpv replies with non UTF-8 data)
=item features a simple keybind/event system
=back
=head2 OVERVIEW OF OPERATION
This module forks an F<mpv> process and uses F<--input-ipc-client> (or
equivalent) to create a bidirectional communication channel between it and
the F<mpv> process.
It then speaks the somewhat JSON-looking (but not really being JSON)
=item F<--pause>, to keep F<mpv> from instantly starting to play a file, in case you want to
inspect/change properties first.
=item F<--force-window=no> (or similar), to keep F<mpv> from instantly opening a window, or to force it to do so.
=item F<--audio-client-name=yourappname>, to make sure audio streams are associated witht eh right program.
=item F<--wid=id>, to embed F<mpv> into another application.
=item F<--no-terminal>, F<--no-input-default-bindings>, F<--no-input-cursor>, F<--input-conf=/dev/null>, F<--input-vo-keyboard=no> - to ensure only you control input.
=back
The return value can be used to decide whether F<mpv> needs initializing:
if ($mpv->start) {
$mpv->bind_key (...);
$mpv->cmd (set => property => value);
...
}
You can immediately starting sending commands when this method returns,
even if F<mpv> has not yet started.
=cut
sub start {
=cut
sub on_event {
my ($self, $event, $data) = @_;
$self->{on_event}($self, $event, $data) if $self->{on_event};
}
=item $mpv->on_key ($string)
Invoked when a key declared by C<< ->bind_key >> is pressed. The default
invokes the C<on_key> code reference specified in the constructor with the
C<$mpv> object and the key name as arguments, or do nothing if none was
given.
For more details and examples, see the C<bind_key> method.
For subclassing, see I<SUBCLASSING>, below.
=cut
sub on_key {
my ($self, $key) = @_;
$self->{on_key}($self, $key) if $self->{on_key};
}
$mpv->cmd_recv ("stop");
$position = $mpv->cmd_recv ("get_property", "playback-time");
=cut
sub cmd_recv {
&cmd->recv
}
=item $mpv->bind_key ($INPUT => $string)
This is an extension implement by this module to make it easy to get key
events. The way this is implemented is to bind a C<client-message> witha
first argument of C<AnyEvent::MPV> and the C<$string> you passed. This
C<$string> is then passed to the C<on_key> handle when the key is
proessed, e.g.:
my $mpv = AnyEvent::MPV->new (
on_key => sub {
my ($mpv, $key) = @_;
if ($key eq "letmeout") {
print "user pressed escape\n";
}
},
);
$mpv_>bind_key (ESC => "letmeout");
You cna find a list of key names L<in the mpv
documentation|https://mpv.io/manual/stable/#key-names>.
The key configuration is lost when F<mpv> is stopped and must be (re-)done
after every C<start>.
=cut
sub bind_key {
my ($self, $key, $event) = @_;
$event =~ s/([^A-Za-z0-9\-_])/sprintf "\\x%02x", ord $1/ge;
$self->cmd (keybind => $key => "no-osd script-message AnyEvent::MPV key $event");
}
=item [$guard] = $mpv->register_event ($event => $coderef->($mpv, $event, $data))
This method registers a callback to be invoked for a specific
event. Whenever the event occurs, it calls the coderef with the C<$mpv>
object, the C<$event> name and the event object, just like the C<on_event>
method.
For a lst of events, see L<the mpv
--osd-on-seek=msg-bar --osd-bar-align-y=-0.85 --osd-bar-w=95
--sub-auto=exact --audio-file-auto=exact
Since it runs on a TV without a desktop environemnt, it tries to keep complications such as dbus
away and the screensaver happy:
# prevent xscreensaver from doing something stupid, such as starting dbus
$ENV{DBUS_SESSION_BUS_ADDRESS} = "/"; # prevent dbus autostart for sure
$ENV{XDG_CURRENT_DESKTOP} = "generic";
It does bind a number of keys to internal (to doomfrontend) commands:
for (
List::Util::pairs qw(
ESC return
q return
ENTER enter
SPACE pause
[ steprev
] stepfwd
j subtitle
b blue
D triangle
UP up
DOWN down
RIGHT right
LEFT left
),
(map { ("KP$_" => "num$_") } 0..9),
KP_INS => 0, # KP0, but different
) {
$mpv->bind_key ($_->[0] => $_->[1]);
}
It also reacts to sponsorblock chapters, so it needs to know when vidoe
chapters change. Preadting C<AnyEvent::MPV>, it handles observers
manually:
$mpv->cmd (observe_property => 1, "chapter-metadata");
It also tries to apply an F<mpv> profile, if it exists:
$self->show_all;
$window->realize;
my $xid = $window->window->get_xid;
Then it starts F<mpv> using this setup:
local $ENV{LC_ALL} = "POSIX";
$self->{mpv}->start (
"--no-terminal",
"--no-input-terminal",
"--no-input-default-bindings",
"--no-input-cursor",
"--input-conf=/dev/null",
"--input-vo-keyboard=no",
"--loop-file=inf",
"--force-window=yes",
"--idle=yes",
"--audio-client-name=CV",
<https://mpv.io/manual/stable/#command-interface> is required to use
this module.
Features of this module are:
uses AnyEvent, so integrates well into most event-based programs
supports asynchronous and synchronous operation
allows you to properly pass binary filenames
accepts data encoded in any way (does not crash when mpv replies with
non UTF-8 data)
features a simple keybind/event system
OVERVIEW OF OPERATION
This module forks an mpv process and uses --input-ipc-client (or
equivalent) to create a bidirectional communication channel between it
and the mpv process.
It then speaks the somewhat JSON-looking (but not really being JSON)
protocol that mpv implements to both send it commands, decode and handle
replies, and handle asynchronous events.
--idle=yes or --idle=once to keep mpv from quitting when you don't
specify a file to play.
--pause, to keep mpv from instantly starting to play a file, in case
you want to inspect/change properties first.
--force-window=no (or similar), to keep mpv from instantly opening a
window, or to force it to do so.
--audio-client-name=yourappname, to make sure audio streams are
associated witht eh right program.
--wid=id, to embed mpv into another application.
--no-terminal, --no-input-default-bindings, --no-input-cursor,
--input-conf=/dev/null, --input-vo-keyboard=no - to ensure only you
control input.
The return value can be used to decide whether mpv needs
initializing:
if ($mpv->start) {
$mpv->bind_key (...);
$mpv->cmd (set => property => value);
...
}
You can immediately starting sending commands when this method
returns, even if mpv has not yet started.
$mpv->stop
Ensures that mpv is being stopped, by killing mpv with a "TERM"
signal if needed. After this, you can "->start" a new instance
The first/implicit argument is the $mpv object, the second is the
event name (same as "$data->{event}", purely for convenience), and
the third argument is the event object as sent by mpv (sans "event"
key). See List of events
<https://mpv.io/manual/stable/#list-of-events> in its documentation.
For subclassing, see *SUBCLASSING*, below.
$mpv->on_key ($string)
Invoked when a key declared by "->bind_key" is pressed. The default
invokes the "on_key" code reference specified in the constructor
with the $mpv object and the key name as arguments, or do nothing if
none was given.
For more details and examples, see the "bind_key" method.
For subclassing, see *SUBCLASSING*, below.
$mpv->cmd ($command => $arg, $arg...)
Queues a command to be sent to mpv, using the given arguments, and
immediately return a condvar.
See the mpv documentation
<https://mpv.io/manual/stable/#list-of-input-commands> for details
on individual commands.
On error, the condvar will croak when "recv" is called.
$result = $mpv->cmd_recv ($command => $arg, $arg...)
The same as calling "cmd" and immediately "recv" on its return
value. Useful when you don't want to mess with mpv asynchronously or
simply needs to have the result:
$mpv->cmd_recv ("stop");
$position = $mpv->cmd_recv ("get_property", "playback-time");
$mpv->bind_key ($INPUT => $string)
This is an extension implement by this module to make it easy to get
key events. The way this is implemented is to bind a
"client-message" witha first argument of "AnyEvent::MPV" and the
$string you passed. This $string is then passed to the "on_key"
handle when the key is proessed, e.g.:
my $mpv = AnyEvent::MPV->new (
on_key => sub {
my ($mpv, $key) = @_;
if ($key eq "letmeout") {
print "user pressed escape\n";
}
},
);
$mpv_>bind_key (ESC => "letmeout");
You cna find a list of key names in the mpv documentation
<https://mpv.io/manual/stable/#key-names>.
The key configuration is lost when mpv is stopped and must be
(re-)done after every "start".
[$guard] = $mpv->register_event ($event => $coderef->($mpv, $event,
$data))
This method registers a callback to be invoked for a specific event.
--osd-on-seek=msg-bar --osd-bar-align-y=-0.85 --osd-bar-w=95
--sub-auto=exact --audio-file-auto=exact
Since it runs on a TV without a desktop environemnt, it tries to keep
complications such as dbus away and the screensaver happy:
# prevent xscreensaver from doing something stupid, such as starting dbus
$ENV{DBUS_SESSION_BUS_ADDRESS} = "/"; # prevent dbus autostart for sure
$ENV{XDG_CURRENT_DESKTOP} = "generic";
It does bind a number of keys to internal (to doomfrontend) commands:
for (
List::Util::pairs qw(
ESC return
q return
ENTER enter
SPACE pause
[ steprev
] stepfwd
j subtitle
b blue
D triangle
UP up
DOWN down
RIGHT right
LEFT left
),
(map { ("KP$_" => "num$_") } 0..9),
KP_INS => 0, # KP0, but different
) {
$mpv->bind_key ($_->[0] => $_->[1]);
}
It also reacts to sponsorblock chapters, so it needs to know when vidoe
chapters change. Preadting "AnyEvent::MPV", it handles observers
manually:
$mpv->cmd (observe_property => 1, "chapter-metadata");
It also tries to apply an mpv profile, if it exists:
$self->show_all;
$window->realize;
my $xid = $window->window->get_xid;
Then it starts mpv using this setup:
local $ENV{LC_ALL} = "POSIX";
$self->{mpv}->start (
"--no-terminal",
"--no-input-terminal",
"--no-input-default-bindings",
"--no-input-cursor",
"--input-conf=/dev/null",
"--input-vo-keyboard=no",
"--loop-file=inf",
"--force-window=yes",
"--idle=yes",
"--audio-client-name=CV",
( run in 0.928 second using v1.01-cache-2.11-cpan-2398b32b56e )