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 - sogal@opensuse.org
+
+- Fix interpreter.patch
+
+-------------------------------------------------------------------
+Sun Dec 23 10:28:41 UTC 2018 - sogal@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
# Some bits taken from quodlibet mpris plugin by
+
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: