1 |
=head1 NAME |
2 |
|
3 |
AnyEvent::MPV - remote control mpv (https://mpv.io) |
4 |
|
5 |
=head1 SYNOPSIS |
6 |
|
7 |
use AnyEvent::MPV; |
8 |
|
9 |
=head1 DESCRIPTION |
10 |
|
11 |
This module allows you to remote control F<mpv> (a video player). It also |
12 |
is an L<AnyEvent> user, you need to make sure that you use and run a |
13 |
supported event loop. |
14 |
|
15 |
There are other modules doing this, and I haven't looked much at them |
16 |
other than to decide that they don't handle encodings correctly, and since |
17 |
none of them use AnyEvent, I wrote my own. When in doubt, have a look at |
18 |
them, too. |
19 |
|
20 |
Knowledge of the L<mpv command |
21 |
interface|https://mpv.io/manual/stable/#command-interface> is required to |
22 |
use this module. |
23 |
|
24 |
Features of this module are: |
25 |
|
26 |
=over |
27 |
|
28 |
=item uses AnyEvent, so integrates well into most event-based programs |
29 |
|
30 |
=item supports asynchronous and synchronous operation |
31 |
|
32 |
=item allows you to properly pass binary filenames |
33 |
|
34 |
=item accepts data encoded in any way (does not crash when mpv replies with non UTF-8 data) |
35 |
|
36 |
=item features a simple keybind/event system |
37 |
|
38 |
=back |
39 |
|
40 |
=head2 OVERVIEW OF OPERATION |
41 |
|
42 |
This module forks an F<mpv> process and uses F<--input-ipc-client> (or |
43 |
equivalent) to create a bidirectional communication channel between it and |
44 |
the F<mpv> process. |
45 |
|
46 |
It then speaks the somewhat JSON-looking (but not really being JSON) |
47 |
protocol that F<mpv> implements to both send it commands, decode and |
48 |
handle replies, and handle asynchronous events. |
49 |
|
50 |
Here is a very simple client: |
51 |
|
52 |
use AnyEvent; |
53 |
use AnyEvent::MPV; |
54 |
|
55 |
my $videofile = "./xyzzy.mp4"; |
56 |
|
57 |
my $mpv = AnyEvent::MPV->new (trace => 1); |
58 |
|
59 |
$mpv->start ("--", $videofile); |
60 |
|
61 |
my $timer = AE::timer 2, 0, my $quit = AE::cv; |
62 |
$quit->recv; |
63 |
|
64 |
This starts F<mpv> with the two arguments C<--> and C<$videofile>, which |
65 |
it should load and play. It then waits two seconds by starting a timer and |
66 |
quits. The C<trace> argument to the constructor makes F<mpv> more verbose |
67 |
and also prints the commands and responses, so you can have an idea what |
68 |
is going on. |
69 |
|
70 |
In my case, the above example would output something like this: |
71 |
|
72 |
[uosc] Disabled because original osc is enabled! |
73 |
mpv> {"event":"start-file","playlist_entry_id":1} |
74 |
mpv> {"event":"tracks-changed"} |
75 |
(+) Video --vid=1 (*) (h264 480x480 30.000fps) |
76 |
mpv> {"event":"metadata-update"} |
77 |
mpv> {"event":"file-loaded"} |
78 |
Using hardware decoding (nvdec). |
79 |
mpv> {"event":"video-reconfig"} |
80 |
VO: [gpu] 480x480 cuda[nv12] |
81 |
mpv> {"event":"video-reconfig"} |
82 |
mpv> {"event":"playback-restart"} |
83 |
|
84 |
This is not usually very useful (you could just run F<mpv> as a simple |
85 |
shell command), so let us load the file at runtime: |
86 |
|
87 |
use AnyEvent; |
88 |
use AnyEvent::MPV; |
89 |
|
90 |
my $videofile = "./xyzzy.mp4"; |
91 |
|
92 |
my $mpv = AnyEvent::MPV->new ( |
93 |
trace => 1, |
94 |
args => ["--pause", "--idle=yes"], |
95 |
); |
96 |
|
97 |
$mpv->start; |
98 |
$mpv->cmd_recv (loadfile => $mpv->escape_binary ($videofile)); |
99 |
$mpv->cmd ("set", "pause", "no"); |
100 |
|
101 |
my $timer = AE::timer 2, 0, my $quit = AE::cv; |
102 |
$quit->recv; |
103 |
|
104 |
This specifies extra arguments in the constructor - these arguments are |
105 |
used every time you C<< ->start >> F<mpv>, while the arguments to C<< |
106 |
->start >> are only used for this specific clal to0 C<start>. The argument |
107 |
F<--pause> keeps F<mpv> in pause mode (i.e. it does not play the file |
108 |
after loading it), and C<--idle=yes> tells F<mpv> to not quit when it does |
109 |
not have a playlist - as no files are specified on the command line. |
110 |
|
111 |
To load a file, we then send it a C<loadfile> command, which accepts, as |
112 |
first argument, the URL or path to a video file. To make sure F<mpv> does |
113 |
not misinterpret the path as a URL, it was prefixed with F<./> (similarly |
114 |
to "protecting" paths in perls C<open>). |
115 |
|
116 |
Since commands send I<to> F<mpv> are send in UTF-8, we need to escape the |
117 |
filename (which might be in any encoding) using the C<esscape_binary> |
118 |
method - this is not needed if your filenames are just ascii, or magically |
119 |
get interpreted correctly, but if you accept arbitrary filenamews (e.g. |
120 |
from the user), you need to do this. |
121 |
|
122 |
The C<cmd_recv> method then queues the command, waits for a reply and |
123 |
returns the reply data (or croaks on error). F<mpv> would, at this point, |
124 |
load the file and, if everything was successful, show the first frame and |
125 |
pause. Note that, since F<mpv> is implement rather synchronously itself, |
126 |
do not expect commands to fail in many circumstances - for example, fit |
127 |
he file does not exit, you will likely get an event, but the C<loadfile> |
128 |
command itself will run successfully. |
129 |
|
130 |
To unpause, we send another command, C<set>, to set the C<pause> property |
131 |
to C<no>, this time using the C<cmd> method, which queues the command, but |
132 |
instead of waiting for a reply, it immediately returns a condvar that cna |
133 |
be used to receive results. |
134 |
|
135 |
This should then cause F<mpv> to start playing the video. |
136 |
|
137 |
It then again waits two seconds and quits. |
138 |
|
139 |
Now, just waiting two seconds is rather, eh, unuseful, so let's look at |
140 |
receiving events (using a somewhat embellished example): |
141 |
|
142 |
use AnyEvent; |
143 |
use AnyEvent::MPV; |
144 |
|
145 |
my $videofile = "xyzzy.mp4"; |
146 |
|
147 |
my $quit = AE::cv; |
148 |
|
149 |
my $mpv = AnyEvent::MPV->new ( |
150 |
trace => 1, |
151 |
args => ["--pause", "--idle=yes"], |
152 |
on_event => sub { |
153 |
my ($mpv, $event, $data) = @_; |
154 |
|
155 |
if ($event eq "start-file") { |
156 |
$mpv->cmd ("set", "pause", "no"); |
157 |
} elsif ($event eq "end-file") { |
158 |
print "end-file<$data->{reason}>\n"; |
159 |
$quit->send; |
160 |
} |
161 |
}, |
162 |
); |
163 |
|
164 |
$mpv->start; |
165 |
$mpv->cmd (loadfile => $mpv->escape_binary ($videofile)); |
166 |
|
167 |
$quit->recv; |
168 |
|
169 |
This example uses a global condvar C<$quit> to wait for the file to finish |
170 |
playing. Also, most of the logic is now in an C<on_event> callback, which |
171 |
receives an event name and the actual event object. |
172 |
|
173 |
The two events we handle are C<start-file>, which is emitted by F<mpv> |
174 |
once it has loaded a new file, and C<end-file>, which signals the end |
175 |
of a file. |
176 |
|
177 |
In the former event, we again set the C<pause> property to C<no> so the |
178 |
movie starts playing. For the latter event, we tell the main program to |
179 |
quit by invoking C<$quit>. |
180 |
|
181 |
This should conclude the basics of operation. There are a few more |
182 |
examples later in the documentation. |
183 |
|
184 |
=head2 ENCODING CONVENTIONS |
185 |
|
186 |
As a rule of thumb, all data you pass to this module to be sent to F<mpv> |
187 |
is expected to be in unicode. To pass something that isn't, you need to |
188 |
escape it using C<escape_binary>. |
189 |
|
190 |
Data received from C<$mpv>, however, is I<not> decoded to unicode, as data |
191 |
returned by F<mpv> is not generally encoded in unicode, and the encoding |
192 |
is usually unspecified. So if you receive data and expect it to be in |
193 |
unicode, you need to first decode it from UTF-8, but note that this might |
194 |
fail. This is not a limitation of this module - F<mpv> simply does not |
195 |
specify nor guarantee a specific encoding, or any encoding at all, in its |
196 |
protocol. |
197 |
|
198 |
=head2 METHODS |
199 |
|
200 |
=over |
201 |
|
202 |
=cut |
203 |
|
204 |
package AnyEvent::MPV; |
205 |
|
206 |
use common::sense; |
207 |
|
208 |
use Fcntl (); |
209 |
use Scalar::Util (); |
210 |
|
211 |
use AnyEvent (); |
212 |
use AnyEvent::Util (); |
213 |
|
214 |
our $JSON = eval { require JSON::XS; JSON::XS:: } |
215 |
|| do { require JSON::PP; JSON::PP:: }; |
216 |
|
217 |
our $JSON_CODER = |
218 |
|
219 |
our $VERSION = '0.1'; |
220 |
|
221 |
our $mpv_path; # last mpv path used |
222 |
our $mpv_optionlist; # output of mpv --list-options |
223 |
|
224 |
=item $mpv = AnyEvent::MPV->new (key => value...) |
225 |
|
226 |
Creates a new C<mpv> object, but does not yet do anything. The support key-value pairs are: |
227 |
|
228 |
=over |
229 |
|
230 |
=item mpv => $path |
231 |
|
232 |
The path to the F<mpv> binary to use - by default, C<mpv> is used and |
233 |
therefore, uses your C<PATH> to find it. |
234 |
|
235 |
=item args => [...] |
236 |
|
237 |
Arguments to pass to F<mpv>. These arguments are passed after the |
238 |
hardcoded arguments used by this module, but before the arguments passed |
239 |
ot C<start>. It does not matter whether you specify your arguments using |
240 |
this key, or in the C<start> call, but when you invoke F<mpv> multiple |
241 |
times, typically the arguments used for all invocations go here, while |
242 |
arguments used for specific invocations (e..g filenames) are passed to |
243 |
C<start>. |
244 |
|
245 |
=item trace => false|true|coderef |
246 |
|
247 |
Enables tracing if true. In trace mode, output from F<mpv> is printed to |
248 |
standard error using a C<< mpv> >> prefix, and commands sent to F<mpv> |
249 |
are printed with a C<< >mpv >> prefix. |
250 |
|
251 |
If a code reference is passed, then instead of printing to standard |
252 |
errort, this coderef is invoked with a first arfgument being either |
253 |
C<< mpv> >> or C<< >mpv >>, and the second argument being a string to |
254 |
display. The default implementation simply does this: |
255 |
|
256 |
sub { |
257 |
warn "$_[0] $_[1]\n"; |
258 |
} |
259 |
|
260 |
=item on_eof => $coderef->($mpv) |
261 |
|
262 |
=item on_event => $coderef->($mpv, $event, $data) |
263 |
|
264 |
=item on_key => $coderef->($mpv, $string) |
265 |
|
266 |
These are invoked by the default method implementation of the same name - |
267 |
see below. |
268 |
|
269 |
=back |
270 |
|
271 |
=cut |
272 |
|
273 |
sub new { |
274 |
my ($class, %kv) = @_; |
275 |
|
276 |
bless { |
277 |
mpv => "mpv", |
278 |
args => [], |
279 |
%kv, |
280 |
}, $class |
281 |
} |
282 |
|
283 |
=item $string = $mpv->escape_binary ($string) |
284 |
|
285 |
This module excects all command data sent to F<mpv> to be in unicode. Some |
286 |
things are not, such as filenames. To pass binary data such as filenames |
287 |
through a comamnd, you need to escape it using this method. |
288 |
|
289 |
The simplest example is a C<loadfile> command: |
290 |
|
291 |
$mpv->cmd_recv (loadfile => $mpv->escape_binary ($path)); |
292 |
|
293 |
=cut |
294 |
|
295 |
# can be used to escape filenames |
296 |
sub escape_binary { |
297 |
shift; |
298 |
local $_ = shift; |
299 |
# we escape every "illegal" octet using U+10e5df HEX. this is later undone in cmd |
300 |
s/([\x00-\x1f\x80-\xff])/sprintf "\x{10e5df}%02x", ord $1/ge; |
301 |
$_ |
302 |
} |
303 |
|
304 |
=item $started = $mpv->start (argument...) |
305 |
|
306 |
Starts F<mpv>, passing the given arguemnts as extra arguments to |
307 |
F<mpv>. If F<mpv> is already running, it returns false, otherwise it |
308 |
returns a true value, so you can easily start F<mpv> on demand by calling |
309 |
C<start> just before using it, and if it is already running, it will not |
310 |
be started again. |
311 |
|
312 |
The arguments passwd to F<mpv> are a set of hardcoded built-in arguments, |
313 |
followed by the arguments specified in the constructor, followed by the |
314 |
arguments passwd to this method. The built-in arguments currently are |
315 |
F<--no-input-terminal>, F<--really-quiet> (or F<--quiet> in C<trace> |
316 |
mode), and C<--input-ipc-client> (or equivalent). |
317 |
|
318 |
Some commonly used and/or even useful arguments you might want to pass are: |
319 |
|
320 |
=over |
321 |
|
322 |
=item F<--idle=yes> or F<--idle=once> to keep F<mpv> from quitting when you |
323 |
don't specify a file to play. |
324 |
|
325 |
=item F<--pause>, to keep F<mpv> from instantly starting to play a file, in case you want to |
326 |
inspect/change properties first. |
327 |
|
328 |
=item F<--force-window=no> (or similar), to keep F<mpv> from instantly opening a window, or to force it to do so. |
329 |
|
330 |
=item F<--audio-client-name=yourappname>, to make sure audio streams are associated witht eh right program. |
331 |
|
332 |
=item F<--wid=id>, to embed F<mpv> into another application. |
333 |
|
334 |
=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. |
335 |
|
336 |
=back |
337 |
|
338 |
The return value can be used to decide whether F<mpv> needs initializing: |
339 |
|
340 |
if ($mpv->start) { |
341 |
$mpv->bind_key (...); |
342 |
$mpv->cmd (set => property => value); |
343 |
... |
344 |
} |
345 |
|
346 |
You can immediately starting sending commands when this method returns, |
347 |
even if F<mpv> has not yet started. |
348 |
|
349 |
=cut |
350 |
|
351 |
sub start { |
352 |
my ($self, @extra_args) = @_; |
353 |
|
354 |
return 0 if $self->{fh}; |
355 |
|
356 |
# cache optionlist for same "path" |
357 |
($mpv_path, $mpv_optionlist) = ($self->{mpv}, scalar qx{\Q$self->{mpv}\E --list-options}) |
358 |
if $self->{mpv} ne $mpv_path; |
359 |
|
360 |
my $options = $mpv_optionlist; |
361 |
|
362 |
my ($fh, $slave) = AnyEvent::Util::portable_socketpair |
363 |
or die "socketpair: $!\n"; |
364 |
|
365 |
AnyEvent::Util::fh_nonblocking $fh, 1; |
366 |
|
367 |
$self->{pid} = fork; |
368 |
|
369 |
if ($self->{pid} eq 0) { |
370 |
AnyEvent::Util::fh_nonblocking $slave, 0; |
371 |
fcntl $slave, Fcntl::F_SETFD, 0; |
372 |
|
373 |
my $input_file = $options =~ /\s--input-ipc-client\s/ ? "input-ipc-client" : "input-file"; |
374 |
|
375 |
exec $self->{mpv}, |
376 |
qw(--no-input-terminal), |
377 |
($self->{trace} ? "--quiet" : "--really-quiet"), |
378 |
"--$input_file=fd://" . (fileno $slave), |
379 |
@{ $self->{args} }, |
380 |
@extra_args; |
381 |
exit 1; |
382 |
} |
383 |
|
384 |
$self->{fh} = $fh; |
385 |
|
386 |
my $trace = delete $self->{trace} || sub { }; |
387 |
|
388 |
$trace = sub { warn "$_[0] $_[1]\n" } if $trace && !ref $trace; |
389 |
|
390 |
my $buf; |
391 |
my $wbuf; |
392 |
|
393 |
Scalar::Util::weaken $self; |
394 |
|
395 |
$self->{rw} = AE::io $fh, 0, sub { |
396 |
if (sysread $fh, $buf, 8192, length $buf) { |
397 |
while ($buf =~ s/^([^\n]+)\n//) { |
398 |
$trace->("mpv>" => "$1"); |
399 |
|
400 |
if ("{" eq substr $1, 0, 1) { |
401 |
eval { |
402 |
my $reply = $JSON->new->latin1->decode ($1); |
403 |
|
404 |
if (exists $reply->{event}) { |
405 |
if ( |
406 |
$reply->{event} eq "client-message" |
407 |
and $reply->{args}[0] eq "AnyEvent::MPV" |
408 |
) { |
409 |
if ($reply->{args}[1] eq "key") { |
410 |
(my $key = $reply->{args}[2]) =~ s/\\x(..)/chr hex $1/ge; |
411 |
$self->on_key ($key); |
412 |
} |
413 |
} else { |
414 |
$self->on_event ($reply->{event}, $reply); |
415 |
} |
416 |
} elsif (exists $reply->{request_id}) { |
417 |
my $cv = delete $self->{cmd_cv}{$reply->{request_id}}; |
418 |
|
419 |
unless ($cv) { |
420 |
warn "no cv found for request id <$reply->{request_id}>\n"; |
421 |
next; |
422 |
} |
423 |
|
424 |
if (exists $reply->{data}) { |
425 |
$cv->send ($reply->{data}); |
426 |
} elsif ($reply->{error} eq "success") { # success means error... eh.. no... |
427 |
$cv->send; |
428 |
} else { |
429 |
$cv->croak ($reply->{error}); |
430 |
} |
431 |
|
432 |
} else { |
433 |
warn "unexpected reply from mpv, pleasew report: <$1>\n"; |
434 |
} |
435 |
}; |
436 |
warn $@ if $@; |
437 |
} else { |
438 |
$trace->("mpv>" => "$1"); |
439 |
} |
440 |
} |
441 |
} else { |
442 |
$self->stop; |
443 |
$self->on_eof; |
444 |
} |
445 |
}; |
446 |
|
447 |
$self->{_send} = sub { |
448 |
$wbuf .= "$_[0]\n"; |
449 |
|
450 |
$trace->(">mpv" => "$_[0]"); |
451 |
|
452 |
$self->{ww} ||= AE::io $fh, 1, sub { |
453 |
my $len = syswrite $fh, $wbuf; |
454 |
substr $wbuf, 0, $len, ""; |
455 |
undef $self->{ww} unless length $wbuf; |
456 |
}; |
457 |
}; |
458 |
|
459 |
1 |
460 |
} |
461 |
|
462 |
=item $mpv->stop |
463 |
|
464 |
Ensures that F<mpv> is being stopped, by killing F<mpv> with a C<TERM> |
465 |
signal if needed. After this, you can C<< ->start >> a new instance again. |
466 |
|
467 |
=cut |
468 |
|
469 |
sub stop { |
470 |
my ($self) = @_; |
471 |
|
472 |
delete $self->{rw}; |
473 |
delete $self->{ww}; |
474 |
|
475 |
if ($self->{pid}) { |
476 |
|
477 |
close delete $self->{fh}; # current mpv versions should cleanup on their own on close |
478 |
|
479 |
kill TERM => $self->{pid}; |
480 |
|
481 |
} |
482 |
|
483 |
delete $self->{pid}; |
484 |
delete $self->{cmd_cv}; |
485 |
} |
486 |
|
487 |
=item $mpv->on_eof |
488 |
|
489 |
This method is called when F<mpv> quits - usually unexpectedly. The |
490 |
default implementation will call the C<on_eof> code reference specified in |
491 |
the constructor, or do nothing if none was given. |
492 |
|
493 |
For subclassing, see I<SUBCLASSING>, below. |
494 |
|
495 |
=cut |
496 |
|
497 |
sub on_eof { |
498 |
my ($self) = @_; |
499 |
|
500 |
$self->{on_eof}($self) if $self->{on_eof}; |
501 |
} |
502 |
|
503 |
=item $mpv->on_event ($event, $data) |
504 |
|
505 |
This method is called when F<mpv> sends an asynchronous event. The default |
506 |
implementation will call the C<on_event> code reference specified in the |
507 |
constructor, or do nothing if none was given. |
508 |
|
509 |
The first/implicit argument is the C<$mpv> object, the second is the event |
510 |
name (same as C<< $data->{event} >>, purely for convenience), and the |
511 |
third argument is the full event object as sent by F<mpv>. See L<List of |
512 |
events|https://mpv.io/manual/stable/#list-of-events> in its documentation. |
513 |
|
514 |
For subclassing, see I<SUBCLASSING>, below. |
515 |
|
516 |
=cut |
517 |
|
518 |
sub on_event { |
519 |
my ($self, $key) = @_; |
520 |
|
521 |
$self->{on_event}($self, $key) if $self->{on_event}; |
522 |
} |
523 |
|
524 |
=item $mpv->on_key ($string) |
525 |
|
526 |
Invoked when a key declared by C<< ->bind_key >> is pressed. The default |
527 |
invokes the C<on_key> code reference specified in the constructor with the |
528 |
C<$mpv> object and the key name as arguments, or do nothing if none was |
529 |
given. |
530 |
|
531 |
For more details and examples, see the C<bind_key> method. |
532 |
|
533 |
For subclassing, see I<SUBCLASSING>, below. |
534 |
|
535 |
=cut |
536 |
|
537 |
sub on_key { |
538 |
my ($self, $key) = @_; |
539 |
|
540 |
$self->{on_key}($self, $key) if $self->{on_key}; |
541 |
} |
542 |
|
543 |
=item $mpv->cmd ($command => $arg, $arg...) |
544 |
|
545 |
Queues a command to be sent to F<mpv>, using the given arguments, and |
546 |
immediately return a condvar. |
547 |
|
548 |
See L<the mpv |
549 |
documentation|https://mpv.io/manual/stable/#list-of-input-commands> for |
550 |
details on individual commands. |
551 |
|
552 |
The condvar can be ignored: |
553 |
|
554 |
$mpv->cmd (set_property => "deinterlace", "yes"); |
555 |
|
556 |
Or it can be used to synchronously wait for the command results: |
557 |
|
558 |
$cv = $mpv->cmd (get_property => "video-format"); |
559 |
$format = $cv->recv; |
560 |
|
561 |
# or simpler: |
562 |
|
563 |
$format = $mpv->cmd (get_property => "video-format")->recv; |
564 |
|
565 |
# or even simpler: |
566 |
|
567 |
$format = $mpv->cmd_recv (get_property => "video-format"); |
568 |
|
569 |
Or you can set a callback: |
570 |
|
571 |
$cv = $mpv->cmd (get_property => "video-format"); |
572 |
$cv->cb (sub { |
573 |
my $format = $_[0]->recv; |
574 |
}); |
575 |
|
576 |
On error, the condvar will croak when C<recv> is called. |
577 |
|
578 |
=cut |
579 |
|
580 |
sub cmd { |
581 |
my ($self, @cmd) = @_; |
582 |
|
583 |
my $cv = AE::cv; |
584 |
|
585 |
my $reqid = ++$self->{reqid}; |
586 |
$self->{cmd_cv}{$reqid} = $cv; |
587 |
|
588 |
my $cmd = $JSON->new->utf8->encode ({ command => ref $cmd[0] ? $cmd[0] : \@cmd, request_id => $reqid*1 }); |
589 |
|
590 |
# (un-)apply escape_binary hack |
591 |
$cmd =~ s/\xf4\x8e\x97\x9f(..)/sprintf sprintf "\\x%02x", hex $1/ges; # f48e979f == 10e5df in utf-8 |
592 |
|
593 |
$self->{_send}($cmd); |
594 |
|
595 |
$cv |
596 |
} |
597 |
|
598 |
=item $result = $mpv->cmd_recv ($command => $arg, $arg...) |
599 |
|
600 |
The same as calling C<cmd> and immediately C<recv> on its return |
601 |
value. Useful when you don't want to mess with F<mpv> asynchronously or |
602 |
simply needs to have the result: |
603 |
|
604 |
$mpv->cmd_recv ("stop"); |
605 |
$position = $mpv->cmd_recv ("get_property", "playback-time"); |
606 |
|
607 |
=cut |
608 |
|
609 |
sub cmd_recv { |
610 |
&cmd->recv |
611 |
} |
612 |
|
613 |
=item $mpv->bind_key ($INPUT => $string) |
614 |
|
615 |
This is an extension implement by this module to make it easy to get key events. The way this is implemented |
616 |
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 |
617 |
passed ot the C<on_key> handle when the key is proessed, e.g.: |
618 |
|
619 |
my $mpv = AnyEvent::MPV->new ( |
620 |
on_key => sub { |
621 |
my ($mpv, $key) = @_; |
622 |
|
623 |
if ($key eq "letmeout") { |
624 |
print "user pressed escape\n"; |
625 |
} |
626 |
}, |
627 |
); |
628 |
|
629 |
$mpv_>bind_key (ESC => "letmeout"); |
630 |
|
631 |
The key configuration is lost when F<mpv> is stopped and must be (re-)done |
632 |
after every C<start>. |
633 |
|
634 |
=cut |
635 |
|
636 |
sub bind_key { |
637 |
my ($self, $key, $event) = @_; |
638 |
|
639 |
$event =~ s/([^A-Za-z0-9\-_])/sprintf "\\x%02x", ord $1/ge; |
640 |
$self->cmd (keybind => $key => "no-osd script-message AnyEvent::MPV key $event"); |
641 |
} |
642 |
|
643 |
=back |
644 |
|
645 |
=head2 SUBCLASSING |
646 |
|
647 |
Like most perl objects, C<AnyEvent::MPV> objects are implemented as |
648 |
hashes, with the constructor simply storing all passed key-value pairs in |
649 |
the object. If you want to subclass to provide your own C<on_*> methods, |
650 |
be my guest and rummage around in the internals as much as you wish - the |
651 |
only guarantee that this module dcoes is that it will not use keys with |
652 |
double colons in the name, so youc an use those, or chose to simply not |
653 |
care and deal with the breakage. |
654 |
|
655 |
If you don't want to go to the effort of subclassing this module, you can |
656 |
also specify all event handlers as constructor keys. |
657 |
|
658 |
=head1 SEE ALSO |
659 |
|
660 |
L<AnyEvent>, L<the mpv command documentation|https://mpv.io/manual/stable/#command-interface>. |
661 |
|
662 |
=head1 AUTHOR |
663 |
|
664 |
Marc Lehmann <schmorp@schmorp.de> |
665 |
http://home.schmorp.de/ |
666 |
|
667 |
=cut |
668 |
|
669 |
1 |
670 |
|