Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
ce34a80
python: initial draft of second stage with per thread GIL
8lurry Mar 3, 2025
96bb3b2
python: update generated/player/python/meson.build
8lurry Mar 3, 2025
66b6df4
python: a working solution
8lurry Mar 7, 2025
175062e
python: update generated/player/python/meson.build
8lurry Mar 7, 2025
154061a
python: call mp_thread_join before finalize
8lurry Mar 9, 2025
143d446
python: add debug helper function print_ref_count
8lurry Mar 9, 2025
870ebce
python: replace pthread_t with generic typedef mp_thread
8lurry Mar 9, 2025
53b0854
python: debug ref count and set error message
8lurry Mar 10, 2025
9093292
python: fix up directory structure to current standard
8lurry Mar 10, 2025
54cbef8
python: lint
8lurry Mar 12, 2025
9c7ed1b
python: take python to the core
8lurry Mar 18, 2025
e429be5
python: move context storage from extension_module to mpvclient/defaults
8lurry Mar 19, 2025
21ac771
python: optimize, add doc & cleanup code
8lurry Mar 19, 2025
bb7a8da
python: observe/unobserve properties
8lurry Mar 19, 2025
3795282
python: check Py_IsInitialized on Py_Finalize
8lurry Mar 20, 2025
c65555d
python: lint
8lurry Mar 20, 2025
0d17981
python: add mpv.get_opt
8lurry Mar 20, 2025
781ca21
python: check codespell
8lurry Mar 21, 2025
8c4c5a7
python: lint
8lurry Mar 21, 2025
b724cdb
python: add function read_options
8lurry Mar 24, 2025
df83751
python: add mpv.add_timeout function
8lurry Mar 26, 2025
d595dd5
python: add function mpv.register_event
8lurry Mar 26, 2025
debbd8a
python: a few scripts (duplicates of TOOLS/lua/*)
8lurry Mar 26, 2025
fde52b0
python: lint & debug makenode func & add acomressor script
8lurry Mar 29, 2025
d48b993
python: add script autodeint
8lurry Mar 29, 2025
9664ad9
python: have option enable-python to switch python off
8lurry Mar 31, 2025
82995f4
python: optimize and add feature
8lurry Apr 2, 2025
4ffaff6
python: optimize & update docs
8lurry Apr 3, 2025
e02e6f0
python: add script cycle-deinterlace-pullup
8lurry Apr 3, 2025
7a494af
python: add script gamma-auto
8lurry Apr 3, 2025
72d412b
python: add script observe-all
8lurry Apr 3, 2025
e087874
python: add script ontop-playback
8lurry Apr 3, 2025
69619dd
python: take measures for possible invalid unicodes
8lurry Apr 6, 2025
2913b14
python: optimize and debug
8lurry Apr 7, 2025
e650ec0
python: add script osd-test
8lurry Apr 7, 2025
0118a9b
python: optimize source, add feature
8lurry Apr 9, 2025
993a4ba
python: add scripts status-line & test-hooks
8lurry Apr 9, 2025
6f42051
python: update docs and code cleanup
8lurry Apr 13, 2025
46db6b2
python: follow kasper's suggestion, connect debug def to buildtype debug
8lurry Apr 13, 2025
17525af
python: update player/py_extend.c
8lurry Apr 13, 2025
10a268a
python: use PRIu64 format macro constant
8lurry Apr 14, 2025
6193d6d
python: lint and avoid calling Py_FinalizeEx (see source file)
8lurry Mar 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions DOCS/man/mpv.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1555,6 +1555,8 @@ works like in older mpv releases:

.. include:: javascript.rst

.. include:: python.rst

.. include:: ipc.rst

.. include:: changes.rst
Expand Down
257 changes: 257 additions & 0 deletions DOCS/man/python.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
PYTHON SCRIPTING
================

..
Useful links
ASS markup: https://aegisub.org/docs/latest/ass_tags/

mpv can load Python scripts. (See `Script location`_.)


Python specific options
-----------------------

- enable-python

Config option (/ runtime option) `enable-python` has the default value
`false` (/ `no`) and hence by default Python doesn't initialize on runs of
mpv, unable to load any python script. This option has been set to `false`
because if there's no script need to run then having python on the heap is a
waste of resource. To be able to run python scripts, set `enable-pyhton` to
`yes` on mpv.conf file.


mpv_event as a python dictionary
--------------------------------

Has the following keys::

{
event_id: int;
reply_userdata: int;
error: int;
error_message?: string;
data: any;
}

- `event_id`; represents an `mpv_event_id`. See: `Event id`_.
- `reply_userdata`; unique id number for a request event.
- `error`; one of mpv's error number or 0.
- `error_message`; (optional) description of the error.
- `data`; type varies depending on the `event_id`::

(MPV_EVENT_CLIENT_MESSAGE)data: tuple[str];

(MPV_EVENT_PROPERTY_CHANGE)data: {
name: str; # name of the property
value: any; # value of the property
}

(MPV_EVENT_HOOK)data: {
name: str; # hook_name
id: int; # id to use to call _mpv.hook_continue
}


Event id
--------

::

MPV_EVENT_NONE = 0
MPV_EVENT_SHUTDOWN = 1
MPV_EVENT_LOG_MESSAGE = 2
MPV_EVENT_GET_PROPERTY_REPLY = 3
MPV_EVENT_SET_PROPERTY_REPLY = 4
MPV_EVENT_COMMAND_REPLY = 5
MPV_EVENT_START_FILE = 6
MPV_EVENT_END_FILE = 7
MPV_EVENT_FILE_LOADED = 8
MPV_EVENT_CLIENT_MESSAGE = 16
MPV_EVENT_VIDEO_RECONFIG = 17
MPV_EVENT_AUDIO_RECONFIG = 18
MPV_EVENT_SEEK = 20
MPV_EVENT_PLAYBACK_RESTART = 21
MPV_EVENT_PROPERTY_CHANGE = 22
MPV_EVENT_QUEUE_OVERFLOW = 24
MPV_EVENT_HOOK = 25


The wrapper module
------------------

The `player/python/defaults.py` is the wrapper module to the internal c level
python extension contained in `player/py_extend.c`. It has the most useful class
`Mpv` giving away the functionalities for calling `mpv` API.

``class Mpv``:

``Mpv.register_event(self, event_name)``
See: `Possible event names`_ section
for the argument event_name. Returns a decorator that takes in a function having
the following signature, with an example::

@mpv.register_event(mpv.MPV_EVENT_COMMAND_REPLY)
def command_reply(event):
print(event["data"])

So, the function put to the `register_event(en)` decorator receives one
argument representing an `mpv_event as a python dictionary`_.

``Mpv.add_timeout(self, sec, func, *args, name=None, **kwargs)``
Utilizes `threading.Timer` to schedule the `func` to run after `sec`
seconds. `args` and `kwargs` are passed into the `func` while calling it.
The keyword argument `name` is used to reference the `threading.Timer`
instance to manipulate it, for example, for cancelling it.

``Mpv.timers``
Type::

Mpv.timers: dict[str, treading.Timer]

Here the keyword argument `name` to `Mpv.add_timeout` used as key. If `name`
is `None` then `name` is dynamically created.

Uses::

if "detect_crop" in mpv.timers:
mpv.warn("Already cropdetecting!")

Or::

mpv.clear_timer("detect_crop")

``Mpv.clear_timer(self, name)``
Given the name of a timer this function cancels it.

``Mpv.get_opt(self, key, default=None)``
Returns the option value defined in section `options/script_opts`. If the
key is not found it returns the `default`.

``Mpv.log(self, level, *args)``
The following functions can be used to send log messages::

Mpv.log(self, level, *args)
Mpv.trace(self, *args)
Mpv.debug(self, *args)
Mpv.info(self, *args)
Mpv.warn(self, *args)
Mpv.error(self, *args)
Mpv.fatal(self, *args)

``Mpv.osd_message(self, text, duration=-1, osd_level=None)``
Displays osd messages. See: `OSD Commands`_ for more detail.

``Mpv.command_string(self, name)``
Given the string representation of a command `command_string`, runs it.

``Mpv.commandv(self, *args)``
Given a number of arguments as command, runs it. Arguments are parsed into
string before running the command.

``Mpv.command(self, node)``
Given an `mpv_node` representation in python data types. Runs the node as a
command and returns it's result as another `mpv_node` python representation.

``Mpv.command_node_async_callback(self, node)``
Returns a decorator which on invoke calls `Mpv.command_node_async` as the
given `node` and registers a given function to call with the result when the
async command returns. The decorator function return a `registry entry` of the
following form::

{"callback": callback_function, "id": async_command_id}

``Mpv.abort_async_command(self, registry_entry)``
Given a `registry entry` described above, this function cancels an async
command referenced by `registry_entry["id"]`.


``Mpv.find_config_file(self, filename)``
Given the filename return an mpv configuration file. `None` if file not
found.

``Mpv.request_event(self, event_name)``
Given an `event_name` of the form `mpv.MPV_EVENT_CLIENT_MESSAGE` mpv enables
messages when the event has occurred.

``Mpv.enable_messages(self, level)``
Given a log `level`, mpv enables log messages above this `level` from the
client.

``Mpv.observe_property(self, property_name, mpv_format)``
Returns a decorator which takes in a function to invoke (with the property
value) when the observed property has changed. Example use case::

from mpvclient import mpv

@mpv.observe_property("pause", mpv.MPV_FORMAT_NODE)
def on_pause_change(data):
if data:
mpv.osd_message(f"Paused the video for you!")

``Mpv.unobserve_property(self, id)``
Given the id of a property observer remove the observer.

``Mpv.set_property(self, property_name, mpv_format, data)``
A set property call to a said mpv_format, set's the property. Property
setters::

Mpv.set_property_string(name, data)
Mpv.set_property_osd(name, data)
Mpv.set_property_bool(name, data)
Mpv.set_property_int(name, data)
Mpv.set_property_float(name, data)
Mpv.set_property_node(name, data)

``Mpv.del_property(self, name)``
Delete a previously set property.

``Mpv.get_property(self, property_name, mpv_format)``
A get property call to a said mpv_format gets the value of the property.
Property getters::

Mpv.get_property_string(self, name)
Mpv.get_property_osd(self, name)
Mpv.get_property_bool(self, name)
Mpv.get_property_int(self, name)
Mpv.get_property_float(self, name)
Mpv.get_property_node(self, name)


``Mpv.add_binding(self, key=None, name=None, builtin=False, **opts)``

key

name

builtin
whether to put the binding in the builtin section this means if the user
defines bindings using "{name}", they won't be ignored or overwritten -
instead, they are preferred to the bindings defined with this call

opts
boolean members (repeatable, complex)


Possible event names
--------------------

::

mpv.MPV_EVENT_NONE
mpv.MPV_EVENT_SHUTDOWN
mpv.MPV_EVENT_LOG_MESSAGE
mpv.MPV_EVENT_GET_PROPERTY_REPLY
mpv.MPV_EVENT_SET_PROPERTY_REPLY
mpv.MPV_EVENT_COMMAND_REPLY
mpv.MPV_EVENT_START_FILE
mpv.MPV_EVENT_END_FILE
mpv.MPV_EVENT_FILE_LOADED
mpv.MPV_EVENT_CLIENT_MESSAGE
mpv.MPV_EVENT_VIDEO_RECONFIG
mpv.MPV_EVENT_AUDIO_RECONFIG
mpv.MPV_EVENT_SEEK
mpv.MPV_EVENT_PLAYBACK_RESTART
mpv.MPV_EVENT_PROPERTY_CHANGE
mpv.MPV_EVENT_QUEUE_OVERFLOW
mpv.MPV_EVENT_HOOK
23 changes: 23 additions & 0 deletions TOOLS/python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
mpv python scripts
==================

The python scripts in this folder are inspired from (/ duplicates of)
`TOOLS/lua/*`.

The python scripts in this folder can be loaded on a one-time basis by
adding the option

--script=/path/to/script.py

to mpv's command line.

Where appropriate, they may also be placed in ~/.config/mpv/scripts/ from
where they will be automatically loaded when mpv starts.

This is only a small selection of internally maintained scripts. Some of them
are just for testing mpv internals, or serve as examples. An extensive
user-edited list of 3rd party scripts is available here:

https://github.com/mpv-player/mpv/wiki/User-Scripts

(Anyone can add their own scripts to that list.)
Loading
Loading