commit
10b3f317f4
14 changed files with 149 additions and 67 deletions
14
.github/ISSUE_TEMPLATE/Bug.md
vendored
14
.github/ISSUE_TEMPLATE/Bug.md
vendored
|
@ -1,6 +1,10 @@
|
||||||
---
|
---
|
||||||
name: Bug Report
|
name: Bug Report
|
||||||
about: Something is broken / doesn't work as expected
|
about: Something doesn't work (as expected)
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Bug Report
|
### Bug Report
|
||||||
|
@ -8,17 +12,12 @@ about: Something is broken / doesn't work as expected
|
||||||
#### Summary
|
#### Summary
|
||||||
Affected module: <module name>
|
Affected module: <module name>
|
||||||
|
|
||||||
Description:
|
#### Description:
|
||||||
<description>
|
<description>
|
||||||
|
|
||||||
#### What is the current behaviour and what is the expected behaviour?
|
|
||||||
|
|
||||||
#### How to reproduce
|
#### How to reproduce
|
||||||
<!-- Please provide steps on how to reproduce the issue (screenshots would be great) -->
|
<!-- Please provide steps on how to reproduce the issue (screenshots would be great) -->
|
||||||
|
|
||||||
#### Expected behavior
|
|
||||||
<!-- What was the expected (correct) behavior? -->
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
If you are having problems with fonts, please read:
|
If you are having problems with fonts, please read:
|
||||||
https://github.com/tobi-wan-kenobi/bumblebee-status/issues/228
|
https://github.com/tobi-wan-kenobi/bumblebee-status/issues/228
|
||||||
|
@ -29,4 +28,3 @@ https://github.com/tobi-wan-kenobi/bumblebee-status/issues/233
|
||||||
Please note FontAwesome 5 is currently not supported:
|
Please note FontAwesome 5 is currently not supported:
|
||||||
https://github.com/tobi-wan-kenobi/bumblebee-status/issues/239
|
https://github.com/tobi-wan-kenobi/bumblebee-status/issues/239
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
|
4
.github/ISSUE_TEMPLATE/Feature.md
vendored
4
.github/ISSUE_TEMPLATE/Feature.md
vendored
|
@ -1,6 +1,10 @@
|
||||||
---
|
---
|
||||||
name: Feature Request
|
name: Feature Request
|
||||||
about: You have a neat idea that should be implemented?
|
about: You have a neat idea that should be implemented?
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Feature Request
|
### Feature Request
|
||||||
|
|
20
.github/ISSUE_TEMPLATE/Support.md
vendored
20
.github/ISSUE_TEMPLATE/Support.md
vendored
|
@ -1,20 +0,0 @@
|
||||||
---
|
|
||||||
name: ❓ Support Question
|
|
||||||
about: Have a problem that you can't figure out?
|
|
||||||
---
|
|
||||||
|
|
||||||
<!-- Fill in the relevant information below to help triage your issue. -->
|
|
||||||
<!--
|
|
||||||
Note: All issues will instant closed if the issue template is not complete. Please understand that it is easier for us if you fill out the template to help you faster.
|
|
||||||
|
|
||||||
!All text inside \<\!-- \--\> will be hidden from us so please remove the arrows in the statements below.
|
|
||||||
-->
|
|
||||||
|
|
||||||
| Q | A
|
|
||||||
|------------ | -----
|
|
||||||
| Version | x
|
|
||||||
|
|
||||||
|
|
||||||
#### Support Question
|
|
||||||
<!-- Describe the issue you are facing here. -->
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
[![Test Coverage](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/badges/coverage.svg)](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/coverage)
|
[![Test Coverage](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/badges/coverage.svg)](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/coverage)
|
||||||
[![Issue Count](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/badges/issue_count.svg)](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status)
|
[![Issue Count](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/badges/issue_count.svg)](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status)
|
||||||
|
|
||||||
**Many, many thanks to all contributors! As of now, 48 of the modules are from various contributors (!), and only 19 from myself.**
|
**Many, many thanks to all contributors! As of now, 49 of the modules are from various contributors (!), and only 19 from myself.**
|
||||||
|
|
||||||
![Solarized Powerline](https://github.com/tobi-wan-kenobi/bumblebee-status/blob/master/screenshots/themes/powerline-solarized.png)
|
![Solarized Powerline](https://github.com/tobi-wan-kenobi/bumblebee-status/blob/master/screenshots/themes/powerline-solarized.png)
|
||||||
|
|
||||||
|
@ -189,7 +189,7 @@ Modules and commandline utilities are only required for modules, the core itself
|
||||||
* netifaces (for the modules 'nic', 'traffic')
|
* netifaces (for the modules 'nic', 'traffic')
|
||||||
* requests (for the modules 'weather', 'github', 'getcrypto', 'stock', 'currency', 'sun')
|
* requests (for the modules 'weather', 'github', 'getcrypto', 'stock', 'currency', 'sun')
|
||||||
* power (for the module 'battery')
|
* power (for the module 'battery')
|
||||||
* dbus (for the module 'spotify')
|
* dbus (for the module 'spotify', 'deezer')
|
||||||
* i3ipc (for the module 'title')
|
* i3ipc (for the module 'title')
|
||||||
* pacman-contrib (for module 'arch-update')
|
* pacman-contrib (for module 'arch-update')
|
||||||
* docker (for the module 'docker_ps')
|
* docker (for the module 'docker_ps')
|
||||||
|
|
|
@ -25,9 +25,12 @@ except ImportError:
|
||||||
class Module(bumblebee.engine.Module):
|
class Module(bumblebee.engine.Module):
|
||||||
def __init__(self, engine, config):
|
def __init__(self, engine, config):
|
||||||
self._batteries = []
|
self._batteries = []
|
||||||
|
try:
|
||||||
for battery in os.listdir('/sys/class/power_supply/'):
|
for battery in os.listdir('/sys/class/power_supply/'):
|
||||||
if not any(i in battery for i in ['AC', 'hidpp']):
|
if not any(i in battery for i in ['AC', 'hidpp']):
|
||||||
self._batteries.append("/sys/class/power_supply/" + battery)
|
self._batteries.append("/sys/class/power_supply/" + battery)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
super(Module, self).__init__(engine, config, bumblebee.output.Widget(full_text=self.capacity))
|
super(Module, self).__init__(engine, config, bumblebee.output.Widget(full_text=self.capacity))
|
||||||
|
|
||||||
|
@ -67,11 +70,7 @@ class Module(bumblebee.engine.Module):
|
||||||
errors += 1
|
errors += 1
|
||||||
|
|
||||||
if errors == len(self._batteries):
|
if errors == len(self._batteries):
|
||||||
# if all batteries return errors, but we are still running
|
return "n/a"
|
||||||
# assume we are on A/C
|
|
||||||
widget.set("ac", True)
|
|
||||||
widget.set("capacity", 100)
|
|
||||||
return "ac"
|
|
||||||
|
|
||||||
capacity = int( float(self.energy_now) / float(self.energy_full) * 100.0)
|
capacity = int( float(self.energy_now) / float(self.energy_full) * 100.0)
|
||||||
capacity = capacity if capacity < 100 else 100
|
capacity = capacity if capacity < 100 else 100
|
||||||
|
|
77
bumblebee/modules/deezer.py
Normal file
77
bumblebee/modules/deezer.py
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
# pylint: disable=C0111,R0903
|
||||||
|
|
||||||
|
"""Displays the current song being played
|
||||||
|
Requires the following library:
|
||||||
|
* python-dbus
|
||||||
|
Parameters:
|
||||||
|
* deezer.format: Format string (defaults to "{artist} - {title}")
|
||||||
|
Available values are: {album}, {title}, {artist}, {trackNumber}, {playbackStatus}
|
||||||
|
* deezer.previous: Change binding for previous song (default is left click)
|
||||||
|
* deezer.next: Change binding for next song (default is right click)
|
||||||
|
* deezer.pause: Change binding for toggling pause (default is middle click)
|
||||||
|
Available options for deezer.previous, deezer.next and deezer.pause are:
|
||||||
|
LEFT_CLICK, RIGHT_CLICK, MIDDLE_CLICK, SCROLL_UP, SCROLL_DOWN
|
||||||
|
"""
|
||||||
|
|
||||||
|
import bumblebee.input
|
||||||
|
import bumblebee.output
|
||||||
|
import bumblebee.engine
|
||||||
|
|
||||||
|
from bumblebee.output import scrollable
|
||||||
|
|
||||||
|
try:
|
||||||
|
import dbus
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Module(bumblebee.engine.Module):
|
||||||
|
def __init__(self, engine, config):
|
||||||
|
super(Module, self).__init__(engine, config,
|
||||||
|
bumblebee.output.Widget(full_text=self.deezer)
|
||||||
|
)
|
||||||
|
buttons = {"LEFT_CLICK":bumblebee.input.LEFT_MOUSE,
|
||||||
|
"RIGHT_CLICK":bumblebee.input.RIGHT_MOUSE,
|
||||||
|
"MIDDLE_CLICK":bumblebee.input.MIDDLE_MOUSE,
|
||||||
|
"SCROLL_UP":bumblebee.input.WHEEL_UP,
|
||||||
|
"SCROLL_DOWN":bumblebee.input.WHEEL_DOWN,
|
||||||
|
}
|
||||||
|
|
||||||
|
self._song = ""
|
||||||
|
self._format = self.parameter("format", "{artist} - {title}")
|
||||||
|
prev_button = self.parameter("previous", "LEFT_CLICK")
|
||||||
|
next_button = self.parameter("next", "RIGHT_CLICK")
|
||||||
|
pause_button = self.parameter("pause", "MIDDLE_CLICK")
|
||||||
|
|
||||||
|
cmd = "dbus-send --session --type=method_call --dest=org.mpris.MediaPlayer2.deezer \
|
||||||
|
/org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player."
|
||||||
|
engine.input.register_callback(self, button=buttons[prev_button],
|
||||||
|
cmd=cmd + "Previous")
|
||||||
|
engine.input.register_callback(self, button=buttons[next_button],
|
||||||
|
cmd=cmd + "Next")
|
||||||
|
engine.input.register_callback(self, button=buttons[pause_button],
|
||||||
|
cmd=cmd + "PlayPause")
|
||||||
|
|
||||||
|
## @scrollable
|
||||||
|
def deezer(self, widget):
|
||||||
|
return str(self._song)
|
||||||
|
|
||||||
|
def hidden(self):
|
||||||
|
return str(self._song) == ""
|
||||||
|
|
||||||
|
def update(self, widgets):
|
||||||
|
try:
|
||||||
|
bus = dbus.SessionBus()
|
||||||
|
deezer = bus.get_object("org.mpris.MediaPlayer2.deezer", "/org/mpris/MediaPlayer2")
|
||||||
|
deezer_iface = dbus.Interface(deezer, 'org.freedesktop.DBus.Properties')
|
||||||
|
props = deezer_iface.Get('org.mpris.MediaPlayer2.Player', 'Metadata')
|
||||||
|
playback_status = str(deezer_iface.Get('org.mpris.MediaPlayer2.Player', 'PlaybackStatus'))
|
||||||
|
self._song = self._format.format(album=str(props.get('xesam:album')),
|
||||||
|
title=str(props.get('xesam:title')),
|
||||||
|
artist=','.join(props.get('xesam:artist')),
|
||||||
|
trackNumber=str(props.get('xesam:trackNumber')),
|
||||||
|
playbackStatus=u"\u25B6" if playback_status=="Playing" else u"\u258D\u258D" if playback_status=="Paused" else "",)
|
||||||
|
except Exception:
|
||||||
|
self._song = ""
|
||||||
|
|
||||||
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
|
@ -93,13 +93,21 @@ class Module(bumblebee.engine.Module):
|
||||||
return temperature
|
return temperature
|
||||||
|
|
||||||
def get_mhz(self):
|
def get_mhz(self):
|
||||||
|
mhz = None
|
||||||
try:
|
try:
|
||||||
output = open("/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq").read()
|
output = open("/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq").read()
|
||||||
mhz = int(float(output)/1000.0)
|
mhz = int(float(output)/1000.0)
|
||||||
except:
|
except:
|
||||||
output = open("/proc/cpuinfo").read()
|
output = open("/proc/cpuinfo").read()
|
||||||
m = re.search(r"cpu MHz\s+:\s+(\d+)", output)
|
m = re.search(r"cpu MHz\s+:\s+(\d+)", output)
|
||||||
|
if m:
|
||||||
mhz = int(m.group(1))
|
mhz = int(m.group(1))
|
||||||
|
else:
|
||||||
|
m = re.search(r"BogoMIPS\s+:\s+(\d+)", output)
|
||||||
|
if m:
|
||||||
|
return "{} BogoMIPS".format(int(m.group(1)))
|
||||||
|
if not mhz:
|
||||||
|
return "n/a"
|
||||||
|
|
||||||
if mhz < 1000:
|
if mhz < 1000:
|
||||||
return "{} MHz".format(mhz)
|
return "{} MHz".format(mhz)
|
||||||
|
|
|
@ -132,18 +132,25 @@ class Module(bumblebee.engine.Module):
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def _cpu(self, _):
|
def _cpu(self, _):
|
||||||
|
mhz = None
|
||||||
try:
|
try:
|
||||||
output = open("/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq").read()
|
output = open("/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq").read()
|
||||||
mhz = int(float(output)/1000.0)
|
mhz = int(float(output)/1000.0)
|
||||||
except:
|
except:
|
||||||
output = open("/proc/cpuinfo").read()
|
output = open("/proc/cpuinfo").read()
|
||||||
m = re.search(r"cpu MHz\s+:\s+(\d+)", output)
|
m = re.search(r"cpu MHz\s+:\s+(\d+)", output)
|
||||||
|
if m:
|
||||||
mhz = int(m.group(1))
|
mhz = int(m.group(1))
|
||||||
|
else:
|
||||||
|
m = re.search(r"BogoMIPS\s+:\s+(\d+)", output)
|
||||||
|
if m:
|
||||||
|
return "{} BogoMIPS".format(int(m.group(1)))
|
||||||
|
if not mhz:
|
||||||
|
return "n/a"
|
||||||
|
|
||||||
if mhz < 1000:
|
if mhz < 1000:
|
||||||
return "{} MHz".format(mhz)
|
return "{} MHz".format(mhz)
|
||||||
else:
|
else:
|
||||||
return "{:0.01f} GHz".format(float(mhz)/1000.0)
|
return "{:0.01f} GHz".format(float(mhz)/1000.0)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# -*- coding: UTF-8 -*-
|
# -*- coding: UTF-8 -*-
|
||||||
# pylint: disable=C0111,R0903
|
# pylint: disable=C0111,R0903
|
||||||
|
|
||||||
"""Display a stock quote from yahoo finance.
|
"""Display a stock quote from worldtradingdata.com
|
||||||
|
|
||||||
Requires the following python packages:
|
Requires the following python packages:
|
||||||
* requests
|
* requests
|
||||||
|
@ -9,7 +9,6 @@ Requires the following python packages:
|
||||||
Parameters:
|
Parameters:
|
||||||
* stock.symbols : Comma-separated list of symbols to fetch
|
* stock.symbols : Comma-separated list of symbols to fetch
|
||||||
* stock.change : Should we fetch change in stock value (defaults to True)
|
* stock.change : Should we fetch change in stock value (defaults to True)
|
||||||
* stock.currencies : List of symbols to go with the values (default $)
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import bumblebee.input
|
import bumblebee.input
|
||||||
|
@ -17,6 +16,7 @@ import bumblebee.output
|
||||||
import bumblebee.engine
|
import bumblebee.engine
|
||||||
import bumblebee.util
|
import bumblebee.util
|
||||||
|
|
||||||
|
import json
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
@ -28,36 +28,27 @@ class Module(bumblebee.engine.Module):
|
||||||
)
|
)
|
||||||
self._symbols = self.parameter('symbols', '')
|
self._symbols = self.parameter('symbols', '')
|
||||||
self._change = bumblebee.util.asbool(self.parameter('change', True))
|
self._change = bumblebee.util.asbool(self.parameter('change', True))
|
||||||
self._currencies = self.parameter('currencies', None)
|
self._value = None
|
||||||
self._baseurl = 'http://download.finance.yahoo.com/d/quotes.csv'
|
|
||||||
self._value = self.fetch()
|
|
||||||
self.interval(60)
|
self.interval(60)
|
||||||
|
|
||||||
if not self._currencies:
|
|
||||||
self._currencies = '$' * len(self._symbols)
|
|
||||||
|
|
||||||
# The currencies could be unicode, like the € symbol. Convert to a unicode object.
|
|
||||||
if hasattr(self._currencies, 'decode'):
|
|
||||||
self._currencies = self._currencies.decode('utf-8', 'ignore')
|
|
||||||
|
|
||||||
def value(self, widget):
|
def value(self, widget):
|
||||||
results = []
|
results = []
|
||||||
if not self._value:
|
if not self._value:
|
||||||
return 'n/a'
|
return 'n/a'
|
||||||
for i, val in enumerate(self._value.split('\n')):
|
data = json.loads(self._value)
|
||||||
try:
|
|
||||||
currency_symbol = self._currencies[i]
|
for symbol in data['quoteResponse']['result']:
|
||||||
except:
|
valkey = 'regularMarketChange' if self._change else 'regularMarketPrice'
|
||||||
currency_symbol = '$'
|
sym = 'n/a' if not 'symbol' in symbol else symbol['symbol']
|
||||||
results.append('%s%s' % (currency_symbol, val))
|
currency = 'USD' if not 'currency' in symbol else symbol['currency']
|
||||||
|
val = 'n/a' if not valkey in symbol else '{:.2f}'.format(symbol[valkey])
|
||||||
|
results.append('{} {} {}'.format(sym, val, currency))
|
||||||
return u' '.join(results)
|
return u' '.join(results)
|
||||||
|
|
||||||
def fetch(self):
|
def fetch(self):
|
||||||
if self._symbols:
|
if self._symbols:
|
||||||
url = self._baseurl
|
url = 'https://query1.finance.yahoo.com/v7/finance/quote?symbols='
|
||||||
url += '?s=%s&f=l1' % self._symbols
|
url += self._symbols + '&fields=regularMarketPrice,currency,regularMarketChange'
|
||||||
if self._change:
|
|
||||||
url += 'c1'
|
|
||||||
return requests.get(url).text.strip()
|
return requests.get(url).text.strip()
|
||||||
else:
|
else:
|
||||||
logging.error('unable to retrieve stock exchange rate')
|
logging.error('unable to retrieve stock exchange rate')
|
||||||
|
|
|
@ -7,15 +7,14 @@ import json
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import bumblebee.store
|
import bumblebee.store
|
||||||
|
import bumblebee.util
|
||||||
_TrueValues = ["true", "t", "yes", "y", "1"]
|
|
||||||
|
|
||||||
def scrollable(func):
|
def scrollable(func):
|
||||||
def wrapper(module, widget):
|
def wrapper(module, widget):
|
||||||
text = func(module, widget)
|
text = func(module, widget)
|
||||||
if not text: return text
|
if not text: return text
|
||||||
width = widget.get("theme.width", module.parameter("width", 30))
|
width = widget.get("theme.width", module.parameter("width", 30))
|
||||||
if module.parameter("scrolling.makewide", "true").lower() in _TrueValues:
|
if bumblebee.util.asbool(module.parameter("scrolling.makewide", "true")):
|
||||||
widget.set("theme.minwidth", "A"*width)
|
widget.set("theme.minwidth", "A"*width)
|
||||||
if len(text) <= width:
|
if len(text) <= width:
|
||||||
return text
|
return text
|
||||||
|
|
|
@ -69,5 +69,15 @@ class TestUtil(unittest.TestCase):
|
||||||
# test if which also works with garbage input
|
# test if which also works with garbage input
|
||||||
self.assertTrue(bu.which("qwertygarbage") is None)
|
self.assertTrue(bu.which("qwertygarbage") is None)
|
||||||
|
|
||||||
|
def test_asbool(self):
|
||||||
|
for val in ("t", "true", "y", "yes", "on", "1", 1, True):
|
||||||
|
self.assertTrue(bu.asbool(val))
|
||||||
|
if isinstance(val, str):
|
||||||
|
self.assertTrue(bu.asbool(val.upper()))
|
||||||
|
|
||||||
|
for val in ("f", "false", "n", "no", "off", "0", 0, False):
|
||||||
|
self.assertFalse(bu.asbool(val))
|
||||||
|
if isinstance(val, str):
|
||||||
|
self.assertFalse(bu.asbool(val.upper()))
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -247,6 +247,9 @@
|
||||||
"github": {
|
"github": {
|
||||||
"prefix": "github"
|
"prefix": "github"
|
||||||
},
|
},
|
||||||
|
"deezer": {
|
||||||
|
"prefix": ""
|
||||||
|
},
|
||||||
"spotify": {
|
"spotify": {
|
||||||
"prefix": ""
|
"prefix": ""
|
||||||
},
|
},
|
||||||
|
|
|
@ -172,6 +172,9 @@
|
||||||
"github": {
|
"github": {
|
||||||
"prefix": " "
|
"prefix": " "
|
||||||
},
|
},
|
||||||
|
"deezer": {
|
||||||
|
"prefix": " "
|
||||||
|
},
|
||||||
"spotify": {
|
"spotify": {
|
||||||
"prefix": " "
|
"prefix": " "
|
||||||
},
|
},
|
||||||
|
|
|
@ -153,6 +153,9 @@
|
||||||
"github": {
|
"github": {
|
||||||
"prefix": "\uf233"
|
"prefix": "\uf233"
|
||||||
},
|
},
|
||||||
|
"deezer": {
|
||||||
|
"prefix": "\uf305"
|
||||||
|
},
|
||||||
"spotify": {
|
"spotify": {
|
||||||
"prefix": "\uf305"
|
"prefix": "\uf305"
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue