Hello community,
here is the log from the commit of package python-python-mpv for
openSUSE:Factory checked in at 2020-07-17 20:50:11
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-python-mpv (Old)
and /work/SRC/openSUSE:Factory/.python-python-mpv.new.3592 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-python-mpv"
Fri Jul 17 20:50:11 2020 rev:13 rq:821382 version:0.4.8
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-python-mpv/python-python-mpv.changes
2020-07-14 07:59:42.281870278 +0200
+++
/work/SRC/openSUSE:Factory/.python-python-mpv.new.3592/python-python-mpv.changes
2020-07-17 20:50:46.756915856 +0200
@@ -1,0 +2,11 @@
+Fri Jul 17 05:17:54 UTC 2020 - Luigi Baldoni <[email protected]>
+
+- Update to version 0.4.8
+ * README: add video overlay example
+ * mpv.py: add wait_until_paused, wait_until_playing
+ * mpv.py: Add overlay support
+ * mpv.py: add some missing commands
+ * added "python_requires"
+ * remove superfluous whitespaces
+
+-------------------------------------------------------------------
Old:
----
python-mpv-0.4.7.tar.gz
New:
----
python-mpv-0.4.8.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-python-mpv.spec ++++++
--- /var/tmp/diff_new_pack.3xGw5Y/_old 2020-07-17 20:50:48.056917212 +0200
+++ /var/tmp/diff_new_pack.3xGw5Y/_new 2020-07-17 20:50:48.060917216 +0200
@@ -17,7 +17,7 @@
Name: python-python-mpv
-Version: 0.4.7
+Version: 0.4.8
Release: 0
Summary: Python interface to the mpv media player
License: AGPL-3.0-or-later
++++++ python-mpv-0.4.7.tar.gz -> python-mpv-0.4.8.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-mpv-0.4.7/PKG-INFO
new/python-mpv-0.4.8/PKG-INFO
--- old/python-mpv-0.4.7/PKG-INFO 2020-07-12 13:30:54.000000000 +0200
+++ new/python-mpv-0.4.8/PKG-INFO 2020-07-16 21:06:35.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: python-mpv
-Version: 0.4.7
+Version: 0.4.8
Summary: A python interface to the mpv media player
Home-page: https://github.com/jaseg/python-mpv
Author: jaseg
@@ -20,4 +20,5 @@
Classifier: Programming Language :: Python :: 3.5
Classifier: Topic :: Multimedia :: Sound/Audio :: Players
Classifier: Topic :: Multimedia :: Video :: Display
+Requires-Python: >=3.5
Provides-Extra: screenshot_raw
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-mpv-0.4.7/README.rst
new/python-mpv-0.4.8/README.rst
--- old/python-mpv-0.4.7/README.rst 2020-07-12 13:25:58.000000000 +0200
+++ new/python-mpv-0.4.8/README.rst 2020-07-16 19:46:24.000000000 +0200
@@ -122,6 +122,45 @@
del player
+Video overlays
+..............
+
+.. code:: python
+
+ #!/usr/bin/env python3
+ import time
+ from PIL import Image, ImageDraw, ImageFont
+ import mpv
+
+ player = mpv.MPV()
+
+ player.loop = True
+ player.play('test.webm')
+ player.wait_until_playing()
+
+ font = ImageFont.truetype('DejaVuSans.ttf', 40)
+
+ while not player.core_idle:
+
+ time.sleep(0.5)
+ overlay = player.create_image_overlay()
+
+ for pos in range(0, 500, 5):
+ ts = player.time_pos
+ if ts is None:
+ break
+
+ img = Image.new('RGBA', (400, 150), (255, 255, 255, 0))
+ d = ImageDraw.Draw(img)
+ d.text((10, 10), 'Hello World', font=font, fill=(0, 255, 255, 128))
+ d.text((10, 60), f't={ts:.3f}', font=font, fill=(255, 0, 255, 255))
+
+ overlay.update(img, pos=(2*pos, pos))
+ time.sleep(0.05)
+
+ overlay.remove()
+
+
Playlist handling
.................
@@ -187,7 +226,7 @@
player = mpv.MPV()
player.play('test.webm')
- player.wait_for_property('core-idle', lambda idle: not idle)
+ player.wait_until_playing()
player.sub_add('test.srt')
player.wait_for_playback()
@@ -285,7 +324,7 @@
application = MainClass()
Gtk.main()
-Using OpenGL from PyGObject via new render context API
+Using OpenGL from PyGObject via new render context API
......................................................
Just like it is possible to render into a GTK widget through X11 windows, it
`also is possible to render into a GTK
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-mpv-0.4.7/mpv.py new/python-mpv-0.4.8/mpv.py
--- old/python-mpv-0.4.7/mpv.py 2020-07-12 12:47:40.000000000 +0200
+++ new/python-mpv-0.4.8/mpv.py 2020-07-16 19:19:44.000000000 +0200
@@ -144,7 +144,7 @@
('w', c_int),
('h', c_int),
('internal_format', c_int)]
-
+
def __init__(self, w, h, fbo=0, internal_format=0):
self.w, self.h = w, h
self.fbo = fbo
@@ -164,7 +164,7 @@
('connector_id', c_int),
('atomic_request_ptr', c_void_p),
('render_fd', c_int)]
-
+
class MpvOpenGLDRMDrawSurfaceSize(Structure):
_fields_ = [('width', c_int), ('height', c_int)]
@@ -640,32 +640,39 @@
eid = devent['event_id']
for callback in event_callbacks:
callback(devent)
+
if eid in (MpvEventID.SHUTDOWN, MpvEventID.END_FILE):
with playback_cond:
playback_cond.notify_all()
+
if eid == MpvEventID.PROPERTY_CHANGE:
pc = devent['event']
name, value, _fmt = pc['name'], pc['value'], pc['format']
-
for handler in property_handlers[name]:
handler(name, value)
+
if eid == MpvEventID.LOG_MESSAGE and log_handler is not None:
ev = devent['event']
log_handler(ev['level'], ev['prefix'], ev['text'])
+
if eid == MpvEventID.CLIENT_MESSAGE:
# {'event': {'args': ['key-binding', 'foo', 'u-', 'g']},
'reply_userdata': 0, 'error': 0, 'event_id': 16}
target, *args = devent['event']['args']
if target in message_handlers:
message_handlers[target](*args)
+
if eid == MpvEventID.SHUTDOWN:
_mpv_detach_destroy(event_handle)
return
+
except Exception as e:
traceback.print_exc()
_py_to_mpv = lambda name: name.replace('_', '-')
_mpv_to_py = lambda name: name.replace('-', '_')
+_drop_nones = lambda *args: [ arg for arg in args if arg is not None ]
+
class _Proxy:
def __init__(self, mpv):
super().__setattr__('mpv', mpv)
@@ -736,6 +743,80 @@
self._read_iter = iter([]) # make next read() call return EOF
# TODO?
+
+class ImageOverlay:
+ def __init__(self, m, overlay_id, img=None, pos=(0, 0)):
+ self.m = m
+ self.overlay_id = overlay_id
+ self.pos = pos
+ self._size = None
+ if img is not None:
+ self.update(img)
+
+ def update(self, img=None, pos=None):
+ from PIL import Image
+ if img is not None:
+ self.img = img
+ img = self.img
+
+ w, h = img.size
+ stride = w*4
+
+ if pos is not None:
+ self.pos = pos
+ x, y = self.pos
+
+ # Pre-multiply alpha channel
+ bg = Image.new('RGBA', (w, h), (0, 0, 0, 0))
+ out = Image.alpha_composite(bg, img)
+
+ # Copy image to ctypes buffer
+ if img.size != self._size:
+ self._buf = create_string_buffer(w*h*4)
+ self._size = img.size
+
+ self._buf[:] = out.tobytes('raw', 'BGRA')
+ source = '&' + str(addressof(self._buf))
+
+ self.m.overlay_add(self.overlay_id, x, y, source, 0, 'bgra', w, h,
stride)
+
+ def remove(self):
+ self.m.remove_overlay(self.overlay_id)
+
+
+class FileOverlay:
+ def __init__(self, m, overlay_id, filename=None, size=None, stride=None,
pos=(0,0)):
+ self.m = m
+ self.overlay_id = overlay_id
+ self.pos = pos
+ self.size = size
+ self.stride = stride
+ if filename is not None:
+ self.update(filename)
+
+ def update(self, filename=None, size=None, stride=None, pos=None):
+ if filename is not None:
+ self.filename = filename
+
+ if pos is not None:
+ self.pos = pos
+
+ if size is not None:
+ self.size = size
+
+ if stride is not None:
+ self.stride = stride
+
+ x, y = self.pos
+ w, h = self.size
+ stride = self.stride or 4*w
+
+ self.m.overlay_add(self, self.overlay_id, x, y, self.filename, 0,
'bgra', w, h, stride)
+
+ def remove(self):
+ self.m.remove_overlay(self.overlay_id)
+
+
class MPV(object):
"""See man mpv(1) for the details of the implemented commands. All mpv
properties can be accessed as
``my_mpv.some_property`` and all mpv options can be accessed as
``my_mpv['some-option']``.
@@ -789,6 +870,8 @@
self.register_stream_protocol('python', self._python_stream_open)
self._python_streams = {}
self._python_stream_catchall = None
+ self.overlay_ids = set()
+ self.overlays = {}
if loglevel is not None or log_handler is not None:
self.set_loglevel(loglevel or 'terminal-default')
if start_event_thread:
@@ -803,6 +886,14 @@
with self._playback_cond:
self._playback_cond.wait()
+ def wait_until_paused(self):
+ """Waits until playback of the current title is paused or done."""
+ self.wait_for_property('core-idle')
+
+ def wait_until_playing(self):
+ """Waits until playback of the current title has started."""
+ self.wait_for_property('core-idle', lambda idle: not idle)
+
def wait_for_property(self, name, cond=lambda val: val,
level_sensitive=True):
"""Waits until ``cond`` evaluates to a truthy value on the named
property. This can be used to wait for
properties such as ``idle_active`` indicating the player is done with
regular playback and just idling around
@@ -869,8 +960,8 @@
self.command('revert_seek');
def frame_step(self):
- """Mapped mpv frame_step command, see man mpv(1)."""
- self.command('frame_step')
+ """Mapped mpv frame-step command, see man mpv(1)."""
+ self.command('frame-step')
def frame_back_step(self):
"""Mapped mpv frame_back_step command, see man mpv(1)."""
@@ -911,6 +1002,34 @@
b,g,r,a = img.split()
return Image.merge('RGB', (r,g,b))
+ def allocate_overlay_id(self):
+ free_ids = set(range(64)) - self.overlay_ids
+ if not free_ids:
+ raise IndexError('All overlay IDs are in use')
+ next_id, *_ = sorted(free_ids)
+ self.overlay_ids.add(next_id)
+ return next_id
+
+ def free_overlay_id(self, overlay_id):
+ self.overlay_ids.remove(overlay_id)
+
+ def create_file_overlay(self, filename=None, size=None, stride=None,
pos=(0,0)):
+ overlay_id = self.allocate_overlay_id()
+ overlay = FileOverlay(self, overlay_id, filename, size, stride, pos)
+ self.overlays[overlay_id] = overlay
+ return overlay
+
+ def create_image_overlay(self, img=None, pos=(0,0)):
+ overlay_id = self.allocate_overlay_id()
+ overlay = ImageOverlay(self, overlay_id, img, pos)
+ self.overlays[overlay_id] = overlay
+ return overlay
+
+ def remove_overlay(self, overlay_id):
+ self.overlay_remove(overlay_id)
+ self.free_overlay_id(overlay_id)
+ del self.overlays[overlay_id]
+
def playlist_next(self, mode='weak'):
"""Mapped mpv playlist_next command, see man mpv(1)."""
self.command('playlist_next', mode)
@@ -919,6 +1038,10 @@
"""Mapped mpv playlist_prev command, see man mpv(1)."""
self.command('playlist_prev', mode)
+ def playlist_play_index(self, idx):
+ """Mapped mpv playlist-play-index command, see man mpv(1)."""
+ self.command('playlist-play-index', idx)
+
@staticmethod
def _encode_options(options):
return ','.join('{}={}'.format(_py_to_mpv(str(key)), str(val)) for
key, val in options.items())
@@ -943,6 +1066,14 @@
"""Mapped mpv playlist_move command, see man mpv(1)."""
self.command('playlist_move', index1, index2)
+ def playlist_shuffle(self):
+ """Mapped mpv playlist-shuffle command, see man mpv(1)."""
+ self.command('playlist-shuffle')
+
+ def playlist_unshuffle(self):
+ """Mapped mpv playlist-unshuffle command, see man mpv(1)."""
+ self.command('playlist-unshuffle')
+
def run(self, command, *args):
"""Mapped mpv run command, see man mpv(1)."""
self.command('run', command, *args)
@@ -955,9 +1086,40 @@
"""Mapped mpv quit_watch_later command, see man mpv(1)."""
self.command('quit_watch_later', code)
- def sub_add(self, filename):
+ def stop(self, keep_playlist=False):
+ """Mapped mpv stop command, see man mpv(1)."""
+ if keep_playist:
+ self.command('stop', 'keep-playlist')
+ else:
+ self.command('stop')
+
+ def audio_add(self, url, flags='select', title=None, lang=None):
+ """Mapped mpv audio_add command, see man mpv(1)."""
+ self.command('audio_add', url.encode(fs_enc), *_drop_nones(flags,
title, lang))
+
+ def audio_remove(self, audio_id=None):
+ """Mapped mpv audio_remove command, see man mpv(1)."""
+ self.command('audio_remove', audio_id)
+
+ def audio_reload(self, audio_id=None):
+ """Mapped mpv audio_reload command, see man mpv(1)."""
+ self.command('audio_reload', audio_id)
+
+ def video_add(self, url, flags='select', title=None, lang=None):
+ """Mapped mpv video_add command, see man mpv(1)."""
+ self.command('video_add', url.encode(fs_enc), *_drop_nones(flags,
title, lang))
+
+ def video_remove(self, video_id=None):
+ """Mapped mpv video_remove command, see man mpv(1)."""
+ self.command('video_remove', video_id)
+
+ def video_reload(self, video_id=None):
+ """Mapped mpv video_reload command, see man mpv(1)."""
+ self.command('video_reload', video_id)
+
+ def sub_add(self, url, flags='select', title=None, lang=None):
"""Mapped mpv sub_add command, see man mpv(1)."""
- self.command('sub_add', filename.encode(fs_enc))
+ self.command('sub_add', url.encode(fs_enc), *_drop_nones(flags, title,
lang))
def sub_remove(self, sub_id=None):
"""Mapped mpv sub_remove command, see man mpv(1)."""
@@ -979,18 +1141,60 @@
"""Mapped mpv osd command, see man mpv(1)."""
self.command('osd')
+ def print_text(self, text):
+ """Mapped mpv print-text command, see man mpv(1)."""
+ self.command('print-text', text)
+
def show_text(self, string, duration='-1', level=None):
"""Mapped mpv show_text command, see man mpv(1)."""
self.command('show_text', string, duration, level)
+ def expand_text(self, text):
+ """Mapped mpv expand-text command, see man mpv(1)."""
+ return self.node_command('expand-text', text)
+
+ def expand_path(self, path):
+ """Mapped mpv expand-path command, see man mpv(1)."""
+ return self.node_command('expand-path', path)
+
def show_progress(self):
"""Mapped mpv show_progress command, see man mpv(1)."""
self.command('show_progress')
+ def rescan_external_files(self, mode='reselect'):
+ """Mapped mpv rescan-external-files command, see man mpv(1)."""
+ self.command('rescan-external-files', mode)
+
def discnav(self, command):
"""Mapped mpv discnav command, see man mpv(1)."""
self.command('discnav', command)
+ def mouse(x, y, button=None, mode='single'):
+ """Mapped mpv mouse command, see man mpv(1)."""
+ if button is None:
+ self.command('mouse', x, y, mode)
+ else:
+ self.command('mouse', x, y, button, mode)
+
+ def keypress(self, name):
+ """Mapped mpv keypress command, see man mpv(1)."""
+ self.command('keypress', name)
+
+ def keydown(self, name):
+ """Mapped mpv keydown command, see man mpv(1)."""
+ self.command('keydown', name)
+
+ def keyup(self, name=None):
+ """Mapped mpv keyup command, see man mpv(1)."""
+ if name is None:
+ self.command('keyup')
+ else:
+ self.command('keyup', name)
+
+ def keybind(self, name, command):
+ """Mapped mpv keybind command, see man mpv(1)."""
+ self.command('keybind', name, command)
+
def write_watch_later_config(self):
"""Mapped mpv write_watch_later_config command, see man mpv(1)."""
self.command('write_watch_later_config')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-mpv-0.4.7/python_mpv.egg-info/PKG-INFO
new/python-mpv-0.4.8/python_mpv.egg-info/PKG-INFO
--- old/python-mpv-0.4.7/python_mpv.egg-info/PKG-INFO 2020-07-12
13:30:54.000000000 +0200
+++ new/python-mpv-0.4.8/python_mpv.egg-info/PKG-INFO 2020-07-16
21:06:35.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: python-mpv
-Version: 0.4.7
+Version: 0.4.8
Summary: A python interface to the mpv media player
Home-page: https://github.com/jaseg/python-mpv
Author: jaseg
@@ -20,4 +20,5 @@
Classifier: Programming Language :: Python :: 3.5
Classifier: Topic :: Multimedia :: Sound/Audio :: Players
Classifier: Topic :: Multimedia :: Video :: Display
+Requires-Python: >=3.5
Provides-Extra: screenshot_raw
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-mpv-0.4.7/setup.py
new/python-mpv-0.4.8/setup.py
--- old/python-mpv-0.4.7/setup.py 2020-07-12 13:30:36.000000000 +0200
+++ new/python-mpv-0.4.8/setup.py 2020-07-16 21:06:00.000000000 +0200
@@ -3,7 +3,7 @@
from setuptools import setup
setup(
name = 'python-mpv',
- version = '0.4.7',
+ version = '0.4.8',
py_modules = ['mpv'],
description = 'A python interface to the mpv media player',
url = 'https://github.com/jaseg/python-mpv',
@@ -17,6 +17,7 @@
test_suite = 'mpv-test',
keywords = ['mpv', 'library', 'video', 'audio', 'player', 'display',
'multimedia'],
+ python_requires='>=3.5',
classifiers = [
'Development Status :: 4 - Beta',
'Environment :: X11 Applications',