python: update distribution
authorOlivier Aubert <contact@olivieraubert.net>
Sat, 6 Oct 2018 22:07:52 +0000 (00:07 +0200)
committerOlivier Aubert <contact@olivieraubert.net>
Sat, 6 Oct 2018 22:07:52 +0000 (00:07 +0200)
generated/3.0/examples/cocoavlc.py
generated/3.0/vlc.py
generated/dev/vlc.py [changed mode: 0644->0755]
generator/generate.py

index 3beb6d3..9e65fc4 100755 (executable)
@@ -1,20 +1,19 @@
 
 # -*- coding: utf-8 -*-
 
-# Original <http://Code.Google.com/archive/p/cocoa-python>
-
 # Example of using PyCocoa <http://PyPI.org/project/PyCocoa> to create
 # a window, table and an application menu to run a video using VLC on
 # macOS.  The Python-VLC binding <http://PyPI.Python.org/pypi/python-vlc>
-# and the corresponding VLC App,see <http://www.VideoLan.org/index.html>.
+# and the corresponding VLC App, see <http://www.VideoLan.org/index.html>.
 
-# This VLC player has only been tested with VLC 2.2.6, 3.0.1, 3.0.2 and
-# 3.0.3 and the corresponding vlc.py Python-VLC binding using 64-bit
-# Python 2.7.14 and 3.6.4 on macOS 10.13.4 High Sierra.  The player does
-# not work using PyPy Python <http://PyPy.org> nor with Intel(R)
-# Python <http://Software.Intel.com/en-us/distribution-for-python>.
+# This VLC player has only been tested with VLC 2.2.6, 2.2.8, 3.0.1,
+# 3.0.2 and 3.0.3 and the compatible vlc.py Python-VLC binding using
+# 64-bit Python 2.7.14, 2.7.15, 3.6.4, 3.6.5 and/or 3.7.0 on macOS
+# 10.13.4, 10.13.5 and 10.13.6 High Sierra.  This player does not work
+# using PyPy Python <http://PyPy.org> nor with Intel(R) Python
+# <http://Software.Intel.com/en-us/distribution-for-python>.
 
-# MIT License <http://opensource.org/licenses/MIT>
+# MIT License <http://OpenSource.org/licenses/MIT>
 #
 # Copyright (C) 2017-2018 -- mrJean1 at Gmail dot com
 #
 
 
 def _PyPI(package):
-    return '<http://PyPI.org/project/%s>' % (package,)
-
+    return 'see <http://PyPI.org/project/%s>' % (package,)
 
-try:
+try:  # PYCHOK expected
     import vlc
 except ImportError:
-    raise ImportError('no %s module, see %s?' % ('vlc.py', _PyPI('python-vlc')))
+    raise ImportError('no %s module, %s' % ('vlc.py', _PyPI('Python-VLC')))
 try:
-    import pycocoa  # PYCHOK expected
+    from pycocoa import __version__ as __PyCocoa__
 except ImportError:
-    raise ImportError('no %s module, see %s?' % ('pycocoa', _PyPI('PyCocoa')))
-# the imports listed explicitly to help PyChecker
-from pycocoa import App, app_title, aspect_ratio, bytes2str, \
-                    closeTables, Item, MediaWindow, Menu, OpenPanel, \
-                    printf, str2bytes, Table, z1000str, zSIstr, \
-                    __version__ as __PyCocoa__  # PYCHOK expected
+    raise ImportError('no %s module, %s' % ('pycocoa', _PyPI('PyCocoa')))
+if __PyCocoa__ < '18.08.09':
+    raise ImportError('%s %s or later required, %s' % ('pycocoa', '18.8.9',
+                     _PyPI('PyCocoa')))
+del _PyPI
+
+# all imports listed explicitly to help PyChecker
+from pycocoa import App, app_title, aspect_ratio, bytes2str, closeTables, \
+                    get_printer, Item, ItemSeparator, MediaWindow, Menu, \
+                    OpenPanel, printf, str2bytes, Table, z1000str, zSIstr
+
 import os
 import platform
 import sys
 from time import strftime, strptime
+try:
+    from urllib import unquote as mrl_unquote  # Python 2
+except ImportError:
+    from urllib.parse import unquote as mrl_unquote  # Python 3+
 
 __all__  = ('AppVLC',)
-__version__ = '18.06.09'
-
-if __PyCocoa__ < '18.06.02':
-    raise ImportError('%s %s or newer required, see %s' % ('pycocoa',
-                      '18.6.2', _PyPI('PyCocoa')))
-del _PyPI, pycocoa
+__version__ = '18.08.15'
 
 _Adjust  = vlc.VideoAdjustOption  # Enum
 # <http://Wiki.VideoLan.org/Documentation:Modules/adjust>
@@ -74,6 +76,7 @@ _Adjust3 = {_Adjust.Brightness: (0, 1, 2),
             _Adjust.Gamma:   (0.01, 1, 10),
             _Adjust.Hue:        (0, 0, 360),
             _Adjust.Saturation: (0, 1, 3)}
+_Argv0   = os.path.splitext(os.path.basename(__file__))[0]
 _macOS   = platform.mac_ver()[0:3:2]  # PYCHOK false
 _Movies  = '.m4v', '.mov', '.mp4'  # lower-case file types for movies, videos
 _Python  = sys.version.split()[0], platform.architecture()[0]  # PYCHOK false
@@ -83,7 +86,7 @@ _VLC_3_  = vlc.__version__.split('.')[0] > '2' and \
 
 
 def _mspf(fps):
-    # convert frames per second to frame length in millisecs
+    # convert frames per second to frame length in millisecs per frame
     return 1000.0 / (fps or 25)
 
 
@@ -94,23 +97,33 @@ class AppVLC(App):
        Set things up inside the C{.__init__} and C{.appLauched_}
        methods, start by calling the C{.run} method.
     '''
-    adjustr = ''
-    marquee = None
-    logostr = ''
-    panel   = None
-    player  = None
-    resized = False
-    scale   = 1  # media zoom factor
-    video   = None
-    window  = None
-
-    def __init__(self, video=None, adjustr='', logostr='', marquee=False, **kwds):
-        super(AppVLC, self).__init__(**kwds)
+    adjustr   = ''
+    marquee   = None
+    logostr   = ''
+    player    = None
+    raiser    = False
+    resized   = False
+    scale     = 1  # media zoom factor
+    Snapshot  = Item('Snapshot', key='s', alt=True)
+    snapshots = 0
+    Toggle    = None
+    video     = None
+    window    = None
+
+    def __init__(self, video=None,       # video file name
+                       adjustr='',       # vlc.VideoAdjustOption
+                       logostr='',       # vlc.VideoLogoOption
+                       marquee=False,    # vlc.VideoMarqueeOption
+                       raiser=False,     # re-raise errors
+                       title='AppVLC'):  # window title
+        super(AppVLC, self).__init__(raiser=raiser, title=title)
         self.adjustr = adjustr
         self.logostr = logostr
         self.marquee = marquee
-        self.panel   = OpenPanel(_Select)
+        self.media   = None
         self.player  = vlc.MediaPlayer()
+        self.raiser  = raiser
+        self.Toggle  = Item('Play', self.menuToggle_, key='p', ctrl=True)
         self.video   = video
 
     def appLaunched_(self, app):
@@ -118,9 +131,9 @@ class AppVLC(App):
         self.window = MediaWindow(title=self.video or self.title)
 
         if self.player:
-            # the VLC player on macOS needs an NSView
+            # the VLC player on macOS needs an ObjC NSView
             self.player.set_nsobject(self.window.NSview)
-            self.player.set_mrl(self.video)
+            self.media = self.player.set_mrl(self.video)
 
             if self.adjustr:  # preset video options
                 for o in self.adjustr.lower().split(','):
@@ -137,27 +150,34 @@ class AppVLC(App):
 
             menu = Menu('VLC')
             menu.append(
-                # the action/method for each item is
-                # 'menu' + item.title + '_', with
-                # spaces and dots removed, see the
-                # function pycocoa.title2action.
-                menu.item('Open...', key='o'),
-                menu.separator(),
-                menu.item('Info', key='i'),
-                menu.item('Close Windows', key='w'),
-                menu.separator(),
-                menu.item('Play',   key='p', ctrl=True),
-                menu.item('Pause',  key='s', ctrl=True),
-                menu.item('Rewind', key='r', ctrl=True),
-                menu.separator(),
-                menu.item('Zoom In',  key='+'),
-                menu.item('Zoom Out', key='-'),
-                menu.item('Faster', key='>', shift=True),
-                menu.item('Slower', key='<', shift=True))
+                # the action/method name for each item
+                # is string 'menu' + item.title + '_',
+                # without any spaces and trailing dots,
+                # see function pycocoa.title2action.
+                Item('Open...', key='o'),
+                ItemSeparator(),
+                Item('Info', key='i'),
+                Item('Close Windows', key='w'),
+                ItemSeparator(),
+                self.Toggle,  # Play >< Pause
+                Item('Rewind', key='r', ctrl=True),
+                ItemSeparator(),
+                Item('Zoom In',  key='+'),
+                Item('Zoom Out', key='-'),
+                ItemSeparator(),
+                Item('Faster', key='>', shift=True),
+                Item('Slower', key='<', shift=True))
             if _VLC_3_:
                 menu.append(
-                    menu.item('Brighter'),
-                    menu.item('Darker'))
+                    Item('Brighter', key='b', shift=True),
+                    Item('Darker',   key='d', shift=True))
+            menu.append(
+                ItemSeparator(),
+                Item('Audio Filters', self.menuFilters_, key='a', shift=True),
+                Item('Video Filters', self.menuFilters_, key='v', shift=True))
+            menu.append(
+                ItemSeparator(),
+                self.Snapshot)
             self.append(menu)
 
         self.menuPlay_(None)
@@ -179,16 +199,35 @@ class AppVLC(App):
     def menuFaster_(self, item):
         self._rate(item, 1.25)
 
-    def menuInfo_(self, item):
+    def menuFilters_(self, item):
         try:
             self.menuPause_(item)
+            # display audio/video filters table
+            t = Table(' Name:150:bold', ' Short:150:Center:center', ' Long:300', 'Help')
+            i = self.player.get_instance()
+            b = item.title.split()[0]
+            for f in sorted(i.audio_filter_list_get() if b == 'Audio'
+                       else i.video_filter_list_get()):
+                while f and not f[-1]:  # "rstrip" None
+                    f = f[:-1]
+                t.append(*map(bytes2str, f))
+
+            t.display('VLC %s Filters' % (b,), width=800)
 
-            # display Python, vlc, libVLC, media info
+        except Exception as x:
+            if self.raiser:
+                raise
+            printf('%s', x, nl=1, nt=1)
+
+    def menuInfo_(self, item):
+        try:
+            self.menuPause_(item)
+            # display Python, vlc, libVLC, media info table
             p = self.player
             m = p.get_media()
 
-            t = Table(' Name:bold', ' Value:200:Center:center', ' Alt:300')
-            t.append('cocoavlc', __version__, '20' + __version__)
+            t = Table(' Name:bold', ' Value:200:Center:center', ' Alt:100')
+            t.append(_Argv0, __version__, '20' + __version__)
             t.append('PyCocoa', __PyCocoa__, '20' + __PyCocoa__)
             t.append('Python', *_Python)
             t.append('macOS', *_macOS)
@@ -202,16 +241,17 @@ class AppVLC(App):
             t.append('libVLC', *bytes2str(vlc.libvlc_get_compiler()).split(None, 1))
             t.separator()
 
-            f = bytes2str(m.get_mrl())
+            f = mrl_unquote(bytes2str(m.get_mrl()))
             t.append('media', os.path.basename(f), f)
-            if f.startswith('file:///'):
+            if f.lower().startswith('file://'):
                 z = os.path.getsize(f[7:])
                 t.append('size', z1000str(z), zSIstr(z))
             t.append('state', str(p.get_state()))
-            t.append('track/count', z1000str(p.video_get_track()), z1000str(p.video_get_track_count()))
-            t.append('time/duration', z1000str(p.get_time()), z1000str(m.get_duration()))
             f = max(p.get_position(), 0)
             t.append('position', '%.2f%%' % (f * 100,), f)
+            f = ['%.3f s' % (ms * 1e-3) for ms in (p.get_time(), m.get_duration())]
+            t.append('time/duration', *f)  # both shown in seconds
+            t.append('track/count', z1000str(p.video_get_track()), z1000str(p.video_get_track_count()))
             t.separator()
 
             f = p.get_fps()
@@ -227,58 +267,107 @@ class AppVLC(App):
             t.append('scale', '%.3f' % (p.video_get_scale(),), '%.3f' % (self.scale,))
             t.separator()
 
-            def _VLCadjustr2(option):
+            def VLCadjustr2(option):  # get option value
                 lo, _, hi = _Adjust3[option]
                 f = self.player.video_get_adjust_float(option)
                 p = max(0, (f - lo)) * 100.0 / (hi - lo)
                 t = '%.2f %.1f%%' % (f, p)
+                # return 2-tuple (value, percentage) as strings
                 return t.replace('.0%', '%').replace('.00', '.0').split()
 
-            t.append('brightness', *_VLCadjustr2(_Adjust.Brightness))
-            t.append('contrast',   *_VLCadjustr2(_Adjust.Contrast))
-            t.append('gamma',      *_VLCadjustr2(_Adjust.Gamma))
-            t.append('hue',        *_VLCadjustr2(_Adjust.Hue))
-            t.append('saturation', *_VLCadjustr2(_Adjust.Saturation))
+            t.append('brightness', *VLCadjustr2(_Adjust.Brightness))
+            t.append('contrast',   *VLCadjustr2(_Adjust.Contrast))
+            t.append('gamma',      *VLCadjustr2(_Adjust.Gamma))
+            t.append('hue',        *VLCadjustr2(_Adjust.Hue))
+            t.append('saturation', *VLCadjustr2(_Adjust.Saturation))
             t.separator()
 
-            t.display('Python, VLC & Media Information', width=600)
+            s = vlc.MediaStats()  # re-use single MediaStats instance?
+            if m.get_stats(s):
+
+                def Kops2bpstr2(bitrate):  # convert Ko/s to bits/sec
+                    # bitrates are conventionally in kilo-octets-per-sec
+                    return zSIstr(bitrate * 8000, B='bps', K=1000).split()
+
+                t.append('media read',     *zSIstr(s.read_bytes).split())
+                t.append('input bitrate',  *Kops2bpstr2(s.input_bitrate))
+                if s.input_bitrate > 0:  # XXX approximate caching, based
+                    # on <http://GitHub.com/oaubert/python-vlc/issues/61>
+                    b = s.read_bytes - s.demux_read_bytes
+                    c = b / (s.input_bitrate * 1000)
+                    t.append('input caching', '%.3f s' % (c,), zSIstr(b))
+                t.append('demux read',     *zSIstr(s.demux_read_bytes).split())
+                t.append('stream bitrate', *Kops2bpstr2(s.demux_bitrate))
+
+                t.append('video decoded', z1000str(s.decoded_video),      'blocks')
+                t.append('video played',  z1000str(s.displayed_pictures), 'frames')
+                t.append('video lost',    z1000str(s.lost_pictures),      'frames')
+
+                t.append('audio decoded', z1000str(s.decoded_audio),   'blocks')
+                t.append('audio played',  z1000str(s.played_abuffers), 'buffers')
+                t.append('audio lost',    z1000str(s.lost_abuffers),   'buffers')
+
+            t.display('Python, VLC & Media Information', width=500)
 
         except Exception as x:
-            printf('%r', x, nl=1, nt=1)
+            if self.raiser:
+                raise
+            printf('%s', x, nl=1, nt=1)
 
     def menuOpen_(self, item):
         # stop the current video and show
         # the panel to select another video
         self.menuPause_(item)
         self.badge.label = 'O'
-        video = self.panel.pick(_Movies)
-        if video:
-            self.window.title = self.video = video
-            self.player.set_mrl(video)
+        v = OpenPanel(_Select).pick(_Movies)
+        if v:
+            self.window.title = self.video = v
+            self.player.set_mrl(v)
             self.ratio = 3
             self._resize(True)
 
-    def menuPause_(self, item):  # PYCHOK expected
-        # note, .pause() pauses and un-pauses the video,
-        # .stop() stops the video and blanks the window
-        if self.player.is_playing():
+    def menuPause_(self, item, pause=False):  # PYCHOK expected
+        # note, .player.pause() pauses and un-pauses the video,
+        # .player.stop() stops the video and blanks the window
+        if pause or self.player.is_playing():
             self.player.pause()
-            self.badge.label = 'S'
+            self.badge.label = 'S'  # stopped
+            self.Toggle.title = 'Play'  # item.title = 'Play'
 
     def menuPlay_(self, item_or_None):  # PYCHOK expected
         self.player.play()
-        self.badge.label = 'P'
+        self.badge.label = 'P'  # Playing
+        self.Toggle.title = 'Pause'  # item.title = 'Pause'
 
     def menuRewind_(self, item):  # PYCHOK expected
         self.player.set_position(0.0)
-        # can't re-play once at the end
-        # self.player.play()
+        # note, can't re-play once at the end
+        # self.menuPlay_()
         self.badge.label = 'R'
         self._resize(False)
 
     def menuSlower_(self, item):
         self._rate(item, 0.80)
 
+    def menuSnapshot_(self, item):  # PYCHOK expected
+        w = self.lastWindow
+        if w:
+            self.snapshots += 1
+            s = '-'.join((_Argv0,
+                          'snapshot%d' % (self.snapshots,),
+                           w.__class__.__name__))
+            if isinstance(w, MediaWindow):
+                self.player.video_take_snapshot(0, s + '.png', 0, 0)
+            elif get_printer:  # in PyCocoa 18.08.04+
+                get_printer().printView(w.PMview, toPDF=s + '.pdf')
+
+    def menuToggle_(self, item):
+        # toggle between Pause and Play
+        if self.player.is_playing():
+            self.menuPause_(item, pause=True)
+        else:
+            self.menuPlay_(item)
+
     def menuZoomIn_(self, item):
         self._zoom(item, 1.25)
 
@@ -289,8 +378,13 @@ class AppVLC(App):
         # quit or click of window close button
         if window is self.window:
             self.terminate()
+        self.Snapshot.isEnabled = False
         super(AppVLC, self).windowClose_(window)
 
+    def windowLast_(self, window):
+        self.Snapshot.isEnabled = window.isPrintable or isinstance(window, MediaWindow)
+        super(AppVLC, self).windowLast_(window)
+
     def windowResize_(self, window):
         if window is self.window:
             self._resize(False)
@@ -330,7 +424,7 @@ class AppVLC(App):
         # adjust a video option like brightness, contrast, etc.
         p = self.player
         # <http://Wiki.VideoLan.org/Documentation:Modules/adjust>
-        # note, .Enable must be set to 1, but once will suffices
+        # note, .Enable must be set to 1, but once is sufficient
         p.video_set_adjust_int(_Adjust.Enable, 1)
         try:
             lo, _, hi = _Adjust3[option]
@@ -362,7 +456,7 @@ class AppVLC(App):
         # put video marquee at the bottom-center
         p = self.player
         m = vlc.VideoMarqueeOption  # Enum
-        # <http://Wiki.VideoLan.org/Documentation:Modules/marq/=>
+        # <http://Wiki.VideoLan.org/Documentation:Modules/marq>
         p.video_set_marquee_int(m.Enable, 1)
         p.video_set_marquee_int(m.Size, int(size))  # pixels
         p.video_set_marquee_int(m.Position, vlc.Position.Bottom)
@@ -391,6 +485,7 @@ if __name__ == '__main__':  # MCCABE 20
 
     _adjustr = ''
     _argv0   = os.path.basename(sys.argv[0])  # _Title
+    _Argv0   = os.path.splitext(_argv0)[0]
     _logostr = ''
     _marquee = False
     _raiser  = False
index 8a6f885..4fe001f 100644 (file)
@@ -55,7 +55,7 @@ logger = logging.getLogger(__name__)
 __version__ = "3.0.4105"
 __libvlc_version__ = "3.0.4"
 __generator_version__ = "1.5"
-build_date  = "Sat Oct  6 22:46:09 2018 3.0.4"
+build_date  = "Sat Oct  6 23:10:52 2018 3.0.4"
 
 # The libvlc doc states that filenames are expected to be in UTF8, do
 # not rely on sys.getfilesystemencoding() which will be confused,
@@ -1812,10 +1812,7 @@ class Instance(_Ctype):
             i = head
             while i:
                 i = i.contents
-                d = [{'id':       libvlc_audio_output_device_id      (self, i.name, d),
-                      'longname': libvlc_audio_output_device_longname(self, i.name, d)}
-                   for d in range(libvlc_audio_output_device_count   (self, i.name))]
-                r.append({'name': i.name, 'description': i.description, 'devices': d})
+                r.append({'name': i.name, 'description': i.description})
                 i = i.next
             libvlc_audio_output_list_release(head)
         return r
@@ -3212,18 +3209,6 @@ class MediaPlayer(_Ctype):
         """
         return track_description_list(libvlc_video_get_spu_description(self))
 
-    def video_get_title_description(self):
-        """Get the description of available titles.
-        """
-        return track_description_list(libvlc_video_get_title_description(self))
-
-    def video_get_chapter_description(self, title):
-        """Get the description of available chapters for specific title.
-
-        @param title: selected title (int)
-        """
-        return track_description_list(libvlc_video_get_chapter_description(self, title))
-
     def video_get_track_description(self):
         """Get the description of available video tracks.
         """
@@ -3354,6 +3339,21 @@ class MediaPlayer(_Ctype):
         return libvlc_media_player_get_agl(self)
 
 
+    def video_get_title_description(self):
+        '''Get the description of available titles.
+        @return: list containing description of available titles. It must be freed with L{track_description_list_release}().
+        '''
+        return libvlc_video_get_title_description(self)
+
+
+    def video_get_chapter_description(self, i_title):
+        '''Get the description of available chapters for specific title.
+        @param i_title: selected title.
+        @return: list containing description of available chapter for title i_title. It must be freed with L{track_description_list_release}().
+        '''
+        return libvlc_video_get_chapter_description(self, i_title)
+
+
     def video_set_subtitle_file(self, psz_subtitle):
         '''Set new video subtitle file.
         \deprecated Use L{add_slave}() instead.
old mode 100644 (file)
new mode 100755 (executable)
index eb8c083..ced9ae0
@@ -55,7 +55,7 @@ logger = logging.getLogger(__name__)
 __version__ = "4.0.0-dev-4987-g028c89ad19105"
 __libvlc_version__ = "4.0.0-dev-4987-g028c89ad19"
 __generator_version__ = "1.5"
-build_date  = "Sat Oct  6 22:46:09 2018 4.0.0-dev-4987-g028c89ad19"
+build_date  = "Sat Oct  6 23:10:52 2018 4.0.0-dev-4987-g028c89ad19"
 
 # The libvlc doc states that filenames are expected to be in UTF8, do
 # not rely on sys.getfilesystemencoding() which will be confused,
@@ -1898,10 +1898,7 @@ class Instance(_Ctype):
             i = head
             while i:
                 i = i.contents
-                d = [{'id':       libvlc_audio_output_device_id      (self, i.name, d),
-                      'longname': libvlc_audio_output_device_longname(self, i.name, d)}
-                   for d in range(libvlc_audio_output_device_count   (self, i.name))]
-                r.append({'name': i.name, 'description': i.description, 'devices': d})
+                r.append({'name': i.name, 'description': i.description})
                 i = i.next
             libvlc_audio_output_list_release(head)
         return r
@@ -2931,18 +2928,6 @@ class MediaPlayer(_Ctype):
         """
         return track_description_list(libvlc_video_get_spu_description(self))
 
-    def video_get_title_description(self):
-        """Get the description of available titles.
-        """
-        return track_description_list(libvlc_video_get_title_description(self))
-
-    def video_get_chapter_description(self, title):
-        """Get the description of available chapters for specific title.
-
-        @param title: selected title (int)
-        """
-        return track_description_list(libvlc_video_get_chapter_description(self, title))
-
     def video_get_track_description(self):
         """Get the description of available video tracks.
         """
index a6924bc..87e8ba8 100755 (executable)
@@ -56,7 +56,7 @@ __all__     = ('Parser',
 
 # Version number MUST have a major < 10 and a minor < 99 so that the
 # generated dist version can be correctly generated.
-__version__ =  '1.5'
+__version__ =  '1.6'
 
 _debug = False