AnyEvent-MPV
view release on metacpan or search on metacpan
my ($mpv, $name, $value) = @_;
print "property sid (=$name) has changed to $value\n";
});
() # ensure the above method is called in void context
}
SUBCLASSING
Like most perl objects, "AnyEvent::MPV" objects are implemented as
hashes, with the constructor simply storing all passed key-value pairs
in the object. If you want to subclass to provide your own "on_*"
methods, be my guest and rummage around in the internals as much as you
wish - the only guarantee that this module dcoes is that it will not use
keys with double colons in the name, so youc an use those, or chose to
simply not care and deal with the breakage.
If you don't want to go to the effort of subclassing this module, you
can also specify all event handlers as constructor keys.
EXAMPLES
Here are some real-world code snippets, thrown in here mainly to give
you some example code to copy.
doomfrontend
At one point I replaced mythtv-frontend by my own terminal-based video
player (based on rxvt-unicode). I toyed with the diea of using mpv's
subtitle engine to create the user interface, but that is hard to use
since you don't know how big your letters are. It is also where most of
this modules code has originally been developed in.
It uses a unified input queue to handle various remote controls, so its
event handling needs are very simple - it simply feeds all events into
the input queue:
my $mpv = AnyEvent::MPV->new (
mpv => $MPV,
args => \@MPV_ARGS,
on_event => sub {
input_feed "mpv/$_[1]", $_[2];
},
on_key => sub {
input_feed $_[1];
},
on_eof => sub {
input_feed "mpv/quit";
},
);
...
$mpv->start ("--idle=yes", "--pause", "--force-window=no");
It also doesn't use complicated command line arguments - the file search
options have the most impact, as they prevent mpv from scanning
directories with tens of thousands of files for subtitles and more:
--audio-client-name=doomfrontend
--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
BS red
i green
o yellow
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:
eval {
# the profile is optional
$mpv->cmd ("apply-profile" => "doomfrontend");
};
Most of the complicated parts deal with saving and restoring per-video
data, such as bookmarks, playing position, selected audio and subtitle
tracks and so on. However, since it uses Coro, it can conveniently block
and wait for replies, which is n ot possible in purely event based
programs, as you are not allowed to block inside event callbacks in most
event loops. This simplifies the code quite a bit.
When the file to be played is a Tv recording done by mythtv, it uses the
"appending" protocol and deinterlacing:
if (is_myth $mpv_path) {
$mpv_path = "appending://$mpv_path";
$initial_deinterlace = 1;
}
( run in 0.832 second using v1.01-cache-2.11-cpan-5837b0d9d2c )