# pylint: disable=C0111,R0903 # -*- coding: utf-8 -*- """Displays information about the current song in mpd. Requires the following executable: * mpc Parameters: * mpd.format: Format string for the song information. Supported tags (see `man mpc` for additional information) * {name} * {artist} * {album} * {albumartist} * {comment} * {composer} * {date} * {originaldate} * {disc} * {genre} * {performer} * {title} * {track} * {time} * {file} * {id} * {prio} * {mtime} * {mdate} Additional tags: * {position} - position of currently playing song not to be confused with %position% mpc tag * {duration} - duration of currently playing song * {file1} - song file name without path prefix if {file} = '/foo/bar.baz', then {file1} = 'bar.baz' * {file2} - song file name without path prefix and extension suffix if {file} = '/foo/bar.baz', then {file2} = 'bar' * mpd.host: MPD host to connect to. (mpc behaviour by default) * mpd.layout: Space-separated list of widgets to add. Possible widgets are the buttons/toggles mpd.prev, mpd.next, mpd.shuffle and mpd.repeat, and the main display with play/pause function mpd.main. contributed by `alrayyes `_ - many thanks! """ from collections import defaultdict import string import os import core.module import core.widget import core.input import core.decorators import util.cli class Module(core.module.Module): def __init__(self, config, theme): super().__init__(config, theme, []) self._layout = self.parameter( "layout", "mpd.prev mpd.main mpd.next mpd.shuffle mpd.repeat" ) self._fmt = self.parameter("format", "{artist} - {title} {position}/{duration}") self._status = None self._shuffle = False self._repeat = False self._tags = defaultdict(lambda: "") if not self.parameter("host"): self._hostcmd = "" else: self._hostcmd = " -h " + self.parameter("host") # Create widgets widget_list = [] widget_map = {} for widget_name in self._layout.split(): widget = core.widget.Widget(name=widget_name, module=self) widget_list.append(widget) if widget_name == "mpd.prev": widget_map[widget] = { "button": core.input.LEFT_MOUSE, "cmd": "mpc prev" + self._hostcmd, } elif widget_name == "mpd.main": widget_map[widget] = { "button": core.input.LEFT_MOUSE, "cmd": "mpc toggle" + self._hostcmd, } widget.full_text(self.description) elif widget_name == "mpd.next": widget_map[widget] = { "button": core.input.LEFT_MOUSE, "cmd": "mpc next" + self._hostcmd, } elif widget_name == "mpd.shuffle": widget_map[widget] = { "button": core.input.LEFT_MOUSE, "cmd": "mpc random" + self._hostcmd, } elif widget_name == "mpd.repeat": widget_map[widget] = { "button": core.input.LEFT_MOUSE, "cmd": "mpc repeat" + self._hostcmd, } else: raise KeyError( "The mpd module does not support a {widget_name!r} widget".format( widget_name=widget_name ) ) self.widgets(widget_list) # Register input callbacks for widget, callback_options in widget_map.items(): core.input.register(widget, **callback_options) def hidden(self): return self._status is None @core.decorators.scrollable def description(self, widget): return string.Formatter().vformat(self._fmt, (), self._tags) def update(self): self._load_song() def state(self, widget): if widget.name == "mpd.shuffle": return "shuffle-on" if self._shuffle else "shuffle-off" if widget.name == "mpd.repeat": return "repeat-on" if self._repeat else "repeat-off" if widget.name == "mpd.prev": return "prev" if widget.name == "mpd.next": return "next" return self._status def _load_song(self): info = "" tags = [ "name", "artist", "album", "albumartist", "comment", "composer", "date", "originaldate", "disc", "genre", "performer", "title", "track", "time", "file", "id", "prio", "mtime", "mdate", ] joinedtags = "\n".join(["tag {0} %{0}%".format(tag) for tag in tags]) info = util.cli.execute( 'mpc -f "{}"{}'.format(joinedtags, self._hostcmd), ignore_errors=True ) self._tags = defaultdict(lambda: "") self._status = None for line in info.split("\n"): if line.startswith("[playing]"): self._status = "playing" elif line.startswith("[paused]"): self._status = "paused" if line.startswith("["): timer = line.split()[2] position = timer.split("/")[0] dur = timer.split("/")[1] duration = dur.split(" ")[0] self._tags.update({"position": position}) self._tags.update({"duration": duration}) if line.startswith("volume"): value = line.split(" ", 2)[1:] for option in value: if option.startswith("repeat: on"): self._repeat = True elif option.startswith("repeat: off"): self._repeat = False elif option.startswith("random: on"): self._shuffle = True elif option.startswith("random: off"): self._shuffle = False if line.startswith("tag"): key, value = line.split(" ", 2)[1:] self._tags.update({key: value}) if key == "file": self._tags.update({"file1": os.path.basename(value)}) self._tags.update( {"file2": os.path.splitext(os.path.basename(value))[0]} ) # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4