[modules/cmus] Add controls for cmus (next/prev/shuffle/repeat)

Add controls that allow the user to switch to the next and previous song
in cmus, toggle shuffle and repeat. Pause/play is toggled by clicking on
the song title itself.

fixes #5
This commit is contained in:
Tobi-wan Kenobi 2016-11-12 12:11:42 +01:00
parent a33cb1d7cb
commit dead54ed1f
7 changed files with 82 additions and 7 deletions

View file

@ -20,6 +20,12 @@ class Module(bumblebee.module.Module):
self._status = "default" self._status = "default"
self._fmt = self._config.parameter("format", "{artist} - {title} {position}/{duration}") self._fmt = self._config.parameter("format", "{artist} - {title} {position}/{duration}")
output.add_callback(module="cmus.prev", button=1, cmd="cmus-remote -r")
output.add_callback(module="cmus.next", button=1, cmd="cmus-remote -n")
output.add_callback(module="cmus.shuffle", button=1, cmd="cmus-remote -S")
output.add_callback(module="cmus.repeat", button=1, cmd="cmus-remote -R")
output.add_callback(module=self.instance(), button=1, cmd="cmus-remote -u")
def _loadsong(self): def _loadsong(self):
process = subprocess.Popen(["cmus-remote", "-Q"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) process = subprocess.Popen(["cmus-remote", "-Q"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
self._query, self._error = process.communicate() self._query, self._error = process.communicate()
@ -30,17 +36,21 @@ class Module(bumblebee.module.Module):
tags = defaultdict(lambda: '') tags = defaultdict(lambda: '')
for line in self._query: for line in self._query:
if line.startswith("status"): if line.startswith("status"):
ignore, status = line.split(" ", 2) status = line.split(" ", 2)[1]
self._status = status self._status = status
if line.startswith("tag"): if line.startswith("tag"):
ignore, key, value = line.split(" ", 2) key, value = line.split(" ", 2)[1:]
tags.update({ key: value }) tags.update({ key: value })
if line.startswith("duration"): if line.startswith("duration"):
ignore, sec = line.split(" ") sec = line.split(" ")[1]
tags.update({ "duration": bumblebee.util.durationfmt(int(sec)) }) tags.update({ "duration": bumblebee.util.durationfmt(int(sec)) })
if line.startswith("position"): if line.startswith("position"):
ignore, sec = line.split(" ") sec = line.split(" ")[1]
tags.update({ "position": bumblebee.util.durationfmt(int(sec)) }) tags.update({ "position": bumblebee.util.durationfmt(int(sec)) })
if line.startswith("set repeat "):
self._repeat = False if line.split(" ")[2] == "false" else True
if line.startswith("set shuffle "):
self._shuffle = False if line.split(" ")[2] == "false" else True
return tags return tags
@ -48,9 +58,19 @@ class Module(bumblebee.module.Module):
self._loadsong() self._loadsong()
tags = self._tags() tags = self._tags()
return bumblebee.output.Widget(self, string.Formatter().vformat(self._fmt, (), tags)) return [
bumblebee.output.Widget(self, "", instance="cmus.prev"),
bumblebee.output.Widget(self, string.Formatter().vformat(self._fmt, (), tags)),
bumblebee.output.Widget(self, "", instance="cmus.next"),
bumblebee.output.Widget(self, "", instance="cmus.shuffle"),
bumblebee.output.Widget(self, "", instance="cmus.repeat"),
]
def state(self, widget): def state(self, widget):
if widget.instance() == "cmus.shuffle":
return "on" if self._shuffle else "off"
if widget.instance() == "cmus.repeat":
return "on" if self._repeat else "off"
return self._status return self._status
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -9,10 +9,11 @@ def output(args):
return bumblebee.outputs.i3.Output(args) return bumblebee.outputs.i3.Output(args)
class Widget(object): class Widget(object):
def __init__(self, obj, text): def __init__(self, obj, text, instance=None):
self._obj = obj self._obj = obj
self._text = text self._text = text
self._store = {} self._store = {}
self._instance = instance
def set(self, key, value): def set(self, key, value):
self._store[key] = value self._store[key] = value
@ -33,7 +34,7 @@ class Widget(object):
return self._obj.__module__.split(".")[-1] return self._obj.__module__.split(".")[-1]
def instance(self): def instance(self):
return getattr(self._obj, "instance")(self) return self._instance if self._instance else getattr(self._obj, "instance")(self)
def text(self): def text(self):
return self._text return self._text

View file

@ -75,14 +75,20 @@ class Theme:
def _get(self, widget, name): def _get(self, widget, name):
module = widget.module() module = widget.module()
state = widget.state() state = widget.state()
inst = widget.instance()
inst = inst.replace("{}.".format(module), "")
module_theme = self._data.get(module, {}) module_theme = self._data.get(module, {})
state_theme = module_theme.get("states", {}).get(state, {}) state_theme = module_theme.get("states", {}).get(state, {})
instance_theme = module_theme.get(inst, {})
instance_state_theme = instance_theme.get("states", {}).get(state, {})
value = None value = None
value = self._defaults.get(name, value) value = self._defaults.get(name, value)
value = self._cycle.get(name, value) value = self._cycle.get(name, value)
value = module_theme.get(name, value) value = module_theme.get(name, value)
value = state_theme.get(name, value) value = state_theme.get(name, value)
value = instance_theme.get(name, value)
value = instance_state_theme.get(name, value)
if type(value) is list: if type(value) is list:
key = "{}{}".format(repr(widget), value) key = "{}{}".format(repr(widget), value)

View file

@ -37,6 +37,18 @@
"stopped": { "stopped": {
"prefix": " [] " "prefix": " [] "
} }
},
"prev": {
"prefix": " |< "
},
"next": {
"prefix": " >| "
},
"shuffle": {
"states": { "on": { "prefix": " S " }, "off": { "prefix": " [s] " } }
},
"repeat": {
"states": { "on": { "prefix": " R " }, "off": { "prefix": " [r] " } }
} }
}, },
"pasink": { "pasink": {

View file

@ -58,6 +58,18 @@
"stopped": { "stopped": {
"prefix": "  " "prefix": "  "
} }
},
"prev": {
"prefix": "  "
},
"next": {
"prefix": "  "
},
"shuffle": {
"states": { "on": { "prefix": "  " }, "off": { "prefix": "  " } }
},
"repeat": {
"states": { "on": { "prefix": "  " }, "off": { "prefix": "  " } }
} }
}, },
"pasink": { "pasink": {

View file

@ -59,6 +59,18 @@
"stopped": { "stopped": {
"prefix": "  " "prefix": "  "
} }
},
"prev": {
"prefix": "  "
},
"next": {
"prefix": "  "
},
"shuffle": {
"states": { "on": { "prefix": "  " }, "off": { "prefix": "  " } }
},
"repeat": {
"states": { "on": { "prefix": "  " }, "off": { "prefix": "  " } }
} }
}, },
"pasink": { "pasink": {

View file

@ -58,6 +58,18 @@
"stopped": { "stopped": {
"prefix": " [] " "prefix": " [] "
} }
},
"prev": {
"prefix": " |< "
},
"next": {
"prefix": " >| "
},
"shuffle": {
"states": { "on": { "prefix": " S " }, "off": { "prefix": " [s] " } }
},
"repeat": {
"states": { "on": { "prefix": " R " }, "off": { "prefix": " [r] " } }
} }
}, },
"pasink": { "pasink": {