summaryrefslogtreecommitdiff
path: root/projects/python-mpv/index.html
diff options
context:
space:
mode:
authorjaseg <git@jaseg.de>2023-03-19 00:54:56 +0100
committerjaseg <git@jaseg.de>2023-03-19 00:54:56 +0100
commit490ca12809a2625549aae16311affdd546e9c201 (patch)
tree58024389e48d91731efa352ae772a058b376b8cf /projects/python-mpv/index.html
parent92e3b5f49f6f5336530988e7839ab3ed283b86e4 (diff)
parentf21dea91904d7bf9628457a5758016c9a0df6d38 (diff)
downloadblog-490ca12809a2625549aae16311affdd546e9c201.tar.gz
blog-490ca12809a2625549aae16311affdd546e9c201.tar.bz2
blog-490ca12809a2625549aae16311affdd546e9c201.zip
deploy.py auto-commit
Diffstat (limited to 'projects/python-mpv/index.html')
-rw-r--r--projects/python-mpv/index.html391
1 files changed, 391 insertions, 0 deletions
diff --git a/projects/python-mpv/index.html b/projects/python-mpv/index.html
new file mode 100644
index 0000000..e789ace
--- /dev/null
+++ b/projects/python-mpv/index.html
@@ -0,0 +1,391 @@
+<!DOCTYPE html>
+<html><head>
+ <meta charset="utf-8">
+ <title>python-mpv | Home</title>
+ <meta name="description" content="">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta name="mobile-web-app-capable" content="yes">
+ <meta name="color-scheme" content="dark light">
+ <link rel="stylesheet" href="/style.css">
+</head>
+<body><nav>
+
+ <a href="/" title="Home">Home</a>
+ <a href="/blog/" title="Blog">Blog</a>
+ <a href="/projects/" title="Projects">Projects</a>
+ <a href="/about/" title="About">About</a>
+ <span class="spacer"></span>
+ <a href="https://git.jaseg.de/" title="cgit">cgit</a>
+ <a href="https://github.com/jaseg" title="Github">Github</a>
+ <a href="https://gitlab.com/neinseg" title="Gitlab">Gitlab</a>
+ <a href="https://chaos.social/jaseg" title="Mastodon">Mastodon</a>
+</nav>
+
+ <header>
+ <h1>python-mpv</h1>
+<ul class="breadcrumbs">
+ <li><a href="/">jaseg.de</a></li>
+ <li><a href="/projects/">Projects</a></li><li><a href="/projects/python-mpv/">python-mpv</a></li>
+</ul>
+
+ </header>
+ <main>
+ <div class="document">
+
+
+<!-- vim: tw=120 sw=4 et -->
+<p>python-mpv is a ctypes-based python interface to the mpv media player. It gives you more or less full control of all
+features of the player, just as the lua interface does.</p>
+<div class="section" id="installation">
+<h2>Installation</h2>
+<pre class="code bash literal-block">
+pip<span class="whitespace"> </span>install<span class="whitespace"> </span>mpv
+</pre>
+<p>...though you can also realistically just copy <a class="reference external" href="https://raw.githubusercontent.com/jaseg/python-mpv/main/mpv.py">mpv.py</a> into your project as it's all nicely contained in one file.</p>
+<div class="section" id="requirements">
+<h3>Requirements</h3>
+<div class="section" id="libmpv">
+<h4>libmpv</h4>
+<p><tt class="docutils literal">libmpv.so</tt> either locally (in your current working directory) or somewhere in your system library search path. This
+module is somewhat lenient as far as <tt class="docutils literal">libmpv</tt> versions are concerned but since <tt class="docutils literal">libmpv</tt> is changing quite frequently
+you'll only get all the newest features when using an up-to-date version of this module. The unit tests for this module
+do some basic automatic version compatibility checks. If you discover anything missing here, please open an <a class="reference external" href="https://github.com/jaseg/python-mpv/issues">issue</a> or
+submit a <a class="reference external" href="https://github.com/jaseg/python-mpv/pulls">pull request</a> on github.</p>
+<p>On Windows you can place libmpv anywhere in your <tt class="docutils literal">%PATH%</tt> (e.g. next to <tt class="docutils literal">python.exe</tt>) or next to this module's
+<tt class="docutils literal">mpv.py</tt>. Before falling back to looking in the mpv module's directory, python-mpv uses the DLL search order built
+into ctypes, which is different to the one Windows uses internally. Consult <a class="reference external" href="https://stackoverflow.com/a/23805306">this stackoverflow post</a> for details.</p>
+</div>
+<div class="section" id="python-3-7-officially">
+<h4>Python &gt;= 3.7 (officially)</h4>
+<p>The <tt class="docutils literal">main</tt> branch officially only supports recent python releases (3.5 onwards), but there is the somewhat outdated
+but functional <a class="reference external" href="https://github.com/jaseg/python-mpv/tree/py2compat">py2compat branch</a> providing Python 2 compatibility.</p>
+</div>
+<div class="section" id="supported-platforms">
+<h4>Supported Platforms</h4>
+<p><strong>Linux</strong>, <strong>Windows</strong> and <strong>OSX</strong> all seem to work mostly fine. For some notes on the installation on Windows see
+<a class="reference external" href="https://github.com/jaseg/python-mpv/issues/60#issuecomment-352719773">this comment</a>. Shared library handling is quite bad on windows, so expect some pain there. On OSX there seems to be
+some bug int the event logic. See <a class="reference external" href="https://github.com/jaseg/python-mpv/issues/36">issue 36</a> and <a class="reference external" href="https://github.com/jaseg/python-mpv/issues/61">issue 61</a> for details. Creating a pyQT window and having mpv draw
+into it seems to be a workaround (about 10loc), but in case you want this fixed please weigh in on the issue tracker
+since right now there is not many OSX users.</p>
+</div>
+</div>
+</div>
+<div class="section" id="usage">
+<h2>Usage</h2>
+<pre class="code python literal-block">
+<span class="keyword namespace">import</span> <span class="name namespace">mpv</span><span class="whitespace">
+</span><span class="name">player</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">(</span><span class="name">ytdl</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">)</span><span class="whitespace">
+</span><span class="name">player</span><span class="operator">.</span><span class="name">play</span><span class="punctuation">(</span><span class="literal string single">'https://youtu.be/DOmdB7D-pUU'</span><span class="punctuation">)</span><span class="whitespace">
+</span><span class="name">player</span><span class="operator">.</span><span class="name">wait_for_playback</span><span class="punctuation">()</span>
+</pre>
+<p>python-mpv mostly exposes mpv's built-in API to python, adding only some porcelain on top. Most &quot;<a class="reference external" href="https://mpv.io/manual/master/#list-of-input-commands">input commands</a>&quot; are mapped to methods of the MPV class. Check out these methods and their docstrings in <a class="reference external" href="https://github.com/jaseg/python-mpv/blob/main/mpv.py">the source</a> for things you can do. Additional controls and status information are exposed through <a class="reference external" href="https://mpv.io/manual/master/#properties">MPV properties</a>. These can be accessed like <tt class="docutils literal">player.metadata</tt>, <tt class="docutils literal">player.fullscreen</tt> and <tt class="docutils literal">player.loop_playlist</tt>.</p>
+<div class="section" id="threading">
+<h3>Threading</h3>
+<p>The <tt class="docutils literal">mpv</tt> module starts one thread for event handling, since MPV sends events that must be processed quickly. The
+event queue has a fixed maxmimum size and some operations can cause a large number of events to be sent.</p>
+<p>If you want to handle threading yourself, you can pass <tt class="docutils literal">start_event_thread=False</tt> to the <tt class="docutils literal">MPV</tt> constructor and
+manually call the <tt class="docutils literal">MPV</tt> object's <tt class="docutils literal">_loop</tt> function. If you have some strong need to not use threads and use some
+external event loop (such as asyncio) instead you can do that, too with some work. The API of the backend C <tt class="docutils literal">libmpv</tt>
+has a function for producing a sort of event file descriptor for a handle. You can use that to produce a file descriptor
+that can be passed to an event loop to tell it to wake up the python-mpv event handler on every incoming event.</p>
+<p>All API functions are thread-safe. If one is not, please file an issue on github.</p>
+</div>
+<div class="section" id="advanced-usage">
+<h3>Advanced Usage</h3>
+<div class="section" id="logging-properties-python-key-bindings-screenshots-and-youtube-dl">
+<h4>Logging, Properties, Python Key Bindings, Screenshots and youtube-dl</h4>
+<pre class="code python literal-block">
+<span class="comment hashbang">#!/usr/bin/env python3</span><span class="whitespace">
+</span><span class="keyword namespace">import</span> <span class="name namespace">mpv</span><span class="whitespace">
+
+</span><span class="keyword">def</span> <span class="name function">my_log</span><span class="punctuation">(</span><span class="name">loglevel</span><span class="punctuation">,</span> <span class="name">component</span><span class="punctuation">,</span> <span class="name">message</span><span class="punctuation">):</span><span class="whitespace">
+</span> <span class="name builtin">print</span><span class="punctuation">(</span><span class="literal string single">'[</span><span class="literal string interpol">{}</span><span class="literal string single">] </span><span class="literal string interpol">{}</span><span class="literal string single">: </span><span class="literal string interpol">{}</span><span class="literal string single">'</span><span class="operator">.</span><span class="name">format</span><span class="punctuation">(</span><span class="name">loglevel</span><span class="punctuation">,</span> <span class="name">component</span><span class="punctuation">,</span> <span class="name">message</span><span class="punctuation">))</span><span class="whitespace">
+
+</span><span class="name">player</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">(</span><span class="name">log_handler</span><span class="operator">=</span><span class="name">my_log</span><span class="punctuation">,</span> <span class="name">ytdl</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">,</span> <span class="name">input_default_bindings</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">,</span> <span class="name">input_vo_keyboard</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">)</span><span class="whitespace">
+
+</span><span class="comment single"># Property access, these can be changed at runtime</span><span class="whitespace">
+</span><span class="name decorator">&#64;player</span><span class="operator">.</span><span class="name">property_observer</span><span class="punctuation">(</span><span class="literal string single">'time-pos'</span><span class="punctuation">)</span><span class="whitespace">
+</span><span class="keyword">def</span> <span class="name function">time_observer</span><span class="punctuation">(</span><span class="name">_name</span><span class="punctuation">,</span> <span class="name">value</span><span class="punctuation">):</span><span class="whitespace">
+</span> <span class="comment single"># Here, _value is either None if nothing is playing or a float containing</span><span class="whitespace">
+</span> <span class="comment single"># fractional seconds since the beginning of the file.</span><span class="whitespace">
+</span> <span class="name builtin">print</span><span class="punctuation">(</span><span class="literal string single">'Now playing at </span><span class="literal string interpol">{:.2f}</span><span class="literal string single">s'</span><span class="operator">.</span><span class="name">format</span><span class="punctuation">(</span><span class="name">value</span><span class="punctuation">))</span><span class="whitespace">
+
+</span><span class="name">player</span><span class="operator">.</span><span class="name">fullscreen</span> <span class="operator">=</span> <span class="keyword constant">True</span><span class="whitespace">
+</span><span class="name">player</span><span class="operator">.</span><span class="name">loop_playlist</span> <span class="operator">=</span> <span class="literal string single">'inf'</span><span class="whitespace">
+</span><span class="comment single"># Option access, in general these require the core to reinitialize</span><span class="whitespace">
+</span><span class="name">player</span><span class="punctuation">[</span><span class="literal string single">'vo'</span><span class="punctuation">]</span> <span class="operator">=</span> <span class="literal string single">'gpu'</span><span class="whitespace">
+
+</span><span class="name decorator">&#64;player</span><span class="operator">.</span><span class="name">on_key_press</span><span class="punctuation">(</span><span class="literal string single">'q'</span><span class="punctuation">)</span><span class="whitespace">
+</span><span class="keyword">def</span> <span class="name function">my_q_binding</span><span class="punctuation">():</span><span class="whitespace">
+</span> <span class="name builtin">print</span><span class="punctuation">(</span><span class="literal string single">'THERE IS NO ESCAPE'</span><span class="punctuation">)</span><span class="whitespace">
+
+</span><span class="name decorator">&#64;player</span><span class="operator">.</span><span class="name">on_key_press</span><span class="punctuation">(</span><span class="literal string single">'s'</span><span class="punctuation">)</span><span class="whitespace">
+</span><span class="keyword">def</span> <span class="name function">my_s_binding</span><span class="punctuation">():</span><span class="whitespace">
+</span> <span class="name">pillow_img</span> <span class="operator">=</span> <span class="name">player</span><span class="operator">.</span><span class="name">screenshot_raw</span><span class="punctuation">()</span><span class="whitespace">
+</span> <span class="name">pillow_img</span><span class="operator">.</span><span class="name">save</span><span class="punctuation">(</span><span class="literal string single">'screenshot.png'</span><span class="punctuation">)</span><span class="whitespace">
+
+</span><span class="name">player</span><span class="operator">.</span><span class="name">play</span><span class="punctuation">(</span><span class="literal string single">'https://youtu.be/DLzxrzFCyOs'</span><span class="punctuation">)</span><span class="whitespace">
+</span><span class="name">player</span><span class="operator">.</span><span class="name">wait_for_playback</span><span class="punctuation">()</span><span class="whitespace">
+
+</span><span class="keyword">del</span> <span class="name">player</span>
+</pre>
+</div>
+<div class="section" id="skipping-silence-using-libav-filters">
+<h4>Skipping silence using libav filters</h4>
+<p>The following code uses the libav silencedetect filter to skip silence at the beginning of a file. It works by loading
+the filter, then parsing its output from mpv's log. Thanks to Sean DeNigris on github (#202) for the original code!</p>
+<pre class="code python literal-block">
+<span class="comment hashbang">#!/usr/bin/env python3</span><span class="whitespace">
+</span><span class="keyword namespace">import</span> <span class="name namespace">sys</span><span class="whitespace">
+</span><span class="keyword namespace">import</span> <span class="name namespace">mpv</span><span class="whitespace">
+
+</span><span class="name">p</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">()</span><span class="whitespace">
+</span><span class="name">p</span><span class="operator">.</span><span class="name">play</span><span class="punctuation">(</span><span class="name">sys</span><span class="operator">.</span><span class="name">argv</span><span class="punctuation">[</span><span class="literal number integer">1</span><span class="punctuation">])</span><span class="whitespace">
+
+</span><span class="keyword">def</span> <span class="name function">skip_silence</span><span class="punctuation">():</span><span class="whitespace">
+</span> <span class="name">p</span><span class="operator">.</span><span class="name">set_loglevel</span><span class="punctuation">(</span><span class="literal string single">'debug'</span><span class="punctuation">)</span><span class="whitespace">
+</span> <span class="name">p</span><span class="operator">.</span><span class="name">af</span> <span class="operator">=</span> <span class="literal string single">'lavfi=[silencedetect=n=-20dB:d=1]'</span><span class="whitespace">
+</span> <span class="name">p</span><span class="operator">.</span><span class="name">speed</span> <span class="operator">=</span> <span class="literal number integer">100</span><span class="whitespace">
+</span> <span class="keyword">def</span> <span class="name function">check</span><span class="punctuation">(</span><span class="name">evt</span><span class="punctuation">):</span><span class="whitespace">
+</span> <span class="name">toks</span> <span class="operator">=</span> <span class="name">evt</span><span class="punctuation">[</span><span class="literal string single">'event'</span><span class="punctuation">][</span><span class="literal string single">'text'</span><span class="punctuation">]</span><span class="operator">.</span><span class="name">split</span><span class="punctuation">()</span><span class="whitespace">
+</span> <span class="keyword">if</span> <span class="literal string single">'silence_end:'</span> <span class="operator word">in</span> <span class="name">toks</span><span class="punctuation">:</span><span class="whitespace">
+</span> <span class="keyword">return</span> <span class="name builtin">float</span><span class="punctuation">(</span><span class="name">toks</span><span class="punctuation">[</span><span class="literal number integer">2</span><span class="punctuation">])</span><span class="whitespace">
+</span> <span class="name">p</span><span class="operator">.</span><span class="name">time_pos</span> <span class="operator">=</span> <span class="name">p</span><span class="operator">.</span><span class="name">wait_for_event</span><span class="punctuation">(</span><span class="literal string single">'log_message'</span><span class="punctuation">,</span> <span class="name">cond</span><span class="operator">=</span><span class="name">check</span><span class="punctuation">)</span><span class="whitespace">
+</span> <span class="name">p</span><span class="operator">.</span><span class="name">speed</span> <span class="operator">=</span> <span class="literal number integer">1</span><span class="whitespace">
+</span> <span class="name">p</span><span class="operator">.</span><span class="name">af</span> <span class="operator">=</span> <span class="literal string single">''</span><span class="whitespace">
+
+</span><span class="name">skip_silence</span><span class="punctuation">()</span><span class="whitespace">
+</span><span class="name">p</span><span class="operator">.</span><span class="name">wait_for_playback</span><span class="punctuation">()</span>
+</pre>
+</div>
+<div class="section" id="video-overlays">
+<h4>Video overlays</h4>
+<pre class="code python literal-block">
+<span class="comment hashbang">#!/usr/bin/env python3</span><span class="whitespace">
+</span><span class="keyword namespace">import</span> <span class="name namespace">time</span><span class="whitespace">
+</span><span class="keyword namespace">from</span> <span class="name namespace">PIL</span> <span class="keyword namespace">import</span> <span class="name">Image</span><span class="punctuation">,</span> <span class="name">ImageDraw</span><span class="punctuation">,</span> <span class="name">ImageFont</span><span class="whitespace">
+</span><span class="keyword namespace">import</span> <span class="name namespace">mpv</span><span class="whitespace">
+
+</span><span class="name">player</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">()</span><span class="whitespace">
+
+</span><span class="name">player</span><span class="operator">.</span><span class="name">loop</span> <span class="operator">=</span> <span class="keyword constant">True</span><span class="whitespace">
+</span><span class="name">player</span><span class="operator">.</span><span class="name">play</span><span class="punctuation">(</span><span class="literal string single">'test.webm'</span><span class="punctuation">)</span><span class="whitespace">
+</span><span class="name">player</span><span class="operator">.</span><span class="name">wait_until_playing</span><span class="punctuation">()</span><span class="whitespace">
+
+</span><span class="name">font</span> <span class="operator">=</span> <span class="name">ImageFont</span><span class="operator">.</span><span class="name">truetype</span><span class="punctuation">(</span><span class="literal string single">'DejaVuSans.ttf'</span><span class="punctuation">,</span> <span class="literal number integer">40</span><span class="punctuation">)</span><span class="whitespace">
+
+</span><span class="keyword">while</span> <span class="operator word">not</span> <span class="name">player</span><span class="operator">.</span><span class="name">core_idle</span><span class="punctuation">:</span><span class="whitespace">
+
+</span> <span class="name">time</span><span class="operator">.</span><span class="name">sleep</span><span class="punctuation">(</span><span class="literal number float">0.5</span><span class="punctuation">)</span><span class="whitespace">
+</span> <span class="name">overlay</span> <span class="operator">=</span> <span class="name">player</span><span class="operator">.</span><span class="name">create_image_overlay</span><span class="punctuation">()</span><span class="whitespace">
+
+</span> <span class="keyword">for</span> <span class="name">pos</span> <span class="operator word">in</span> <span class="name builtin">range</span><span class="punctuation">(</span><span class="literal number integer">0</span><span class="punctuation">,</span> <span class="literal number integer">500</span><span class="punctuation">,</span> <span class="literal number integer">5</span><span class="punctuation">):</span><span class="whitespace">
+</span> <span class="name">ts</span> <span class="operator">=</span> <span class="name">player</span><span class="operator">.</span><span class="name">time_pos</span><span class="whitespace">
+</span> <span class="keyword">if</span> <span class="name">ts</span> <span class="operator word">is</span> <span class="keyword constant">None</span><span class="punctuation">:</span><span class="whitespace">
+</span> <span class="keyword">break</span><span class="whitespace">
+
+</span> <span class="name">img</span> <span class="operator">=</span> <span class="name">Image</span><span class="operator">.</span><span class="name">new</span><span class="punctuation">(</span><span class="literal string single">'RGBA'</span><span class="punctuation">,</span> <span class="punctuation">(</span><span class="literal number integer">400</span><span class="punctuation">,</span> <span class="literal number integer">150</span><span class="punctuation">),</span> <span class="punctuation">(</span><span class="literal number integer">255</span><span class="punctuation">,</span> <span class="literal number integer">255</span><span class="punctuation">,</span> <span class="literal number integer">255</span><span class="punctuation">,</span> <span class="literal number integer">0</span><span class="punctuation">))</span><span class="whitespace">
+</span> <span class="name">d</span> <span class="operator">=</span> <span class="name">ImageDraw</span><span class="operator">.</span><span class="name">Draw</span><span class="punctuation">(</span><span class="name">img</span><span class="punctuation">)</span><span class="whitespace">
+</span> <span class="name">d</span><span class="operator">.</span><span class="name">text</span><span class="punctuation">((</span><span class="literal number integer">10</span><span class="punctuation">,</span> <span class="literal number integer">10</span><span class="punctuation">),</span> <span class="literal string single">'Hello World'</span><span class="punctuation">,</span> <span class="name">font</span><span class="operator">=</span><span class="name">font</span><span class="punctuation">,</span> <span class="name">fill</span><span class="operator">=</span><span class="punctuation">(</span><span class="literal number integer">0</span><span class="punctuation">,</span> <span class="literal number integer">255</span><span class="punctuation">,</span> <span class="literal number integer">255</span><span class="punctuation">,</span> <span class="literal number integer">128</span><span class="punctuation">))</span><span class="whitespace">
+</span> <span class="name">d</span><span class="operator">.</span><span class="name">text</span><span class="punctuation">((</span><span class="literal number integer">10</span><span class="punctuation">,</span> <span class="literal number integer">60</span><span class="punctuation">),</span> <span class="literal string affix">f</span><span class="literal string single">'t=</span><span class="literal string interpol">{</span><span class="name">ts</span><span class="literal string interpol">:</span><span class="literal string single">.3f</span><span class="literal string interpol">}</span><span class="literal string single">'</span><span class="punctuation">,</span> <span class="name">font</span><span class="operator">=</span><span class="name">font</span><span class="punctuation">,</span> <span class="name">fill</span><span class="operator">=</span><span class="punctuation">(</span><span class="literal number integer">255</span><span class="punctuation">,</span> <span class="literal number integer">0</span><span class="punctuation">,</span> <span class="literal number integer">255</span><span class="punctuation">,</span> <span class="literal number integer">255</span><span class="punctuation">))</span><span class="whitespace">
+
+</span> <span class="name">overlay</span><span class="operator">.</span><span class="name">update</span><span class="punctuation">(</span><span class="name">img</span><span class="punctuation">,</span> <span class="name">pos</span><span class="operator">=</span><span class="punctuation">(</span><span class="literal number integer">2</span><span class="operator">*</span><span class="name">pos</span><span class="punctuation">,</span> <span class="name">pos</span><span class="punctuation">))</span><span class="whitespace">
+</span> <span class="name">time</span><span class="operator">.</span><span class="name">sleep</span><span class="punctuation">(</span><span class="literal number float">0.05</span><span class="punctuation">)</span><span class="whitespace">
+
+</span> <span class="name">overlay</span><span class="operator">.</span><span class="name">remove</span><span class="punctuation">()</span>
+</pre>
+</div>
+<div class="section" id="playlist-handling">
+<h4>Playlist handling</h4>
+<pre class="code python literal-block">
+<span class="comment hashbang">#!/usr/bin/env python3</span><span class="whitespace">
+</span><span class="keyword namespace">import</span> <span class="name namespace">mpv</span><span class="whitespace">
+
+</span><span class="name">player</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">(</span><span class="name">ytdl</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">,</span> <span class="name">input_default_bindings</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">,</span> <span class="name">input_vo_keyboard</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">)</span><span class="whitespace">
+
+</span><span class="name">player</span><span class="operator">.</span><span class="name">playlist_append</span><span class="punctuation">(</span><span class="literal string single">'https://youtu.be/PHIGke6Yzh8'</span><span class="punctuation">)</span><span class="whitespace">
+</span><span class="name">player</span><span class="operator">.</span><span class="name">playlist_append</span><span class="punctuation">(</span><span class="literal string single">'https://youtu.be/Ji9qSuQapFY'</span><span class="punctuation">)</span><span class="whitespace">
+</span><span class="name">player</span><span class="operator">.</span><span class="name">playlist_append</span><span class="punctuation">(</span><span class="literal string single">'https://youtu.be/6f78_Tf4Tdk'</span><span class="punctuation">)</span><span class="whitespace">
+
+</span><span class="name">player</span><span class="operator">.</span><span class="name">playlist_pos</span> <span class="operator">=</span> <span class="literal number integer">0</span><span class="whitespace">
+
+</span><span class="keyword">while</span> <span class="keyword constant">True</span><span class="punctuation">:</span><span class="whitespace">
+</span> <span class="comment single"># To modify the playlist, use player.playlist_{append,clear,move,remove}. player.playlist is read-only</span><span class="whitespace">
+</span> <span class="name builtin">print</span><span class="punctuation">(</span><span class="name">player</span><span class="operator">.</span><span class="name">playlist</span><span class="punctuation">)</span><span class="whitespace">
+</span> <span class="name">player</span><span class="operator">.</span><span class="name">wait_for_playback</span><span class="punctuation">()</span>
+</pre>
+</div>
+<div class="section" id="directly-feeding-mpv-data-from-python">
+<h4>Directly feeding mpv data from python</h4>
+<pre class="code python literal-block">
+<span class="comment hashbang">#!/usr/bin/env python3</span><span class="whitespace">
+</span><span class="keyword namespace">import</span> <span class="name namespace">mpv</span><span class="whitespace">
+
+</span><span class="name">player</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">()</span><span class="whitespace">
+</span><span class="name decorator">&#64;player</span><span class="operator">.</span><span class="name">python_stream</span><span class="punctuation">(</span><span class="literal string single">'foo'</span><span class="punctuation">)</span><span class="whitespace">
+</span><span class="keyword">def</span> <span class="name function">reader</span><span class="punctuation">():</span><span class="whitespace">
+</span> <span class="keyword">with</span> <span class="name builtin">open</span><span class="punctuation">(</span><span class="literal string single">'test.webm'</span><span class="punctuation">,</span> <span class="literal string single">'rb'</span><span class="punctuation">)</span> <span class="keyword">as</span> <span class="name">f</span><span class="punctuation">:</span><span class="whitespace">
+</span> <span class="keyword">while</span> <span class="keyword constant">True</span><span class="punctuation">:</span><span class="whitespace">
+</span> <span class="keyword">yield</span> <span class="name">f</span><span class="operator">.</span><span class="name">read</span><span class="punctuation">(</span><span class="literal number integer">1024</span><span class="operator">*</span><span class="literal number integer">1024</span><span class="punctuation">)</span><span class="whitespace">
+
+</span><span class="name">player</span><span class="operator">.</span><span class="name">play</span><span class="punctuation">(</span><span class="literal string single">'python://foo'</span><span class="punctuation">)</span><span class="whitespace">
+</span><span class="name">player</span><span class="operator">.</span><span class="name">wait_for_playback</span><span class="punctuation">()</span>
+</pre>
+</div>
+<div class="section" id="using-external-subtitles">
+<h4>Using external subtitles</h4>
+<p>The easiest way to load custom subtitles from a file is to pass the <tt class="docutils literal"><span class="pre">--sub-file</span></tt> option to the <tt class="docutils literal">loadfile</tt> call:</p>
+<pre class="code python literal-block">
+<span class="comment hashbang">#!/usr/bin/env python3</span><span class="whitespace">
+</span><span class="keyword namespace">import</span> <span class="name namespace">mpv</span><span class="whitespace">
+
+</span><span class="name">player</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">()</span><span class="whitespace">
+</span><span class="name">player</span><span class="operator">.</span><span class="name">loadfile</span><span class="punctuation">(</span><span class="literal string single">'test.webm'</span><span class="punctuation">,</span> <span class="name">sub_file</span><span class="operator">=</span><span class="literal string single">'test.srt'</span><span class="punctuation">)</span><span class="whitespace">
+</span><span class="name">player</span><span class="operator">.</span><span class="name">wait_for_playback</span><span class="punctuation">()</span>
+</pre>
+<p>Note that you can also pass many other options to <tt class="docutils literal">loadfile</tt>. See the mpv docs for details.</p>
+<p>If you want to add subtitle files or streams at runtime, you can use the <tt class="docutils literal"><span class="pre">sub-add</span></tt> command. <tt class="docutils literal"><span class="pre">sub-add</span></tt> can only be
+called once the player is done loading the file and starts playing. An easy way to wait for this is to wait for the
+<tt class="docutils literal"><span class="pre">core-idle</span></tt> property.</p>
+<pre class="code python literal-block">
+<span class="comment hashbang">#!/usr/bin/env python3</span><span class="whitespace">
+</span><span class="keyword namespace">import</span> <span class="name namespace">mpv</span><span class="whitespace">
+
+</span><span class="name">player</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">()</span><span class="whitespace">
+</span><span class="name">player</span><span class="operator">.</span><span class="name">play</span><span class="punctuation">(</span><span class="literal string single">'test.webm'</span><span class="punctuation">)</span><span class="whitespace">
+</span><span class="name">player</span><span class="operator">.</span><span class="name">wait_until_playing</span><span class="punctuation">()</span><span class="whitespace">
+</span><span class="name">player</span><span class="operator">.</span><span class="name">sub_add</span><span class="punctuation">(</span><span class="literal string single">'test.srt'</span><span class="punctuation">)</span><span class="whitespace">
+</span><span class="name">player</span><span class="operator">.</span><span class="name">wait_for_playback</span><span class="punctuation">()</span>
+</pre>
+</div>
+<div class="section" id="using-mpv-s-built-in-gui">
+<h4>Using MPV's built-in GUI</h4>
+<p>python-mpv is using mpv via libmpv. libmpv is meant for embedding into other applications and by default disables most
+GUI features such as the OSD or keyboard input. To enable the built-in GUI, use the following options when initializing
+the MPV instance. See <a class="reference external" href="https://github.com/jaseg/python-mpv/issues/61">Issue 102</a> for more details</p>
+<pre class="code python literal-block">
+<span class="comment single"># Enable the on-screen controller and keyboard shortcuts</span><span class="whitespace">
+</span><span class="name">player</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">(</span><span class="name">input_default_bindings</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">,</span> <span class="name">input_vo_keyboard</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">,</span> <span class="name">osc</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">)</span><span class="whitespace">
+
+</span><span class="comment single"># Alternative version using the old &quot;floating box&quot; style on-screen controller</span><span class="whitespace">
+</span><span class="name">player</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">(</span><span class="name">player_operation_mode</span><span class="operator">=</span><span class="literal string single">'pseudo-gui'</span><span class="punctuation">,</span><span class="whitespace">
+</span> <span class="name">script_opts</span><span class="operator">=</span><span class="literal string single">'osc-layout=box,osc-seekbarstyle=bar,osc-deadzonesize=0,osc-minmousemove=3'</span><span class="punctuation">,</span><span class="whitespace">
+</span> <span class="name">input_default_bindings</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">,</span><span class="whitespace">
+</span> <span class="name">input_vo_keyboard</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">,</span><span class="whitespace">
+</span> <span class="name">osc</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">)</span>
+</pre>
+</div>
+<div class="section" id="pyqt-embedding">
+<h4>PyQT embedding</h4>
+<pre class="code python literal-block">
+<span class="comment hashbang">#!/usr/bin/env python3</span><span class="whitespace">
+</span><span class="keyword namespace">import</span> <span class="name namespace">mpv</span><span class="whitespace">
+</span><span class="keyword namespace">import</span> <span class="name namespace">sys</span><span class="whitespace">
+
+</span><span class="keyword namespace">from</span> <span class="name namespace">PyQt5.QtWidgets</span> <span class="keyword namespace">import</span> <span class="operator">*</span><span class="whitespace">
+</span><span class="keyword namespace">from</span> <span class="name namespace">PyQt5.QtCore</span> <span class="keyword namespace">import</span> <span class="operator">*</span><span class="whitespace">
+
+</span><span class="keyword">class</span> <span class="name class">Test</span><span class="punctuation">(</span><span class="name">QMainWindow</span><span class="punctuation">):</span><span class="whitespace">
+</span> <span class="keyword">def</span> <span class="name function magic">__init__</span><span class="punctuation">(</span><span class="name builtin pseudo">self</span><span class="punctuation">,</span> <span class="name">parent</span><span class="operator">=</span><span class="keyword constant">None</span><span class="punctuation">):</span><span class="whitespace">
+</span> <span class="name builtin">super</span><span class="punctuation">()</span><span class="operator">.</span><span class="name function magic">__init__</span><span class="punctuation">(</span><span class="name">parent</span><span class="punctuation">)</span><span class="whitespace">
+</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">container</span> <span class="operator">=</span> <span class="name">QWidget</span><span class="punctuation">(</span><span class="name builtin pseudo">self</span><span class="punctuation">)</span><span class="whitespace">
+</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">setCentralWidget</span><span class="punctuation">(</span><span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">container</span><span class="punctuation">)</span><span class="whitespace">
+</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">container</span><span class="operator">.</span><span class="name">setAttribute</span><span class="punctuation">(</span><span class="name">Qt</span><span class="operator">.</span><span class="name">WA_DontCreateNativeAncestors</span><span class="punctuation">)</span><span class="whitespace">
+</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">container</span><span class="operator">.</span><span class="name">setAttribute</span><span class="punctuation">(</span><span class="name">Qt</span><span class="operator">.</span><span class="name">WA_NativeWindow</span><span class="punctuation">)</span><span class="whitespace">
+</span> <span class="name">player</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">(</span><span class="name">wid</span><span class="operator">=</span><span class="name builtin">str</span><span class="punctuation">(</span><span class="name builtin">int</span><span class="punctuation">(</span><span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">container</span><span class="operator">.</span><span class="name">winId</span><span class="punctuation">())),</span><span class="whitespace">
+</span> <span class="name">vo</span><span class="operator">=</span><span class="literal string single">'x11'</span><span class="punctuation">,</span> <span class="comment single"># You may not need this</span><span class="whitespace">
+</span> <span class="name">log_handler</span><span class="operator">=</span><span class="name builtin">print</span><span class="punctuation">,</span><span class="whitespace">
+</span> <span class="name">loglevel</span><span class="operator">=</span><span class="literal string single">'debug'</span><span class="punctuation">)</span><span class="whitespace">
+</span> <span class="name">player</span><span class="operator">.</span><span class="name">play</span><span class="punctuation">(</span><span class="literal string single">'test.webm'</span><span class="punctuation">)</span><span class="whitespace">
+
+</span><span class="name">app</span> <span class="operator">=</span> <span class="name">QApplication</span><span class="punctuation">(</span><span class="name">sys</span><span class="operator">.</span><span class="name">argv</span><span class="punctuation">)</span><span class="whitespace">
+
+</span><span class="comment single"># This is necessary since PyQT stomps over the locale settings needed by libmpv.</span><span class="whitespace">
+</span><span class="comment single"># This needs to happen after importing PyQT before creating the first mpv.MPV instance.</span><span class="whitespace">
+</span><span class="keyword namespace">import</span> <span class="name namespace">locale</span><span class="whitespace">
+</span><span class="name">locale</span><span class="operator">.</span><span class="name">setlocale</span><span class="punctuation">(</span><span class="name">locale</span><span class="operator">.</span><span class="name">LC_NUMERIC</span><span class="punctuation">,</span> <span class="literal string single">'C'</span><span class="punctuation">)</span><span class="whitespace">
+</span><span class="name">win</span> <span class="operator">=</span> <span class="name">Test</span><span class="punctuation">()</span><span class="whitespace">
+</span><span class="name">win</span><span class="operator">.</span><span class="name">show</span><span class="punctuation">()</span><span class="whitespace">
+</span><span class="name">sys</span><span class="operator">.</span><span class="name">exit</span><span class="punctuation">(</span><span class="name">app</span><span class="operator">.</span><span class="name">exec_</span><span class="punctuation">())</span>
+</pre>
+</div>
+<div class="section" id="pygobject-embedding">
+<h4>PyGObject embedding</h4>
+<pre class="code python literal-block">
+<span class="comment hashbang">#!/usr/bin/env python3</span><span class="whitespace">
+</span><span class="keyword namespace">import</span> <span class="name namespace">gi</span><span class="whitespace">
+
+</span><span class="keyword namespace">import</span> <span class="name namespace">mpv</span><span class="whitespace">
+
+</span><span class="name">gi</span><span class="operator">.</span><span class="name">require_version</span><span class="punctuation">(</span><span class="literal string single">'Gtk'</span><span class="punctuation">,</span> <span class="literal string single">'3.0'</span><span class="punctuation">)</span><span class="whitespace">
+</span><span class="keyword namespace">from</span> <span class="name namespace">gi.repository</span> <span class="keyword namespace">import</span> <span class="name">Gtk</span><span class="whitespace">
+
+
+</span><span class="keyword">class</span> <span class="name class">MainClass</span><span class="punctuation">(</span><span class="name">Gtk</span><span class="operator">.</span><span class="name">Window</span><span class="punctuation">):</span><span class="whitespace">
+
+</span> <span class="keyword">def</span> <span class="name function magic">__init__</span><span class="punctuation">(</span><span class="name builtin pseudo">self</span><span class="punctuation">):</span><span class="whitespace">
+</span> <span class="name builtin">super</span><span class="punctuation">(</span><span class="name">MainClass</span><span class="punctuation">,</span> <span class="name builtin pseudo">self</span><span class="punctuation">)</span><span class="operator">.</span><span class="name function magic">__init__</span><span class="punctuation">()</span><span class="whitespace">
+</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">set_default_size</span><span class="punctuation">(</span><span class="literal number integer">600</span><span class="punctuation">,</span> <span class="literal number integer">400</span><span class="punctuation">)</span><span class="whitespace">
+</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">connect</span><span class="punctuation">(</span><span class="literal string double">&quot;destroy&quot;</span><span class="punctuation">,</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">on_destroy</span><span class="punctuation">)</span><span class="whitespace">
+
+</span> <span class="name">widget</span> <span class="operator">=</span> <span class="name">Gtk</span><span class="operator">.</span><span class="name">Frame</span><span class="punctuation">()</span><span class="whitespace">
+</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">add</span><span class="punctuation">(</span><span class="name">widget</span><span class="punctuation">)</span><span class="whitespace">
+</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">show_all</span><span class="punctuation">()</span><span class="whitespace">
+
+</span> <span class="comment single"># Must be created &gt;after&lt; the widget is shown, else property 'window' will be None</span><span class="whitespace">
+</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">mpv</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">(</span><span class="name">wid</span><span class="operator">=</span><span class="name builtin">str</span><span class="punctuation">(</span><span class="name">widget</span><span class="operator">.</span><span class="name">get_property</span><span class="punctuation">(</span><span class="literal string double">&quot;window&quot;</span><span class="punctuation">)</span><span class="operator">.</span><span class="name">get_xid</span><span class="punctuation">()))</span><span class="whitespace">
+</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">mpv</span><span class="operator">.</span><span class="name">play</span><span class="punctuation">(</span><span class="literal string double">&quot;test.webm&quot;</span><span class="punctuation">)</span><span class="whitespace">
+
+</span> <span class="keyword">def</span> <span class="name function">on_destroy</span><span class="punctuation">(</span><span class="name builtin pseudo">self</span><span class="punctuation">,</span> <span class="name">widget</span><span class="punctuation">,</span> <span class="name">data</span><span class="operator">=</span><span class="keyword constant">None</span><span class="punctuation">):</span><span class="whitespace">
+</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">mpv</span><span class="operator">.</span><span class="name">terminate</span><span class="punctuation">()</span><span class="whitespace">
+</span> <span class="name">Gtk</span><span class="operator">.</span><span class="name">main_quit</span><span class="punctuation">()</span><span class="whitespace">
+
+
+</span><span class="keyword">if</span> <span class="name variable magic">__name__</span> <span class="operator">==</span> <span class="literal string single">'__main__'</span><span class="punctuation">:</span><span class="whitespace">
+</span> <span class="comment single"># This is necessary since like Qt, Gtk stomps over the locale settings needed by libmpv.</span><span class="whitespace">
+</span> <span class="comment single"># Like with Qt, this needs to happen after importing Gtk but before creating the first mpv.MPV instance.</span><span class="whitespace">
+</span> <span class="keyword namespace">import</span> <span class="name namespace">locale</span><span class="whitespace">
+</span> <span class="name">locale</span><span class="operator">.</span><span class="name">setlocale</span><span class="punctuation">(</span><span class="name">locale</span><span class="operator">.</span><span class="name">LC_NUMERIC</span><span class="punctuation">,</span> <span class="literal string single">'C'</span><span class="punctuation">)</span><span class="whitespace">
+
+</span> <span class="name">application</span> <span class="operator">=</span> <span class="name">MainClass</span><span class="punctuation">()</span><span class="whitespace">
+</span> <span class="name">Gtk</span><span class="operator">.</span><span class="name">main</span><span class="punctuation">()</span>
+</pre>
+</div>
+<div class="section" id="using-opengl-from-pygobject">
+<h4>Using OpenGL from PyGObject</h4>
+<p>Just like it is possible to render into a GTK widget through X11 windows, it <a class="reference external" href="https://gist.github.com/jaseg/657e8ecca3267c0d82ec85d40f423caa">also is possible to render into a GTK
+widget using OpenGL</a> through this python API.</p>
+</div>
+<div class="section" id="using-opengl-from-pyqt5-qml">
+<h4>Using OpenGL from PyQt5/QML</h4>
+<p><a class="reference external" href="https://gitlab.com/robozman">Robozman</a> has mangaed to <a class="reference external" href="https://gitlab.com/robozman/python-mpv-qml-example">make mpv render into a PyQt5/QML widget using OpenGL</a> through this python API.</p>
+</div>
+<div class="section" id="using-mpv-inside-imgui-inside-opengl-via-glfw">
+<h4>Using mpv inside imgui inside OpenGL via GLFW</h4>
+<p><a class="reference external" href="https://github.com/dfaker">dfaker</a> has written a demo (<a class="reference external" href="https://github.com/dfaker/imgui_glfw_pythonmpv_demo/blob/main/main.py">link</a>) that uses mpv to render video into an <a class="reference external" href="https://github.com/ocornut/imgui">imgui</a> UI running on an OpenGL context inside <a class="reference external" href="https://www.glfw.org/">GLFW</a>. Check out their demo to see how to integrate with imgui/OpenGL and how to access properties and manage the lifecycle of an MPV instance.</p>
+</div>
+</div>
+</div>
+<div class="section" id="running-tests">
+<h2>Running tests</h2>
+<p>Use pytest to run tests.</p>
+</div>
+<div class="section" id="coding-conventions">
+<h2>Coding Conventions</h2>
+<p>The general aim is <a class="reference external" href="https://www.python.org/dev/peps/pep-0008/">PEP 8</a>, with liberal application of the &quot;consistency&quot; section. 120 cells line width. Four spaces.
+No tabs. Probably don't bother making pure-formatting PRs except if you think it <em>really</em> helps readability or it
+<em>really</em> irks you if you don't.</p>
+</div>
+<div class="section" id="license">
+<h2>License</h2>
+<p>python-mpv inherits the underlying libmpv's license, which can be either GPLv2 or later (default) or LGPLv2.1 or later.
+For details, see <a class="reference external" href="https://github.com/mpv-player/mpv/blob/master/Copyright">the mpv copyright page</a>.</p>
+</div>
+</div>
+ </main><footer>
+ Copyright © 2023 Jan Sebastian Götte
+ / <a href="http://jaseg.de/about/">About</a>
+ / <a href="http://jaseg.de/imprint/">Imprint</a>
+</footer>
+</body>
+</html>