mpv icon indicating copy to clipboard operation
mpv copied to clipboard

Python Scripting Support [RFC]

Open varbhat opened this issue 2 years ago • 40 comments

Dear mpv community,

I and @8lurry are excited to introduce Python scripting support for mpv through python-embed. With this PR merged, you can use Python for scripting in mpv just how you can use Lua/JS for scripting currently. And I am sure that Python will bring numerous benefits to mpv as a scripting language like:

  1. Rich Scripting Capabilities: Python's clean and expressive syntax, dynamic typing, and rich standard library make it easy to write and maintain scripts for mpv. With Python, users can customize mpv's behavior, automate repetitive tasks, implement complex logic, and create interactive interfaces, opening up new possibilities for personalization and creativity.
  2. Wide Range of Libraries: Python has a vast ecosystem of libraries for various purposes, such as multimedia processing, image manipulation, text processing, machine learning, networking, and more. By incorporating Python scripting into mpv, users can take advantage of these libraries to extend mpv's functionality, add new features, and integrate with other tools and services.
  3. Large Community and Active Development: Python has a massive community of developers and users, with a vast ecosystem of packages, documentation, forums, and resources. By introducing Python scripting support for mpv, we can tap into this community's knowledge, expertise, and enthusiasm, fostering collaboration, innovation, and continuous improvement.

Some People who script mpv are using Lua to act as bridge between mpv and Python. And with Python scripting, this will stop.

We have solved Python-embed's threading issue currently thanks to @8lurry. And when we get per interpreter-GIL in Python 3.12 (https://peps.python.org/pep-0684/), it can be improved even further making the implementation analogous to Lua/Mujs implementations.

With this PR, you can run Python scripts in mpv but we still need to map many mpv functions to Python (We will be updating them in upcoming commits in PR). This PR acts as POC for time being.

We are seeking Feedback on this PR and hope to get this merged within mpv.

CC: @avih , @sfan5 , @Dudemanguy

varbhat avatar Apr 11 '23 17:04 varbhat

i have some concerns regarding add python Scripting Support just like JavaScript

look like i need to do more research

amayra avatar Apr 12 '23 01:04 amayra

Would the per interpreter-GIL in the upcoming python version allow for the elimination of a lot of the python-specific logic that's in this current implementation and let it behave more like lua/js do?

Dudemanguy avatar Apr 12 '23 02:04 Dudemanguy

@Dudemanguy I hope so.

varbhat avatar Apr 12 '23 03:04 varbhat

To an end user It shouldn't seem anything different to any other scripts (js/lua) although the underlying implementation is different.

8lurry avatar Apr 12 '23 09:04 8lurry

@Dudemanguy , FYI, this version of it will work with older python nicely maybe down to python3.3.

8lurry avatar Apr 12 '23 09:04 8lurry

Well if python 3.12 makes it possible to solve some of the technical challenges with embedding python in mpv, I'd think it'd be better to make that the minimum version. That's not to say that the current implementation is bad, but it'd definitely be better if python could just be yet another scripting backend. Plus it's only about a month until python 3.12 releases.

Dudemanguy avatar Apr 12 '23 19:04 Dudemanguy

Python 3.12 is 6 months away. I don't think that waiting for Python 3.12 should block this PR.

LaserEyess avatar Apr 12 '23 20:04 LaserEyess

Oh my mistake. I thought it was next month for some reason.

Dudemanguy avatar Apr 12 '23 21:04 Dudemanguy

There are some existing issues with lower level threads (threads created from the scope outside of python). On such a thread python loses its I/O wrappers (and god knows what else). These problems will still exist in 3.12. But the isolation proposed in pep-0684 can be done from the python context. In my opinion and in performance-wise, there'd be hardly any difference between the two (that is if the former approach was doable).

8lurry avatar Apr 15 '23 07:04 8lurry

This sounds very interesting! Could you share a sample script?

I imagine this could pave the way for a variety of scripts, including ones to easily modify the UI/UX, like context menus, and make mpv scripting more accessible to casual users

versedwildcat avatar Apr 16 '23 13:04 versedwildcat

@versedwildcat , it's still a work in progress. We have just developed a working solution to some problems that we had with embedding python on mpv. We are still a step away from getting you this feature. mpv client API hooks still need to be mapped to python functions. I am working on some part of it as I am replying to you. Thank you for your patience.

8lurry avatar Apr 16 '23 13:04 8lurry

I've converted this PR to a draft for now until it's ready for review-for-merge.

Traneptora avatar Apr 20 '23 23:04 Traneptora

Hello guys, Long time! I had been away long since. Picked up my incomplete work on this thread, and managed to run this gist: https://gist.github.com/8lurry/a57d61acfd9aa1f120446f8c3d982f97 successfully. I'd love to see you guys have tried it out. @Dudemanguy @varbhat @LaserEyess

8lurry avatar Jul 25 '23 16:07 8lurry

Tried it on win11, ran into this issue:

    python: could not load client. discarding: testfile.
    python: no active client found.Could not load python (null)

and if I quit after that I run into assertion failed: image

I've built it using python-embedded 3.11.4. VapourSynthPython as an example works fine with this build.

Also occasionally run into this:

mpv.com --msg-level=python=trace
    python: Loading python scripts...
    python:  (testfile) loading binding b
(crash)

DeadSix27 avatar Jul 29 '23 10:07 DeadSix27

@DeadSix27 , the issues you've mentioned should go away now. I hope to see, all the test cases passing. ;)

8lurry avatar Aug 02 '23 14:08 8lurry

@DeadSix27 , the issues you've mentioned should go away now. I hope to see, all the test cases passing. ;)

Github said this pr has conflicts with master branch. Can you resolved it?This will makes it easier for us to merge and test locally.Thanks

zhongfly avatar Aug 02 '23 14:08 zhongfly

@zhongfly , There you have it.

8lurry avatar Aug 02 '23 16:08 8lurry

@8lurry

    python: could not load client. discarding: testfile.
    python: no active client found.
    python: Could not load python (null)

Same error's still.. any idea?

EDIT: Sometimes I encounter this one:

    python: illegal client. does not have an 'mpv' instance (use: from mpvclient import mpv). discarding: testfile.
    python: no active client found.
    python: Could not load python (null)

I'm using your example script, it definitely has the import.

DeadSix27 avatar Aug 02 '23 18:08 DeadSix27

@8lurry I also build it with python-embedded 3.11.4. I try this very simple script:

from mpvclient import mpv
mpv.info("Python script work!")

mpv crash after script run. Log:

...
[   0.030][d][python] Loading python scripts...
...
[ 229.939][i][python]  (python-test) Python script work!

gdb:

Thread 11 "mpv/python (python)" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 5268.0x5044]
0x00007ff6d34cde5a in script_log.lto_priv ()
(gdb) where
#0  0x00007ff6d34cde5a in script_log.lto_priv ()
#1  0x00007ff8306109e6 in python311!_PyObject_MakeTpCall () from D:\mpv-python\python311.dll
#2  0x00007ff830614548 in python311!PyObject_Vectorcall () from D:\mpv-python\python311.dll
#3  0x00007ff830615da4 in python311!_PyEval_EvalFrameDefault () from D:\mpv-python\python311.dll
#4  0x00007ff83067f196 in python311!PyIter_Send () from D:\mpv-python\python311.dll
#5  0x00007ff830637568 in python311!PyList_AsTuple () from D:\mpv-python\python311.dll

Build file can be download here: https://github.com/zhongfly/mpv-winbuild/actions/runs/5745111914

zhongfly avatar Aug 03 '23 01:08 zhongfly

@DeadSix27

    python: could not load client. discarding: testfile.
    python: no active client found.
    python: Could not load python (null)

^ This may come if your client (testfile.py) is not valid. (i.e. testfile.py has SyntaxError or something)

    python: illegal client. does not have an 'mpv' instance (use: from mpvclient import mpv). discarding: testfile.
    python: no active client found.
    python: Could not load python (null)

^ It won't come if you have "from mpvclient import mpv" on it.

8lurry avatar Aug 03 '23 16:08 8lurry

@8lurry syntax is 100% correct and the import is also correct.

EDIT: Shouldn't mpv notify if the syntax is wrong including traceback?

Also same error as zhong:

Thread 9 "mpv/python (python)" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 5644.0x3fdc]
0x00007ff67f5e6333 in handle_log ()
(gdb) bt
#0  0x00007ff67f5e6333 in handle_log ()
#1  0x00007fff438509e6 in python311!_PyObject_MakeTpCall () from C:\Python311\python311.dll
#2  0x00007fff43854548 in python311!PyObject_Vectorcall () from C:\Python311\python311.dll
#3  0x00007fff43855da4 in python311!_PyEval_EvalFrameDefault () from C:\Python311\python311.dll
#4  0x00007fff438bf196 in python311!PyIter_Send () from C:\Python311\python311.dll
#5  0x00007fff43877568 in python311!PyList_AsTuple () from C:\Python311\python311.dll
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

DeadSix27 avatar Aug 04 '23 00:08 DeadSix27

@DeadSix27 , Could you try it again with doing the following changes?

# self.enable_client_message()
for client in self.clients.values():
    if client.has_binding():
        self.enable_client_message()
        break

And afterwards let me know if the issue persists.

8lurry avatar Aug 06 '23 06:08 8lurry

@DeadSix27 , Could you try it again with doing the following changes?

# self.enable_client_message()
for client in self.clients.values():
    if client.has_binding():
        self.enable_client_message()
        break

And afterwards let me know if the issue persists.

I have tried this,but same issue.This fix not work.

zhongfly avatar Aug 06 '23 07:08 zhongfly

@zhongfly , @DeadSix27 , Would you get me the complete log when you run it (please be sure to set the log level to 'debug').

8lurry avatar Aug 06 '23 08:08 8lurry

@zhongfly , @DeadSix27 , Would you get me the complete log when you run it (please be sure to set the log level to 'debug').

The logs have little relevant information,I have set msg-level=all=trace mpv.log

If I tried to run mpv.info twice,mpv will crash after first one.

from mpvclient import mpv
mpv.info("Python script start!") # mpv crash after here
mpv.info("Python script end!")

mpv-2.log

zhongfly avatar Aug 06 '23 08:08 zhongfly

Build file can be download here: https://github.com/zhongfly/mpv-winbuild/actions/runs/5745111914

@zhongfly, compile it on a windows system instead.

8lurry avatar Aug 07 '23 07:08 8lurry

Build file can be download here: https://github.com/zhongfly/mpv-winbuild/actions/runs/5745111914

@zhongfly, compile it on a windows system instead.

Cross compiling is the go to method, it should work via that and that should be the main interest, I'm sure @zhongfly agrees.

DeadSix27 avatar Aug 07 '23 10:08 DeadSix27

It says here, mingw works with python versions upto 3.4. See: https://wiki.python.org/moin/WindowsCompilers#GCC_-MinGW-w64.28x86.2C_x64.29

8lurry avatar Aug 07 '23 13:08 8lurry

It says here, mingw works with python versions upto 3.4. See: https://wiki.python.org/moin/WindowsCompilers#GCC_-MinGW-w64.28x86.2C_x64.29

Both python wiki and mingw are out of date. The latest version of python works well with mingw-w64, see: https://packages.msys2.org/base/mingw-w64-python.

GalaxySnail avatar Aug 07 '23 13:08 GalaxySnail

Syntax errors now display fine, still same issues as before though, sometimes it tells me mpv hasn't been imported, sometimes it runs the prints in a script and then just crashes just like before.

EDIT: can you make it more verbose?: [ 0.192][e][python] could not load client. discarding: testfile. [ 0.282][e][python] illegal client. does not have an 'mpv' instance (use: from mpvclient import mpv). discarding: testfile2.

Why could it not load the client testfile and testfile2 has this content:

# import os
from mpvclient import mpv
# from pathlib import Path

print("hi")

mpv.info("test")

DeadSix27 avatar Aug 08 '23 14:08 DeadSix27