Hello community,

here is the log from the commit of package mpDris2 for openSUSE:Factory checked 
in at 2018-12-31 09:47:26
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/mpDris2 (Old)
 and      /work/SRC/openSUSE:Factory/.mpDris2.new.28833 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "mpDris2"

Mon Dec 31 09:47:26 2018 rev:4 rq:662115 version:0.7

Changes:
--------
--- /work/SRC/openSUSE:Factory/mpDris2/mpDris2.changes  2018-08-20 
16:22:34.513090110 +0200
+++ /work/SRC/openSUSE:Factory/.mpDris2.new.28833/mpDris2.changes       
2018-12-31 09:48:03.222134624 +0100
@@ -1,0 +2,13 @@
+Sun Dec 23 10:49:50 UTC 2018 - so...@opensuse.org
+
+- Fix interpreter.patch
+
+-------------------------------------------------------------------
+Sun Dec 23 10:28:41 UTC 2018 - so...@opensuse.org
+
+- Update to current Github version, including the following:
+  * Catch Mutagen exceptions for malformed files
+  * Allow a custom bus name to be specified (for multi-instance)
+  * Use SafeConfigParser#read() and Python3 interpreter
+
+-------------------------------------------------------------------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ interpreter.patch ++++++
--- /var/tmp/diff_new_pack.K4cjDh/_old  2018-12-31 09:48:03.658134267 +0100
+++ /var/tmp/diff_new_pack.K4cjDh/_new  2018-12-31 09:48:03.658134267 +0100
@@ -3,7 +3,7 @@
 --- mpDris2-0.7/src/mpDris2.in.py.orig 2018-05-08 21:18:40.591530305 +0200
 +++ mpDris2-0.7/src/mpDris2.in.py      2018-05-08 21:19:35.171342273 +0200
 @@ -1,4 +1,4 @@
--#!/usr/bin/env python
+-#!/usr/bin/env python3
 +#!/usr/bin/python3
  # -*- coding: utf-8 -*-
  #

++++++ mpDris2-0.7.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpDris2-0.7/NEWS new/mpDris2-0.7/NEWS
--- old/mpDris2-0.7/NEWS        2015-12-18 17:32:13.000000000 +0100
+++ new/mpDris2-0.7/NEWS        2018-11-07 22:15:32.000000000 +0100
@@ -1,3 +1,12 @@
+mpDris2 v0.8 (unreleased)
+
+ - "Playing" and "Paused" notifications now show song information (#71).
+
+ - Path to config file can be changed via command line.
+
+ - There is a hidden option to change the D-Bus service name, for advanced
+   multi-instance configurations.
+
 mpDris2 v0.7 (December 18, 2015)
 
  - Now compatible with both pygobject 2.x and 3.x (#62).
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpDris2-0.7/configure.ac new/mpDris2-0.7/configure.ac
--- old/mpDris2-0.7/configure.ac        2015-12-18 17:32:13.000000000 +0100
+++ new/mpDris2-0.7/configure.ac        2018-11-07 22:15:32.000000000 +0100
@@ -8,7 +8,11 @@
 
 m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
 
-AM_PATH_PYTHON([2.5],, [:])
+AM_PATH_PYTHON([3.4],, [:])
+
+define([gitversion], esyscmd([sh -c "which git > /dev/null && (git describe | 
tr -d '\n' || false)"]))
+GITVERSION="gitversion"
+AC_SUBST(GITVERSION)
 
 GETTEXT_PACKAGE=mpDris2
 AC_SUBST(GETTEXT_PACKAGE)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpDris2-0.7/src/Makefile.am 
new/mpDris2-0.7/src/Makefile.am
--- old/mpDris2-0.7/src/Makefile.am     2015-12-18 17:32:13.000000000 +0100
+++ new/mpDris2-0.7/src/Makefile.am     2018-11-07 22:15:32.000000000 +0100
@@ -21,7 +21,9 @@
        mpDris2
 
 edit = sed -e 's|@bindir[@]|$(bindir)|g' \
-          -e 's|@datadir[@]|$(datadir)|g'
+          -e 's|@datadir[@]|$(datadir)|g' \
+          -e 's|@gitversion[@]|$(GITVERSION)|g' \
+          -e 's|@version[@]|$(VERSION)|g'
 
 mpDris2: mpDris2.in.py Makefile
        $(AM_V_GEN) $(edit) $< > $@.tmp && mv $@.tmp $@
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpDris2-0.7/src/mpDris2.in.py 
new/mpDris2-0.7/src/mpDris2.in.py
--- old/mpDris2-0.7/src/mpDris2.in.py   2015-12-18 17:32:13.000000000 +0100
+++ new/mpDris2-0.7/src/mpDris2.in.py   2018-11-07 22:15:32.000000000 +0100
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 #
 #    This program is free software: you can redistribute it and/or modify
@@ -19,13 +19,13 @@
 # Based on mpDris from: Erik Karlsson <p...@ayeon.org>
 # Some bits taken from quodlibet mpris plugin by <christoph.rei...@gmx.at>
 
+
 from __future__ import print_function
 
 import os
 import sys
 import re
 import shlex
-import signal
 import socket
 import getopt
 import mpd
@@ -36,6 +36,10 @@
 import gettext
 import time
 import tempfile
+import base64
+
+__version__ = "@version@"
+__git_version__ = "@gitversion@"
 
 try:
     import mutagen
@@ -50,7 +54,7 @@
 try:
     import gi
     gi.require_version('Notify', '0.7')
-except ImportError:
+except (ImportError, ValueError):
     pass
 
 using_gi_glib = False
@@ -71,7 +75,7 @@
     try:
         import pynotify
         using_old_notify = True
-    except:
+    except ImportError:
         pass
 
 _ = gettext.gettext
@@ -81,18 +85,28 @@
 params = {
     'progname': sys.argv[0],
     # Connection
-    'host': 'localhost',
-    'port': 6600,
+    'host': None,
+    'port': None,
     'password': None,
+    'bus_name': None,
     # Library
     'music_dir': '',
-    'cover_regex': 
re.compile(r'^(album|cover|\.?folder|front).*\.(gif|jpeg|jpg|png)$',
-                              re.I | re.X),
+    'cover_regex': None,
     # Bling
     'mmkeys': True,
     'notify': (using_gi_notify or using_old_notify),
 }
 
+defaults = {
+    # Connection
+    'host': 'localhost',
+    'port': 6600,
+    'password': None,
+    'bus_name': None,
+    # Library
+    'cover_regex': r'^(album|cover|\.?folder|front).*\.(gif|jpeg|jpg|png)$',
+}
+
 notification = None
 
 # MPRIS allowed metadata tags
@@ -232,6 +246,7 @@
 urlhandlers = ['http://']
 downloaded_covers = ['~/.covers/%s-%s.jpg']
 
+
 class MPDWrapper(object):
     """ Wrapper of mpd.MPDClient to handle socket
         errors and similar
@@ -242,7 +257,7 @@
 
         self._dbus = dbus
         self._params = params
-        self._dbus_service = False
+        self._dbus_service = None
 
         self._can_single = False
         self._can_idle = False
@@ -259,6 +274,7 @@
             'repeat': None,
         }
         self._metadata = {}
+        self._temp_song_url = None
         self._temp_cover = None
         self._position = 0
         self._time = 0
@@ -277,6 +293,10 @@
         else:
             return True
 
+    @property
+    def connected(self):
+        return self.client._sock is not None
+
     def my_connect(self):
         """ Init MPD connection """
         try:
@@ -285,8 +305,12 @@
             self._can_single = False
 
             self.client.connect(self._params['host'], self._params['port'])
-            if params['password']:
-                self.password(self._params['password'])
+            if self._params['password']:
+                try:
+                    self.client.password(self._params['password'])
+                except mpd.CommandError as e:
+                    logger.error(e)
+                    sys.exit(1)
 
             commands = self.commands()
             # added in 0.11
@@ -310,7 +334,7 @@
             self.client._sock.settimeout(5.0)
             # Export our DBUS service
             if not self._dbus_service:
-                self._dbus_service = MPRISInterface(self._params['music_dir'])
+                self._dbus_service = MPRISInterface(self._params)
             else:
                 # Add our service to the session bus
                 #self._dbus_service.add_to_connection(dbus.SessionBus(),
@@ -349,16 +373,14 @@
             if self._errors == 6:
                 logger.info('Continue to connect but going silent')
             return True
-        except mpd.CommandError as e:
-            logger.error('MPD command error: %s' % e)
-            return True
 
     def reconnect(self):
         logger.warning("Disconnected")
         notification.notify(identity, _('Disconnected'), 'error')
 
         # Release the DBus name and disconnect from bus
-        self._dbus_service.release_name()
+        if self._dbus_service is not None:
+            self._dbus_service.release_name()
         #self._dbus_service.remove_from_connection()
 
         # Stop monitoring
@@ -379,6 +401,7 @@
         self.run()
 
     def disconnect(self):
+        self._temp_song_url = None
         if self._temp_cover:
             self._temp_cover.close()
             self._temp_cover = None
@@ -458,18 +481,18 @@
         logger.debug('Got GNOME mmkey "%s" for "%s"' % (key, appname))
         if key == 'Play':
             if self._status['state'] == 'play':
-                notification.notify(identity, _('Paused'))
-                self.pause()
+                self.pause(1)
+                self.notify_about_state('pause')
             else:
-                notification.notify(identity, _('Playing'))
                 self.play()
+                self.notify_about_state('play')
         elif key == 'Next':
             self.next()
         elif key == 'Previous':
             self.previous()
         elif key == 'Stop':
-            notification.notify(identity, _('Stopped'))
             self.stop()
+            self.notify_about_state('stop')
 
     def last_currentsong(self):
         return self._currentsong.copy()
@@ -550,9 +573,13 @@
         if 'file' in mpd_meta:
             song_url = mpd_meta['file']
             if not any([song_url.startswith(prefix) for prefix in 
urlhandlers]):
-                song_url = os.path.join(params['music_dir'], song_url)
+                song_url = os.path.join(self._params['music_dir'], song_url)
             self._metadata['xesam:url'] = song_url
-            cover = self.find_cover(song_url)
+            try:
+                cover = self.find_cover(song_url)
+            except mutagen.MutagenError as e:
+                logger.error("Can't extract covers from %r: %r" % (song_url, 
e))
+                cover = None
             if cover:
                 self._metadata['mpris:artUrl'] = cover
 
@@ -565,26 +592,89 @@
                 logger.error("Can't cast value %r to %s" %
                              (value, allowed_tags[key]))
 
+    def notify_about_track(self, meta, state='play'):
+        uri = 'sound'
+        if 'mpris:artUrl' in meta:
+            uri = meta['mpris:artUrl']
+
+        title = 'Unknown Title'
+        if 'xesam:title' in meta:
+            title = meta['xesam:title']
+        elif 'xesam:url' in meta:
+            title = meta['xesam:url'].split('/')[-1]
+
+        artist = 'Unknown Artist'
+        if 'xesam:artist' in meta:
+            artist = ", ".join(meta['xesam:artist'])
+
+        body = _('by %s') % artist
+
+        if state == 'pause':
+            uri = 'media-playback-pause-symbolic'
+            body += ' (%s)' % _('Paused')
+
+        notification.notify(title, body, uri)
+
+    def notify_about_state(self, state):
+        if state == 'stop':
+            notification.notify(identity, _('Stopped'), 
'media-playback-stop-symbolic')
+        else:
+            self.notify_about_track(self.metadata, state)
+
     def find_cover(self, song_url):
         if song_url.startswith('file://'):
             song_path = song_url[7:]
             song_dir = os.path.dirname(song_path)
+
+            # Try existing temporary file
             if self._temp_cover:
-                self._temp_cover.close()
+                if song_url == self._temp_song_url:
+                    logger.debug("find_cover: Reusing old image at %r" % 
self._temp_cover.name)
+                    return 'file://' + self._temp_cover.name
+                else:
+                    logger.debug("find_cover: Cleaning up old image at %r" % 
self._temp_cover.name)
+                    self._temp_song_url = None
+                    self._temp_cover.close()
 
             # Search for embedded cover art
             if mutagen and os.path.exists(song_path):
                 song = mutagen.File(song_path)
-                if 'APIC:' in song.tags:
-                    self._temp_cover = 
tempfile.NamedTemporaryFile(suffix='.jpg')
-                    self._temp_cover.write(song.tags['APIC:'].data)
-                    self._temp_cover.flush()
-                    return 'file://' + self._temp_cover.name
+                if song.tags:
+                    # present but null for some file types
+                    for tag in song.tags.keys():
+                        if tag.startswith("APIC:"):
+                            for pic in song.tags.getall(tag):
+                                if pic.type == 
mutagen.id3.PictureType.COVER_FRONT:
+                                     self._temp_song_url = song_url
+                                     return self._create_temp_cover(pic)
+                if hasattr(song, "pictures"):
+                    # FLAC
+                    for pic in song.pictures:
+                        if pic.type == mutagen.id3.PictureType.COVER_FRONT:
+                            self._temp_song_url = song_url
+                            return self._create_temp_cover(pic)
+                elif song.tags and 'metadata_block_picture' in song.tags:
+                    # OGG
+                    for b64_data in song.get("metadata_block_picture", []):
+                        try:
+                            data = base64.b64decode(b64_data)
+                        except (TypeError, ValueError):
+                            continue
+
+                        try:
+                            pic = mutagen.flac.Picture(data)
+                        except mutagen.flac.error:
+                            continue
+
+                        if pic.type == mutagen.id3.PictureType.COVER_FRONT:
+                            self._temp_song_url = song_url
+                            return self._create_temp_cover(pic)
+
 
             # Look in song directory for common album cover files
             if os.path.exists(song_dir):
                 for f in os.listdir(song_dir):
-                    if params['cover_regex'].match(f):
+                    if self._params['cover_regex'].match(f):
                         return 'file://' + os.path.join(song_dir, f)
 
             # Search the shared cover directories
@@ -597,6 +687,20 @@
                         return 'file://' + f
         return None
 
+    def _create_temp_cover(self, pic):
+        """
+        Create a temporary file containing pic, and return it's location
+        """
+        extension = {'image/jpeg': '.jpg',
+                     'image/png': '.png',
+                     'image/gif': '.gif'}
+
+        self._temp_cover = tempfile.NamedTemporaryFile(prefix='cover-', 
suffix=extension.get(pic.mime, '.jpg'))
+        self._temp_cover.write(pic.data)
+        self._temp_cover.flush()
+        logger.debug("find_cover: Storing embedded image at %r" % 
self._temp_cover.name)
+        return 'file://' + self._temp_cover.name
+
     def last_status(self):
         if time.time() - self._time >= 2:
             self.timer_callback()
@@ -653,29 +757,16 @@
             self.update_metadata()
             new_meta = 
self._dbus_service.update_property('org.mpris.MediaPlayer2.Player',
                                                           'Metadata')
-            if self._params['notify']:
-                uri = 'sound'
-                if 'mpris:artUrl' in new_meta:
-                    uri = new_meta['mpris:artUrl']
-                title = 'Unknown Title'
-                if 'xesam:title' in new_meta:
-                    title = new_meta['xesam:title']
-                elif 'xesam:url' in new_meta:
-                    title = new_meta['xesam:url'].split('/')[-1]
-                artist = 'Unknown Artist'
-                if 'xesam:artist' in new_meta:
-                    artist = ", ".join(new_meta['xesam:artist'])
 
+            if self._params['notify'] and new_status['state'] != 'stop':
                 if old_meta.get('xesam:artist', None) != 
new_meta.get('xesam:artist', None) \
                     or old_meta.get('xesam:album', None) != 
new_meta.get('xesam:album', None) \
                     or old_meta.get('xesam:title', None) != 
new_meta.get('xesam:title', None) \
                     or old_meta.get('xesam:url', None) != 
new_meta.get('xesam:url', None):
-                    # FIXME: maybe this could be done in a nicer way?
-                    notification.notify(title, _('by %s') % artist, uri)
+                    self.notify_about_track(new_meta, new_status['state'])
 
         # "mixer" subsystem
-
-        if old_status['volume'] != new_status['volume']:
+        if old_status.get('volume') != new_status.get('volume'):
             self._dbus_service.update_property('org.mpris.MediaPlayer2.Player',
                                                'Volume')
 
@@ -707,8 +798,13 @@
 
     def register_mediakeys(self):
         try:
-            gsd_object = self._bus.get_object("org.gnome.SettingsDaemon",
-                                              
"/org/gnome/SettingsDaemon/MediaKeys")
+            try:
+                gsd_object = 
self._bus.get_object("org.gnome.SettingsDaemon.MediaKeys",
+                                                  
"/org/gnome/SettingsDaemon/MediaKeys")
+            except:
+                # Try older name.
+                gsd_object = self._bus.get_object("org.gnome.SettingsDaemon",
+                                                  
"/org/gnome/SettingsDaemon/MediaKeys")
             gsd_object.GrabMediaPlayerKeys("mpDris2", 0,
                                            
dbus_interface="org.gnome.SettingsDaemon.MediaKeys")
         except:
@@ -734,10 +830,19 @@
             return self.client.fileno()
     else:
         def fileno(self):
-            if self.client._sock is None:
+            if not self.connected:
                 raise mpd.ConnectionError("Not connected")
             return self.client._sock.fileno()
 
+    ## Access to python-mpd internal APIs
+
+    # We use _write_command("idle") to manually enter idle mode, as it has no
+    # immediate response to fetch.
+    #
+    # Similarly, we use _write_command("noidle") + _fetch_object() to manually
+    # leave idle mode (for reasons I don't quite remember). The result of
+    # _fetch_object() is not used.
+
     if hasattr(mpd.MPDClient, "_write_command"):
         def _write_command(self, *args):
             return self.client._write_command(*args)
@@ -745,20 +850,34 @@
         def _write_command(self, *args):
             return self.client._writecommand(*args)
 
-    if hasattr(mpd.MPDClient, "_fetch_object"):
-        def _fetch_object(self, *args):
-            return self.client._fetch_object(*args)
+    if hasattr(mpd.MPDClient, "_parse_objects_direct"):
+        def _fetch_object(self):
+            objs = self._fetch_objects()
+            if not objs:
+                return {}
+            return objs[0]
+    elif hasattr(mpd.MPDClient, "_fetch_object"):
+        def _fetch_object(self):
+            return self.client._fetch_object()
     elif hasattr(mpd.MPDClient, "_getobject"):
-        def _fetch_object(self, *args):
-            return self.client._writecommand(*args)
+        def _fetch_object(self):
+            return self.client._getobject()
+
+    # We use _fetch_objects("changed") to receive unprompted idle events on
+    # socket activity.
 
-    if hasattr(mpd.MPDClient, "_fetch_objects"):
+    if hasattr(mpd.MPDClient, "_parse_objects_direct"):
+        def _fetch_objects(self, *args):
+            return 
list(self.client._parse_objects_direct(self.client._read_lines(), *args))
+    elif hasattr(mpd.MPDClient, "_fetch_objects"):
         def _fetch_objects(self, *args):
             return self.client._fetch_objects(*args)
     elif hasattr(mpd.MPDClient, "_getobjects"):
         def _fetch_objects(self, *args):
             return self.client._getobjects(*args)
 
+    # Wrapper to catch connection errors when calling mpd client methods.
+
     def __getattr__(self, attr):
         if attr[0] == "_":
             raise AttributeError(attr)
@@ -766,7 +885,6 @@
             return self.call(attr, *a, **kw)
         return fn
 
-    # Catch connection errors when calling mpd client methods
     def call(self, command, *args):
         fn = getattr(self.client, command)
         try:
@@ -792,8 +910,15 @@
                     self._notification = Notify.Notification()
                     self._notification.set_hint("desktop-entry", 
GLib.Variant("s", "mpdris2"))
                     self._notification.set_hint("transient", GLib.Variant("b", 
True))
+                    try:
+                        self._notification.update("mpdris2 %s started" % 
__version__)
+                        self._notification.show()
+                    except GLib.GError as err:
+                        logger.error("Failed to init libnotify: %s", err)
+                        self._notification = None
                 else:
                     logger.error("Failed to init libnotify; disabling 
notifications")
+                    self._notification = None
             elif using_old_notify:
                 logger.debug("Initializing old pynotify")
                 if pynotify.init(identity):
@@ -802,25 +927,31 @@
                     self._notification.set_hint("transient", True)
                 else:
                     logger.error("Failed to init libnotify; disabling 
notifications")
+                    self._notification = None
 
     def notify(self, title, body, uri=''):
         if self._notification:
-            self._notification.update(title, body, uri)
-            self._notification.show()
+            try:
+                self._notification.update(title, body, uri)
+                self._notification.show()
+            except GLib.GError as err:
+                logger.error("Failed to show notification: %s" % err)
 
 
 class MPRISInterface(dbus.service.Object):
     ''' The base object of an MPRIS player '''
 
-    __name = "org.mpris.MediaPlayer2.mpd"
     __path = "/org/mpris/MediaPlayer2"
     __introspect_interface = "org.freedesktop.DBus.Introspectable"
     __prop_interface = dbus.PROPERTIES_IFACE
 
-    def __init__(self, bus, path=""):
+    def __init__(self, params):
         dbus.service.Object.__init__(self, dbus.SessionBus(),
                                      MPRISInterface.__path)
-        self.path = path
+        self._params = params or {}
+        self._name = self._params["bus_name"] or "org.mpris.MediaPlayer2.mpd"
+        if not self._name.startswith("org.mpris.MediaPlayer2."):
+            logger.warn("Configured bus name %r is outside MPRIS2 namespace" % 
self._name)
 
         self._bus = dbus.SessionBus()
         self._uname = self._bus.get_unique_name()
@@ -828,12 +959,12 @@
                                               "/org/freedesktop/DBus")
         self._dbus_obj.connect_to_signal("NameOwnerChanged",
                                          self._name_owner_changed_callback,
-                                         arg0=self.__name)
+                                         arg0=self._name)
 
         self.acquire_name()
 
     def _name_owner_changed_callback(self, name, old_owner, new_owner):
-        if name == self.__name and old_owner == self._uname and new_owner != 
"":
+        if name == self._name and old_owner == self._uname and new_owner != "":
             try:
                 pid = self._dbus_obj.GetConnectionUnixProcessID(new_owner)
             except:
@@ -842,7 +973,7 @@
             loop.quit()
 
     def acquire_name(self):
-        self._bus_name = dbus.service.BusName(MPRISInterface.__name,
+        self._bus_name = dbus.service.BusName(self._name,
                                               bus=self._bus,
                                               allow_replacement=True,
                                               replace_existing=True)
@@ -908,7 +1039,7 @@
         return dbus.Dictionary(mpd_wrapper.metadata, signature='sv')
 
     def __get_volume():
-        vol = float(mpd_wrapper.last_status()['volume'])
+        vol = float(mpd_wrapper.last_status().get('volume', 0))
         if vol > 0:
             return vol / 100.0
         else:
@@ -1020,31 +1151,31 @@
 
     @dbus.service.method(__player_interface, in_signature='', out_signature='')
     def Pause(self):
-        mpd_wrapper.pause()
-        notification.notify(identity, _('Paused'))
+        mpd_wrapper.pause(1)
+        mpd_wrapper.notify_about_state('pause')
         return
 
     @dbus.service.method(__player_interface, in_signature='', out_signature='')
     def PlayPause(self):
         status = mpd_wrapper.status()
         if status['state'] == 'play':
-            mpd_wrapper.pause()
-            notification.notify(identity, _('Paused'))
+            mpd_wrapper.pause(1)
+            mpd_wrapper.notify_about_state('pause')
         else:
             mpd_wrapper.play()
-            notification.notify(identity, _('Playing'))
+            mpd_wrapper.notify_about_state('play')
         return
 
     @dbus.service.method(__player_interface, in_signature='', out_signature='')
     def Stop(self):
         mpd_wrapper.stop()
-        notification.notify(identity, _('Stopped'))
+        mpd_wrapper.notify_about_state('stop')
         return
 
     @dbus.service.method(__player_interface, in_signature='', out_signature='')
     def Play(self):
         mpd_wrapper.play()
-        notification.notify(identity, _('Playing'))
+        mpd_wrapper.notify_about_state('play')
         return
 
     @dbus.service.method(__player_interface, in_signature='x', 
out_signature='')
@@ -1142,15 +1273,18 @@
 
 def usage(params):
     print("""\
-Usage: %(progname)s [OPTION]... [MPD_HOST] [MPD_PORT]
+Usage: %(progname)s [OPTION]...
+
+     -c, --config=PATH      Read a custom configuration file
 
-Note: Environment variables MPD_HOST and MPD_PORT can be used instead of above
-      arguments.
+     -h, --host=ADDR        Set the mpd server address
+         --port=PORT        Set the TCP port
+         --music-dir=PATH   Set the music library path
 
-     -p, --path=PATH        Sets the library path of MPD to PATH
      -d, --debug            Run in debug mode
+     -v, --version          mpDris2 version
 
-Default: MPD_HOST: %(host)s, MPD_PORT: %(port)s
+Environment variables MPD_HOST and MPD_PORT can be used.
 
 Report bugs to https://github.com/eonpatapon/mpDris2/issues"""; % params)
 
@@ -1160,72 +1294,99 @@
     gettext.bindtextdomain('mpDris2', '@datadir@/locale')
     gettext.textdomain('mpDris2')
 
-    config = configparser.SafeConfigParser()
-    config.read(['/etc/mpDris2.conf'] +
-                list(reversed(each_xdg_config('mpDris2/mpDris2.conf'))))
-
-    if config.has_option('Connection', 'host'):
-        params['host'] = config.get('Connection', 'host')
-    if config.has_option('Connection', 'port'):
-        params['port'] = config.get('Connection', 'port')
-    if config.has_option('Connection', 'password'):
-        params['password'] = config.get('Connection', 'password')
-
-    if 'MPD_HOST' in os.environ:
-        params['host'] = os.environ['MPD_HOST']
-    if 'MPD_PORT' in os.environ:
-        params['port'] = os.environ['MPD_PORT']
-
-    if config.has_option('Library', 'music_dir'):
-        music_dir = config.get('Library', 'music_dir')
-    elif config.has_option('Connection', 'music_dir'):
-        music_dir = config.get('Connection', 'music_dir')
-    else:
-        music_dir = find_music_dir()
-
-    if config.has_option('Library', 'cover_regex'):
-        params['cover_regex'] = re.compile(config.get('Library', 
'cover_regex'), re.I | re.X)
-
-    for bling in ['mmkeys', 'notify']:
-        if config.has_option('Bling', bling):
-            params[bling] = config.getboolean('Bling', bling)
+    log_format = '%(asctime)s %(module)s %(levelname)s: %(message)s'
+    log_level = logging.INFO
+    config_file = None
+    music_dir = None
 
+    # Parse command line
     try:
-        (opts, args) = getopt.getopt(sys.argv[1:], 'hdp:', ['help', 'debug', 
'path='])
+        (opts, args) = getopt.getopt(sys.argv[1:], 'c:dh:p:v',
+                                     ['help', 'bus-name=', 'config=',
+                                      'debug', 'host=', 'music-dir=',
+                                      'path=', 'port=', 'version'])
     except getopt.GetoptError as ex:
         (msg, opt) = ex.args
-        print("%s: %s" % (sys.argv[0], msg))
-        print()
+        print("%s: %s" % (sys.argv[0], msg), file=sys.stderr)
+        print(file=sys.stderr)
         usage(params)
         sys.exit(2)
 
-    log_format = '%(asctime)s %(module)s %(levelname)s: %(message)s'
-    log_level = logging.INFO
-
     for (opt, arg) in opts:
-        if opt in ['-h', '--help']:
+        if opt in ['--help']:
             usage(params)
             sys.exit()
-        elif opt in ['-p', '--path']:
-            music_dir = arg
+        elif opt in ['--bus-name']:
+            params['bus_name'] = arg
+        elif opt in ['-c', '--config']:
+            config_file = arg
         elif opt in ['-d', '--debug']:
             log_level = logging.DEBUG
-
-    logging.basicConfig(format=log_format, level=log_level)
-    logger = logging.getLogger('mpDris2')
+        elif opt in ['-h', '--host']:
+            params['host'] = arg
+        elif opt in ['-p', '--path', '--music-dir']:
+            music_dir = arg
+        elif opt in ['--port']:
+            params['port'] = int(arg)
+        elif opt in ['-v', '--version']:
+            v = __version__
+            if __git_version__:
+                v = __git_version__
+            print("mpDris2 version %s" % v)
+            sys.exit()
 
     if len(args) > 2:
         usage(params)
         sys.exit()
 
+    logging.basicConfig(format=log_format, level=log_level)
+    logger = logging.getLogger('mpDris2')
+
+    # Pick up the server address (argv -> environment -> config)
     for arg in args[:2]:
         if arg.isdigit():
             params['port'] = arg
         else:
             params['host'] = arg
 
+    if not params['host']:
+        if 'MPD_HOST' in os.environ:
+            params['host'] = os.environ['MPD_HOST']
+    if not params['port']:
+        if 'MPD_PORT' in os.environ:
+            params['port'] = os.environ['MPD_PORT']
+
+    # Read configuration
+    config = configparser.SafeConfigParser()
+    if config_file:
+        with open(config_file) as fh:
+            config.read(config_file)
+    else:
+        config.read(['/etc/mpDris2.conf'] +
+                    list(reversed(each_xdg_config('mpDris2/mpDris2.conf'))))
+
+    for p in ['host', 'port', 'password', 'bus_name']:
+        if not params[p]:
+            # TODO: switch to get(fallback=…) when possible
+            if config.has_option('Connection', p):
+                params[p] = config.get('Connection', p)
+            else:
+                params[p] = defaults[p]
+
     if '@' in params['host']:
-        params['password'], params['host'] = params['host'].split('@', 1)
+        params['password'], params['host'] = params['host'].rsplit('@', 1)
+
+    for p in ['mmkeys', 'notify']:
+        if config.has_option('Bling', p):
+            params[p] = config.getboolean('Bling', p)
+
+    if not music_dir:
+        if config.has_option('Library', 'music_dir'):
+            music_dir = config.get('Library', 'music_dir')
+        elif config.has_option('Connection', 'music_dir'):
+            music_dir = config.get('Connection', 'music_dir')
+        else:
+            music_dir = find_music_dir()
 
     if music_dir:
         # Ensure that music_dir starts with an URL scheme.
@@ -1241,6 +1402,14 @@
         logger.warning('By not supplying a path for the music library '
                        'this program will break the MPRIS specification!')
 
+    if config.has_option('Library', 'cover_regex'):
+        cover_regex = config.get('Library', 'cover_regex')
+    else:
+        cover_regex = defaults['cover_regex']
+    params['cover_regex'] = re.compile(cover_regex, re.I | re.X)
+
+    logger.debug('Parameters: %r' % params)
+
     if mutagen:
         logger.info('Using Mutagen to read covers from music files.')
     else:


Reply via email to