Merge https://github.com/enkore/i3pystatus into pulseaudio
Conflicts: i3pystatus/pulseaudio/__init__.py
This commit is contained in:
commit
c554244157
1189
README.rst
1189
README.rst
File diff suppressed because it is too large
Load Diff
394
README.tpl.rst
394
README.tpl.rst
@ -1,394 +0,0 @@
|
|||||||
.. Always edit README.tpl.rst. Do not change the module reference manually.
|
|
||||||
|
|
||||||
i3pystatus
|
|
||||||
==========
|
|
||||||
|
|
||||||
.. image:: https://travis-ci.org/enkore/i3pystatus.svg?branch=master
|
|
||||||
:target: https://travis-ci.org/enkore/i3pystatus
|
|
||||||
|
|
||||||
i3pystatus is a (hopefully growing) collection of python scripts for
|
|
||||||
status output compatible to i3status / i3bar of the i3 window manager.
|
|
||||||
|
|
||||||
- `Release Notes`_
|
|
||||||
- `Configuration`_
|
|
||||||
- `Modules`_
|
|
||||||
- `Contribute`_
|
|
||||||
|
|
||||||
Installation
|
|
||||||
------------
|
|
||||||
|
|
||||||
.. admonition:: Note
|
|
||||||
|
|
||||||
i3pystatus requires Python 3.2 or newer and is not compatible with
|
|
||||||
Python 2.x. Some modules require additional dependencies
|
|
||||||
documented below (see `Modules`_).
|
|
||||||
|
|
||||||
From PyPI package `i3pystatus <https://pypi.python.org/pypi/i3pystatus>`_
|
|
||||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
pip install i3pystatus
|
|
||||||
|
|
||||||
Packages for your OS
|
|
||||||
++++++++++++++++++++
|
|
||||||
|
|
||||||
* `Arch Linux <https://aur.archlinux.org/packages/i3pystatus-git/>`_
|
|
||||||
|
|
||||||
Release Notes
|
|
||||||
-------------
|
|
||||||
|
|
||||||
Contributors
|
|
||||||
++++++++++++
|
|
||||||
|
|
||||||
* aaron-lebo
|
|
||||||
* afics
|
|
||||||
* al45tair
|
|
||||||
* Argish42
|
|
||||||
* Arvedui
|
|
||||||
* atalax
|
|
||||||
* bparmentier
|
|
||||||
* cganas
|
|
||||||
* crwood
|
|
||||||
* dubwoc
|
|
||||||
* enkore (current maintainer)
|
|
||||||
* gwarf
|
|
||||||
* janoliver (former maintainer)
|
|
||||||
* jasonmhite
|
|
||||||
* jedrz
|
|
||||||
* jorio
|
|
||||||
* kageurufu
|
|
||||||
* mekanix
|
|
||||||
* Mic92
|
|
||||||
* micha-a-schmidt
|
|
||||||
* naglis
|
|
||||||
* philipdexter
|
|
||||||
* sbrunner
|
|
||||||
* siikamiika
|
|
||||||
* simon04
|
|
||||||
* talwrii
|
|
||||||
* teto
|
|
||||||
* tomkenmag
|
|
||||||
* tomxtobin
|
|
||||||
* tony
|
|
||||||
* xals
|
|
||||||
* yemu
|
|
||||||
* zzatkin
|
|
||||||
|
|
||||||
next
|
|
||||||
++++
|
|
||||||
|
|
||||||
* Added `uptime`_ module
|
|
||||||
* `cpu\_usage`_: Add multicore support
|
|
||||||
* `cpu\_usage\_bar`_: Add multicore support
|
|
||||||
* `network`_: Add unknown_up setting
|
|
||||||
* `parcel`_: Document lxml dependency
|
|
||||||
* Added `network\_traffic`_ module
|
|
||||||
* `mpd`_: Play song on left click even if stopped
|
|
||||||
* Fixed issues with internet-related modules
|
|
||||||
* `battery`_: Added no_text_full option
|
|
||||||
* Unexpected exceptions are now displayed in the status bar
|
|
||||||
* `mail`_: db_path option made optional
|
|
||||||
* Core: added mouse wheel handling for upcoming i3 version
|
|
||||||
* `alsa`_: mouse wheel changes volume
|
|
||||||
* `pulseaudio`_: Added color_muted and color_unmuted options
|
|
||||||
|
|
||||||
3.30
|
|
||||||
++++
|
|
||||||
|
|
||||||
* Added `bitcoin`_ module
|
|
||||||
* Added `now\_playing`_ module
|
|
||||||
* Added `reddit`_ module
|
|
||||||
* Added `shell`_ module
|
|
||||||
* Core: fixed custom statusline colors not working properly (see issue #74)
|
|
||||||
* `alsa`_ and `pulseaudio`_: added optional "formated_muted"
|
|
||||||
audio is muted.
|
|
||||||
* `battery`_: add bar formatter, add not_present_text, full_color,
|
|
||||||
charging_color, not_present_color settings
|
|
||||||
* `disk`_: add color and round_size options
|
|
||||||
* maildir: use os.listdir instead of ls
|
|
||||||
* `mem`_: add round_size option
|
|
||||||
* `mpd`_: add color setting
|
|
||||||
* `mpd`_: add filename formatter
|
|
||||||
* `mpd`_: next song on right click
|
|
||||||
* `network`_ and `wireless`_: support interfaces enslaved to a bonding master
|
|
||||||
* `network`_: detached_down is now True by default
|
|
||||||
* `network`_: fixed some issues with interface up/down detection
|
|
||||||
* `parcel`_: added support for Itella (Finnish national postal service)
|
|
||||||
setting. If provided, it will be used instead of "format" when the
|
|
||||||
* `temp`_: add file setting
|
|
||||||
* `temp`_: fixed issue with Linux kernels 3.15 and newer
|
|
||||||
* `temp`_: removed color_critical and high_factor options
|
|
||||||
* `text`_: add cmd_leftclick and cmd_rightclick options
|
|
||||||
* `weather`_: add colorize option
|
|
||||||
* `wireless`_: Add quality_bar formatter
|
|
||||||
|
|
||||||
3.29
|
|
||||||
++++
|
|
||||||
|
|
||||||
* `network`_: prefer non link-local v6 addresses
|
|
||||||
* `mail`_: Open email client and refresh email with mouse click
|
|
||||||
* `disk`_: Add display and critical limit
|
|
||||||
* `battery`_: fix errors if CURRENT_NOW is not present
|
|
||||||
* `battery`_: add configurable colors
|
|
||||||
* `load`_: add configurable colors and limit
|
|
||||||
* `parcel`_: rewrote DHL tracker
|
|
||||||
* Add `spotify`_ module
|
|
||||||
|
|
||||||
3.28
|
|
||||||
++++
|
|
||||||
|
|
||||||
* **If you're currently using the i3pystatus command to run your i3bar**:
|
|
||||||
Replace ``i3pystatus`` command in your i3 configuration with ``python ~/path/to/your/config.py``
|
|
||||||
* Do not name your script i3pystatus.py or it will break imports.
|
|
||||||
* New options for `mem`_
|
|
||||||
* Added `cpu\_usage`_
|
|
||||||
* Improved error handling
|
|
||||||
* Removed ``i3pystatus`` binary
|
|
||||||
* pulseaudio: changed context name to "i3pystatus_pulseaudio"
|
|
||||||
* Add maildir backend for mails
|
|
||||||
* Code changes
|
|
||||||
* Removed DHL tracker of parcel module, because it doesn't work anymore.
|
|
||||||
|
|
||||||
3.27
|
|
||||||
++++
|
|
||||||
|
|
||||||
* Add weather module
|
|
||||||
* Add text module
|
|
||||||
* PulseAudio module: Add muted/unmuted options
|
|
||||||
|
|
||||||
3.26
|
|
||||||
++++
|
|
||||||
|
|
||||||
* Add mem module
|
|
||||||
|
|
||||||
3.24
|
|
||||||
++++
|
|
||||||
|
|
||||||
**This release introduced changes that may require manual changes to your
|
|
||||||
configuration file**
|
|
||||||
|
|
||||||
* Introduced TimeWrapper
|
|
||||||
* battery module: removed remaining\_* formatters in favor of
|
|
||||||
TimeWrapper, as it can not only reproduce all the variants removed,
|
|
||||||
but can do much more.
|
|
||||||
* mpd: Uses TimeWrapper for song_length, song_elapsed
|
|
||||||
|
|
||||||
Configuration
|
|
||||||
-------------
|
|
||||||
|
|
||||||
The config file is just a normal Python script.
|
|
||||||
|
|
||||||
A simple configuration file could look like this (note the additional
|
|
||||||
dependencies from `network`_, `wireless`_ and `pulseaudio`_ in this
|
|
||||||
example):
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
from i3pystatus import Status
|
|
||||||
|
|
||||||
status = Status(standalone=True)
|
|
||||||
|
|
||||||
# Displays clock like this:
|
|
||||||
# Tue 30 Jul 11:59:46 PM KW31
|
|
||||||
# ^-- calendar week
|
|
||||||
status.register("clock",
|
|
||||||
format="%a %-d %b %X KW%V",)
|
|
||||||
|
|
||||||
# Shows the average load of the last minute and the last 5 minutes
|
|
||||||
# (the default value for format is used)
|
|
||||||
status.register("load")
|
|
||||||
|
|
||||||
# Shows your CPU temperature, if you have a Intel CPU
|
|
||||||
status.register("temp",
|
|
||||||
format="{temp:.0f}°C",)
|
|
||||||
|
|
||||||
# The battery monitor has many formatting options, see README for details
|
|
||||||
|
|
||||||
# This would look like this, when discharging (or charging)
|
|
||||||
# ↓14.22W 56.15% [77.81%] 2h:41m
|
|
||||||
# And like this if full:
|
|
||||||
# =14.22W 100.0% [91.21%]
|
|
||||||
#
|
|
||||||
# This would also display a desktop notification (via dbus) if the percentage
|
|
||||||
# goes below 5 percent while discharging. The block will also color RED.
|
|
||||||
status.register("battery",
|
|
||||||
format="{status}/{consumption:.2f}W {percentage:.2f}% [{percentage_design:.2f}%] {remaining:%E%hh:%Mm}",
|
|
||||||
alert=True,
|
|
||||||
alert_percentage=5,
|
|
||||||
status={
|
|
||||||
"DIS": "↓",
|
|
||||||
"CHR": "↑",
|
|
||||||
"FULL": "=",
|
|
||||||
},)
|
|
||||||
|
|
||||||
# This would look like this:
|
|
||||||
# Discharging 6h:51m
|
|
||||||
status.register("battery",
|
|
||||||
format="{status} {remaining:%E%hh:%Mm}",
|
|
||||||
alert=True,
|
|
||||||
alert_percentage=5,
|
|
||||||
status={
|
|
||||||
"DIS": "Discharging",
|
|
||||||
"CHR": "Charging",
|
|
||||||
"FULL": "Bat full",
|
|
||||||
},)
|
|
||||||
|
|
||||||
# Displays whether a DHCP client is running
|
|
||||||
status.register("runwatch",
|
|
||||||
name="DHCP",
|
|
||||||
path="/var/run/dhclient*.pid",)
|
|
||||||
|
|
||||||
# Shows the address and up/down state of eth0. If it is up the address is shown in
|
|
||||||
# green (the default value of color_up) and the CIDR-address is shown
|
|
||||||
# (i.e. 10.10.10.42/24).
|
|
||||||
# If it's down just the interface name (eth0) will be displayed in red
|
|
||||||
# (defaults of format_down and color_down)
|
|
||||||
#
|
|
||||||
# Note: the network module requires PyPI package netifaces
|
|
||||||
status.register("network",
|
|
||||||
interface="eth0",
|
|
||||||
format_up="{v4cidr}",)
|
|
||||||
|
|
||||||
# Has all the options of the normal network and adds some wireless specific things
|
|
||||||
# like quality and network names.
|
|
||||||
#
|
|
||||||
# Note: requires both netifaces and basiciw
|
|
||||||
status.register("wireless",
|
|
||||||
interface="wlan0",
|
|
||||||
format_up="{essid} {quality:03.0f}%",)
|
|
||||||
|
|
||||||
# Shows disk usage of /
|
|
||||||
# Format:
|
|
||||||
# 42/128G [86G]
|
|
||||||
status.register("disk",
|
|
||||||
path="/",
|
|
||||||
format="{used}/{total}G [{avail}G]",)
|
|
||||||
|
|
||||||
# Shows pulseaudio default sink volume
|
|
||||||
#
|
|
||||||
# Note: requires libpulseaudio from PyPI
|
|
||||||
status.register("pulseaudio",
|
|
||||||
format="♪{volume}",)
|
|
||||||
|
|
||||||
# Shows mpd status
|
|
||||||
# Format:
|
|
||||||
# Cloud connected▶Reroute to Remain
|
|
||||||
status.register("mpd",
|
|
||||||
format="{title}{status}{album}",
|
|
||||||
status={
|
|
||||||
"pause": "▷",
|
|
||||||
"play": "▶",
|
|
||||||
"stop": "◾",
|
|
||||||
},)
|
|
||||||
|
|
||||||
status.run()
|
|
||||||
|
|
||||||
Also change your i3wm config to the following:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
# i3bar
|
|
||||||
bar {
|
|
||||||
status_command python ~/.path/to/your/config/file.py
|
|
||||||
position top
|
|
||||||
workspace_buttons yes
|
|
||||||
}
|
|
||||||
|
|
||||||
Formatting
|
|
||||||
++++++++++
|
|
||||||
|
|
||||||
All modules let you specifiy the exact output formatting using a
|
|
||||||
`format string <http://docs.python.org/3/library/string.html#formatstrings>`_, which
|
|
||||||
gives you a great deal of flexibility.
|
|
||||||
|
|
||||||
If a module gives you a float, it probably has a ton of
|
|
||||||
uninteresting decimal places. Use ``{somefloat:.0f}`` to get the integer
|
|
||||||
value, ``{somefloat:0.2f}`` gives you two decimal places after the
|
|
||||||
decimal dot
|
|
||||||
|
|
||||||
formatp
|
|
||||||
~~~~~~~
|
|
||||||
|
|
||||||
Some modules use an extended format string syntax (the mpd module, for example).
|
|
||||||
Given the format string below the output adapts itself to the available data.
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
[{artist}/{album}/]{title}{status}
|
|
||||||
|
|
||||||
Only if both the artist and album is known they're displayed. If only one or none
|
|
||||||
of them is known the entire group between the brackets is excluded.
|
|
||||||
|
|
||||||
"is known" is here defined as "value evaluating to True in Python", i.e. an empty
|
|
||||||
string or 0 (or 0.0) counts as "not known".
|
|
||||||
|
|
||||||
Inside a group always all format specifiers must evaluate to true (logical and).
|
|
||||||
|
|
||||||
You can nest groups. The inner group will only become part of the output if both
|
|
||||||
the outer group and the inner group are eligible for output.
|
|
||||||
|
|
||||||
TimeWrapper
|
|
||||||
~~~~~~~~~~~
|
|
||||||
|
|
||||||
Some modules that output times use TimeWrapper to format these. TimeWrapper is
|
|
||||||
a mere extension of the standard formatting method.
|
|
||||||
|
|
||||||
The time format that should be used is specified using the format specifier, i.e.
|
|
||||||
with some_time being 3951 seconds a format string like ``{some_time:%h:%m:%s}``
|
|
||||||
would produce ``1:5:51``.
|
|
||||||
|
|
||||||
* ``%h``, ``%m`` and ``%s`` are the hours, minutes and seconds without
|
|
||||||
leading zeros (i.e. 0 to 59 for minutes and seconds)
|
|
||||||
* ``%H``, ``%M`` and ``%S`` are padded with a leading zero to two digits,
|
|
||||||
i.e. 00 to 59
|
|
||||||
* ``%l`` and ``%L`` produce hours non-padded and padded but only if hours
|
|
||||||
is not zero. If the hours are zero it produces an empty string.
|
|
||||||
* ``%%`` produces a literal %
|
|
||||||
* ``%E`` (only valid on beginning of the string) if the time is null,
|
|
||||||
don't format anything but rather produce an empty string. If the
|
|
||||||
time is non-null it is removed from the string.
|
|
||||||
* When the module in question also uses formatp, 0 seconds counts as
|
|
||||||
"not known".
|
|
||||||
* The formatted time is stripped, i.e. spaces on both ends of the
|
|
||||||
result are removed.
|
|
||||||
|
|
||||||
Modules
|
|
||||||
-------
|
|
||||||
|
|
||||||
:System: `clock`_ - `disk`_ - `load`_ - `mem`_ - `cpu\_usage`_
|
|
||||||
:Audio: `alsa`_ - `pulseaudio`_
|
|
||||||
:Hardware: `battery`_ - `backlight`_ - `temp`_
|
|
||||||
:Network: `network`_ - `wireless`_
|
|
||||||
:Music: `now\_playing`_ - `mpd`_
|
|
||||||
:Websites & stuff: `weather`_ - `bitcoin`_ - `reddit`_ - `parcel`_
|
|
||||||
:Other: `mail`_ - `pyload`_ - `text`_
|
|
||||||
:Advanced: `file`_ - `regex`_ - `runwatch`_ - `shell`_
|
|
||||||
|
|
||||||
!!module_doc!!
|
|
||||||
|
|
||||||
Contribute
|
|
||||||
----------
|
|
||||||
|
|
||||||
To contribute a module, make sure it uses one of the Module classes. Most modules
|
|
||||||
use IntervalModule, which just calls a function repeatedly in a specified interval.
|
|
||||||
|
|
||||||
The output attribute should be set to a dictionary which represents your modules output,
|
|
||||||
the protocol is documented `here <http://i3wm.org/docs/i3bar-protocol.html>`_.
|
|
||||||
|
|
||||||
To update this readme run ``python -m i3pystatus.mkdocs`` in the
|
|
||||||
repository root and you're done :)
|
|
||||||
|
|
||||||
Developer documentation is available in the source code and `here
|
|
||||||
<http://i3pystatus.readthedocs.org/en/latest/>`_.
|
|
||||||
|
|
||||||
**Patches and pull requests are very welcome :-)**
|
|
||||||
|
|
||||||
Table of contents
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
.. contents:: Overview of this rather long README
|
|
27
docs/conf.py
27
docs/conf.py
@ -14,10 +14,25 @@
|
|||||||
|
|
||||||
import sys, os
|
import sys, os
|
||||||
|
|
||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
|
||||||
# add these directories to sys.path here. If the directory is relative to the
|
|
||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
|
||||||
sys.path.insert(0, os.path.abspath('.'))
|
sys.path.insert(0, os.path.abspath('.'))
|
||||||
|
sys.path.insert(0, os.path.abspath('..'))
|
||||||
|
|
||||||
|
# requires PyPI mock
|
||||||
|
import mock
|
||||||
|
|
||||||
|
MOCK_MODULES = [
|
||||||
|
"alsaaudio",
|
||||||
|
"netifaces", "psutil",
|
||||||
|
"lxml.html", "lxml.cssselect", "lxml",
|
||||||
|
"praw",
|
||||||
|
"gi.repository", "dbus.mainloop.glib", "dbus",
|
||||||
|
"pywapi", "basiciw",
|
||||||
|
"i3pystatus.pulseaudio.pulse",
|
||||||
|
"notmuch"
|
||||||
|
]
|
||||||
|
|
||||||
|
for mod_name in MOCK_MODULES:
|
||||||
|
sys.modules[mod_name] = mock.Mock()
|
||||||
|
|
||||||
# -- General configuration -----------------------------------------------------
|
# -- General configuration -----------------------------------------------------
|
||||||
|
|
||||||
@ -26,7 +41,11 @@ sys.path.insert(0, os.path.abspath('.'))
|
|||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||||
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']
|
extensions = [
|
||||||
|
'sphinx.ext.autodoc',
|
||||||
|
'sphinx.ext.viewcode',
|
||||||
|
'module_docs',
|
||||||
|
]
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['_templates']
|
templates_path = ['_templates']
|
||||||
|
124
docs/configuration.rst
Normal file
124
docs/configuration.rst
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
Configuration
|
||||||
|
=============
|
||||||
|
|
||||||
|
The config file is just a normal Python script.
|
||||||
|
|
||||||
|
A simple configuration file could look like this (note the additional
|
||||||
|
dependencies from :py:mod:`.network`, :py:mod:`.wireless` and :py:mod:`.pulseaudio` in this
|
||||||
|
example):
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
from i3pystatus import Status
|
||||||
|
|
||||||
|
status = Status(standalone=True)
|
||||||
|
|
||||||
|
# Displays clock like this:
|
||||||
|
# Tue 30 Jul 11:59:46 PM KW31
|
||||||
|
# ^-- calendar week
|
||||||
|
status.register("clock",
|
||||||
|
format="%a %-d %b %X KW%V",)
|
||||||
|
|
||||||
|
# Shows the average load of the last minute and the last 5 minutes
|
||||||
|
# (the default value for format is used)
|
||||||
|
status.register("load")
|
||||||
|
|
||||||
|
# Shows your CPU temperature, if you have a Intel CPU
|
||||||
|
status.register("temp",
|
||||||
|
format="{temp:.0f}°C",)
|
||||||
|
|
||||||
|
# The battery monitor has many formatting options, see README for details
|
||||||
|
|
||||||
|
# This would look like this, when discharging (or charging)
|
||||||
|
# ↓14.22W 56.15% [77.81%] 2h:41m
|
||||||
|
# And like this if full:
|
||||||
|
# =14.22W 100.0% [91.21%]
|
||||||
|
#
|
||||||
|
# This would also display a desktop notification (via dbus) if the percentage
|
||||||
|
# goes below 5 percent while discharging. The block will also color RED.
|
||||||
|
status.register("battery",
|
||||||
|
format="{status}/{consumption:.2f}W {percentage:.2f}% [{percentage_design:.2f}%] {remaining:%E%hh:%Mm}",
|
||||||
|
alert=True,
|
||||||
|
alert_percentage=5,
|
||||||
|
status={
|
||||||
|
"DIS": "↓",
|
||||||
|
"CHR": "↑",
|
||||||
|
"FULL": "=",
|
||||||
|
},)
|
||||||
|
|
||||||
|
# This would look like this:
|
||||||
|
# Discharging 6h:51m
|
||||||
|
status.register("battery",
|
||||||
|
format="{status} {remaining:%E%hh:%Mm}",
|
||||||
|
alert=True,
|
||||||
|
alert_percentage=5,
|
||||||
|
status={
|
||||||
|
"DIS": "Discharging",
|
||||||
|
"CHR": "Charging",
|
||||||
|
"FULL": "Bat full",
|
||||||
|
},)
|
||||||
|
|
||||||
|
# Displays whether a DHCP client is running
|
||||||
|
status.register("runwatch",
|
||||||
|
name="DHCP",
|
||||||
|
path="/var/run/dhclient*.pid",)
|
||||||
|
|
||||||
|
# Shows the address and up/down state of eth0. If it is up the address is shown in
|
||||||
|
# green (the default value of color_up) and the CIDR-address is shown
|
||||||
|
# (i.e. 10.10.10.42/24).
|
||||||
|
# If it's down just the interface name (eth0) will be displayed in red
|
||||||
|
# (defaults of format_down and color_down)
|
||||||
|
#
|
||||||
|
# Note: the network module requires PyPI package netifaces
|
||||||
|
status.register("network",
|
||||||
|
interface="eth0",
|
||||||
|
format_up="{v4cidr}",)
|
||||||
|
|
||||||
|
# Has all the options of the normal network and adds some wireless specific things
|
||||||
|
# like quality and network names.
|
||||||
|
#
|
||||||
|
# Note: requires both netifaces and basiciw
|
||||||
|
status.register("wireless",
|
||||||
|
interface="wlan0",
|
||||||
|
format_up="{essid} {quality:03.0f}%",)
|
||||||
|
|
||||||
|
# Shows disk usage of /
|
||||||
|
# Format:
|
||||||
|
# 42/128G [86G]
|
||||||
|
status.register("disk",
|
||||||
|
path="/",
|
||||||
|
format="{used}/{total}G [{avail}G]",)
|
||||||
|
|
||||||
|
# Shows pulseaudio default sink volume
|
||||||
|
#
|
||||||
|
# Note: requires libpulseaudio from PyPI
|
||||||
|
status.register("pulseaudio",
|
||||||
|
format="♪{volume}",)
|
||||||
|
|
||||||
|
# Shows mpd status
|
||||||
|
# Format:
|
||||||
|
# Cloud connected▶Reroute to Remain
|
||||||
|
status.register("mpd",
|
||||||
|
format="{title}{status}{album}",
|
||||||
|
status={
|
||||||
|
"pause": "▷",
|
||||||
|
"play": "▶",
|
||||||
|
"stop": "◾",
|
||||||
|
},)
|
||||||
|
|
||||||
|
status.run()
|
||||||
|
|
||||||
|
Also change your i3wm config to the following:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
# i3bar
|
||||||
|
bar {
|
||||||
|
status_command python ~/.path/to/your/config/file.py
|
||||||
|
position top
|
||||||
|
workspace_buttons yes
|
||||||
|
}
|
62
docs/formatting.rst
Normal file
62
docs/formatting.rst
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
Formatting
|
||||||
|
==========
|
||||||
|
|
||||||
|
All modules let you specifiy the exact output formatting using a
|
||||||
|
`format string <http://docs.python.org/3/library/string.html#formatstrings>`_, which
|
||||||
|
gives you a great deal of flexibility.
|
||||||
|
|
||||||
|
If a module gives you a float, it probably has a ton of
|
||||||
|
uninteresting decimal places. Use ``{somefloat:.0f}`` to get the integer
|
||||||
|
value, ``{somefloat:0.2f}`` gives you two decimal places after the
|
||||||
|
decimal dot
|
||||||
|
|
||||||
|
.. _formatp:
|
||||||
|
|
||||||
|
formatp
|
||||||
|
-------
|
||||||
|
|
||||||
|
Some modules use an extended format string syntax (the mpd module, for example).
|
||||||
|
Given the format string below the output adapts itself to the available data.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[{artist}/{album}/]{title}{status}
|
||||||
|
|
||||||
|
Only if both the artist and album is known they're displayed. If only one or none
|
||||||
|
of them is known the entire group between the brackets is excluded.
|
||||||
|
|
||||||
|
"is known" is here defined as "value evaluating to True in Python", i.e. an empty
|
||||||
|
string or 0 (or 0.0) counts as "not known".
|
||||||
|
|
||||||
|
Inside a group always all format specifiers must evaluate to true (logical and).
|
||||||
|
|
||||||
|
You can nest groups. The inner group will only become part of the output if both
|
||||||
|
the outer group and the inner group are eligible for output.
|
||||||
|
|
||||||
|
|
||||||
|
.. _TimeWrapper:
|
||||||
|
|
||||||
|
TimeWrapper
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Some modules that output times use TimeWrapper to format these. TimeWrapper is
|
||||||
|
a mere extension of the standard formatting method.
|
||||||
|
|
||||||
|
The time format that should be used is specified using the format specifier, i.e.
|
||||||
|
with some_time being 3951 seconds a format string like ``{some_time:%h:%m:%s}``
|
||||||
|
would produce ``1:5:51``.
|
||||||
|
|
||||||
|
* ``%h``, ``%m`` and ``%s`` are the hours, minutes and seconds without
|
||||||
|
leading zeros (i.e. 0 to 59 for minutes and seconds)
|
||||||
|
* ``%H``, ``%M`` and ``%S`` are padded with a leading zero to two digits,
|
||||||
|
i.e. 00 to 59
|
||||||
|
* ``%l`` and ``%L`` produce hours non-padded and padded but only if hours
|
||||||
|
is not zero. If the hours are zero it produces an empty string.
|
||||||
|
* ``%%`` produces a literal %
|
||||||
|
* ``%E`` (only valid on beginning of the string) if the time is null,
|
||||||
|
don't format anything but rather produce an empty string. If the
|
||||||
|
time is non-null it is removed from the string.
|
||||||
|
* When the module in question also uses formatp, 0 seconds counts as
|
||||||
|
"not known".
|
||||||
|
* The formatted time is stripped, i.e. spaces on both ends of the
|
||||||
|
result are removed.
|
15
docs/i3pystatus.rst
Normal file
15
docs/i3pystatus.rst
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
Module reference
|
||||||
|
================
|
||||||
|
|
||||||
|
.. autogen:: i3pystatus Module
|
||||||
|
|
||||||
|
.. note:: List of all modules:
|
||||||
|
|
||||||
|
.. _mailbackends:
|
||||||
|
|
||||||
|
Mail Backends
|
||||||
|
-------------
|
||||||
|
|
||||||
|
.. autogen:: i3pystatus.mail SettingsBase
|
||||||
|
|
||||||
|
.. nothin'
|
@ -1,14 +1,17 @@
|
|||||||
|
|
||||||
Welcome to i3pystatus's documentation!
|
Welcome to the i3pystatus documentation!
|
||||||
======================================
|
========================================
|
||||||
|
|
||||||
Contents:
|
Contents:
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 4
|
:maxdepth: 4
|
||||||
|
|
||||||
module
|
configuration
|
||||||
|
formatting
|
||||||
|
i3pystatus
|
||||||
i3pystatus.core
|
i3pystatus.core
|
||||||
|
module
|
||||||
|
|
||||||
|
|
||||||
Indices and tables
|
Indices and tables
|
||||||
|
146
docs/module_docs.py
Normal file
146
docs/module_docs.py
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
|
||||||
|
import pkgutil
|
||||||
|
import importlib
|
||||||
|
|
||||||
|
import sphinx.application
|
||||||
|
from docutils.parsers.rst import Directive
|
||||||
|
from docutils.nodes import paragraph
|
||||||
|
from docutils.statemachine import StringList
|
||||||
|
|
||||||
|
import i3pystatus.core.settings
|
||||||
|
import i3pystatus.core.modules
|
||||||
|
from i3pystatus.core.imputil import ClassFinder
|
||||||
|
|
||||||
|
IGNORE_MODULES = ("__main__", "core")
|
||||||
|
|
||||||
|
|
||||||
|
def is_module(obj):
|
||||||
|
return isinstance(obj, type) \
|
||||||
|
and issubclass(obj, i3pystatus.core.settings.SettingsBase) \
|
||||||
|
and not obj.__module__.startswith("i3pystatus.core.")
|
||||||
|
|
||||||
|
|
||||||
|
def process_docstring(app, what, name, obj, options, lines):
|
||||||
|
class Setting:
|
||||||
|
doc = ""
|
||||||
|
required = False
|
||||||
|
default = sentinel = object()
|
||||||
|
empty = object()
|
||||||
|
|
||||||
|
def __init__(self, cls, setting):
|
||||||
|
if isinstance(setting, tuple):
|
||||||
|
self.name = setting[0]
|
||||||
|
self.doc = setting[1]
|
||||||
|
else:
|
||||||
|
self.name = setting
|
||||||
|
|
||||||
|
if setting in cls.required:
|
||||||
|
self.required = True
|
||||||
|
elif hasattr(cls, self.name):
|
||||||
|
default = getattr(cls, self.name)
|
||||||
|
if isinstance(default, str) and not len(default)\
|
||||||
|
or default is None:
|
||||||
|
default = self.empty
|
||||||
|
self.default = default
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
attrs = []
|
||||||
|
if self.required:
|
||||||
|
attrs.append("required")
|
||||||
|
if self.default not in [self.sentinel, self.empty]:
|
||||||
|
attrs.append("default: ``{default}``".format(default=self.default))
|
||||||
|
if self.default is self.empty:
|
||||||
|
attrs.append("default: *empty*")
|
||||||
|
|
||||||
|
formatted = "* **{name}** – {doc}".format(name=self.name, doc=self.doc)
|
||||||
|
if attrs:
|
||||||
|
formatted += " ({attrs})".format(attrs=", ".join(attrs))
|
||||||
|
|
||||||
|
return formatted
|
||||||
|
|
||||||
|
if is_module(obj) and obj.settings:
|
||||||
|
lines.append(".. rubric:: Settings")
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
|
for setting in obj.settings:
|
||||||
|
lines.append(str(Setting(obj, setting)))
|
||||||
|
|
||||||
|
|
||||||
|
def process_signature(app, what, name, obj, options, signature, return_annotation):
|
||||||
|
if is_module(obj):
|
||||||
|
return ("", return_annotation)
|
||||||
|
|
||||||
|
|
||||||
|
def get_modules(path):
|
||||||
|
modules = []
|
||||||
|
for finder, modname, is_package in pkgutil.iter_modules(path):
|
||||||
|
if modname not in IGNORE_MODULES:
|
||||||
|
modules.append(get_module(finder, modname))
|
||||||
|
return modules
|
||||||
|
|
||||||
|
|
||||||
|
def get_module(finder, modname):
|
||||||
|
fullname = "i3pystatus.{modname}".format(modname=modname)
|
||||||
|
return (modname, finder.find_loader(fullname)[0].load_module(fullname))
|
||||||
|
|
||||||
|
|
||||||
|
def get_all(module_path, basecls):
|
||||||
|
mods = []
|
||||||
|
|
||||||
|
finder = ClassFinder(basecls)
|
||||||
|
|
||||||
|
for name, module in get_modules(module_path):
|
||||||
|
classes = finder.get_matching_classes(module)
|
||||||
|
found = []
|
||||||
|
for cls in classes:
|
||||||
|
if cls.__name__ not in found:
|
||||||
|
found.append(cls.__name__)
|
||||||
|
mods.append((module.__name__, cls.__name__))
|
||||||
|
|
||||||
|
return sorted(mods, key=lambda module: module[0])
|
||||||
|
|
||||||
|
|
||||||
|
def generate_automodules(path, basecls):
|
||||||
|
modules = get_all(path, basecls)
|
||||||
|
|
||||||
|
contents = []
|
||||||
|
|
||||||
|
for mod in modules:
|
||||||
|
contents.append(" * :py:mod:`~{}`".format(mod[0]))
|
||||||
|
contents.append("")
|
||||||
|
|
||||||
|
for mod in modules:
|
||||||
|
contents.append(".. automodule:: {}".format(mod[0]))
|
||||||
|
contents.append(" :members: {}\n".format(mod[1]))
|
||||||
|
|
||||||
|
return contents
|
||||||
|
|
||||||
|
|
||||||
|
class AutogenDirective(Directive):
|
||||||
|
required_arguments = 2
|
||||||
|
has_content = True
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
# Raise an error if the directive does not have contents.
|
||||||
|
self.assert_has_content()
|
||||||
|
|
||||||
|
modname = self.arguments[0]
|
||||||
|
modpath = importlib.import_module(modname).__path__
|
||||||
|
basecls = getattr(i3pystatus.core.modules, self.arguments[1])
|
||||||
|
|
||||||
|
contents = []
|
||||||
|
for e in self.content:
|
||||||
|
contents.append(e)
|
||||||
|
contents.append("")
|
||||||
|
contents.extend(generate_automodules(modpath, basecls))
|
||||||
|
|
||||||
|
node = paragraph()
|
||||||
|
self.state.nested_parse(StringList(contents), 0, node)
|
||||||
|
return [node]
|
||||||
|
|
||||||
|
|
||||||
|
def setup(app: sphinx.application.Sphinx):
|
||||||
|
|
||||||
|
app.add_directive("autogen", AutogenDirective)
|
||||||
|
app.connect("autodoc-process-docstring", process_docstring)
|
||||||
|
app.connect("autodoc-process-signature", process_signature)
|
@ -9,7 +9,7 @@ class ALSA(IntervalModule):
|
|||||||
|
|
||||||
Requires pyalsaaudio
|
Requires pyalsaaudio
|
||||||
|
|
||||||
Available formatters:
|
.. rubric:: Available formatters
|
||||||
|
|
||||||
* `{volume}` — the current volume in percent
|
* `{volume}` — the current volume in percent
|
||||||
* `{muted}` — the value of one of the `muted` or `unmuted` settings
|
* `{muted}` — the value of one of the `muted` or `unmuted` settings
|
||||||
|
@ -5,7 +5,7 @@ class Backlight(File):
|
|||||||
"""
|
"""
|
||||||
Screen backlight info
|
Screen backlight info
|
||||||
|
|
||||||
Available formatters:
|
.. rubric:: Available formatters
|
||||||
|
|
||||||
* `{brightness}` — current brightness relative to max_brightness
|
* `{brightness}` — current brightness relative to max_brightness
|
||||||
* `{max_brightness}` — maximum brightness value
|
* `{max_brightness}` — maximum brightness value
|
||||||
|
@ -105,7 +105,7 @@ class BatteryChecker(IntervalModule):
|
|||||||
This class uses the /sys/class/power_supply/…/uevent interface to check for the
|
This class uses the /sys/class/power_supply/…/uevent interface to check for the
|
||||||
battery status
|
battery status
|
||||||
|
|
||||||
Available formatters:
|
.. rubric:: Available formatters
|
||||||
|
|
||||||
* `{remaining}` — remaining time for charging or discharging, uses TimeWrapper formatting, default format is `%E%h:%M`
|
* `{remaining}` — remaining time for charging or discharging, uses TimeWrapper formatting, default format is `%E%h:%M`
|
||||||
* `{percentage}` — battery percentage relative to the last full value
|
* `{percentage}` — battery percentage relative to the last full value
|
||||||
|
@ -15,7 +15,7 @@ class Bitcoin(IntervalModule):
|
|||||||
Index API <https://bitcoinaverage.com> while transaction data is pulled
|
Index API <https://bitcoinaverage.com> while transaction data is pulled
|
||||||
from blockchain.info <https://blockchain.info/api/blockchain_api>.
|
from blockchain.info <https://blockchain.info/api/blockchain_api>.
|
||||||
|
|
||||||
Available formatters:
|
.. rubric:: Available formatters
|
||||||
|
|
||||||
* {last_price}
|
* {last_price}
|
||||||
* {ask_price}
|
* {ask_price}
|
||||||
|
@ -18,7 +18,7 @@ class CpuUsage(IntervalModule):
|
|||||||
|
|
||||||
Linux only
|
Linux only
|
||||||
|
|
||||||
Available formatters:
|
.. rubric:: Available formatters
|
||||||
|
|
||||||
* {usage} usage average of all cores
|
* {usage} usage average of all cores
|
||||||
* {usage_cpu*} usage of one specific core. replace "*" by core number starting at 0
|
* {usage_cpu*} usage of one specific core. replace "*" by core number starting at 0
|
||||||
|
@ -13,12 +13,10 @@ class CpuUsageBar(CpuUsage, ColorRangeModule):
|
|||||||
|
|
||||||
Requires the PyPI package `colour`.
|
Requires the PyPI package `colour`.
|
||||||
|
|
||||||
Available formatters:
|
.. rubric:: Available formatters
|
||||||
|
|
||||||
* {usage_bar} usage average of all cores
|
* {usage_bar} usage average of all cores
|
||||||
* {usage_bar_cpu*} usage of one specific core. replace "*"
|
* {usage_bar_cpuN} usage of one specific core. replace "N" by core number starting at 0
|
||||||
by core number starting at 0
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
format = "{usage_bar}"
|
format = "{usage_bar}"
|
||||||
|
@ -12,7 +12,7 @@ class CpuUsageGraph(CpuUsage, ColorRangeModule):
|
|||||||
|
|
||||||
Linux only
|
Linux only
|
||||||
|
|
||||||
Available formatters:
|
.. rubric:: Available formatters
|
||||||
|
|
||||||
* {cpu_graph} graph of cpu usage.
|
* {cpu_graph} graph of cpu usage.
|
||||||
* {usage} usage average of all cores
|
* {usage} usage average of all cores
|
||||||
|
@ -17,7 +17,7 @@ class Mail(IntervalModule):
|
|||||||
"""
|
"""
|
||||||
Generic mail checker
|
Generic mail checker
|
||||||
|
|
||||||
The `backends` setting determines the backends to use.
|
The `backends` setting determines the backends to use. For available backends see :ref:`mailbackends`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_endstring = """!!i3pystatus.mail!!"""
|
_endstring = """!!i3pystatus.mail!!"""
|
||||||
|
@ -7,7 +7,7 @@ class Mem(IntervalModule):
|
|||||||
"""
|
"""
|
||||||
Shows memory load
|
Shows memory load
|
||||||
|
|
||||||
Available formatters:
|
.. rubric:: Available formatters
|
||||||
|
|
||||||
* {avail_mem}
|
* {avail_mem}
|
||||||
* {percent_used_mem}
|
* {percent_used_mem}
|
||||||
|
@ -8,7 +8,8 @@ class MemBar(IntervalModule, ColorRangeModule):
|
|||||||
"""
|
"""
|
||||||
Shows memory load as a bar.
|
Shows memory load as a bar.
|
||||||
|
|
||||||
Available formatters:
|
.. rubric:: Available formatters
|
||||||
|
|
||||||
* {used_mem_bar}
|
* {used_mem_bar}
|
||||||
|
|
||||||
Requires psutil and colour (from PyPI)
|
Requires psutil and colour (from PyPI)
|
||||||
|
@ -1,138 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
import pkgutil
|
|
||||||
import textwrap
|
|
||||||
|
|
||||||
import i3pystatus
|
|
||||||
import i3pystatus.mail
|
|
||||||
|
|
||||||
from .core.imputil import ClassFinder
|
|
||||||
|
|
||||||
IGNORE = ("__main__", "mkdocs", "core")
|
|
||||||
MODULE_FORMAT = """
|
|
||||||
{name}
|
|
||||||
{heading}
|
|
||||||
|
|
||||||
{doc}
|
|
||||||
|
|
||||||
Settings:
|
|
||||||
|
|
||||||
{settings}
|
|
||||||
|
|
||||||
{endstring}\n"""
|
|
||||||
|
|
||||||
|
|
||||||
class Module:
|
|
||||||
name = ""
|
|
||||||
doc = ""
|
|
||||||
endstring = ""
|
|
||||||
|
|
||||||
def __init__(self, cls, neighbours, module_name, module, heading):
|
|
||||||
self.settings = []
|
|
||||||
self.cls = cls
|
|
||||||
self.heading = heading
|
|
||||||
|
|
||||||
if neighbours == 1:
|
|
||||||
self.name = module_name
|
|
||||||
else:
|
|
||||||
self.name = "{module}.{cls}".format(
|
|
||||||
module=module_name, cls=self.cls.__name__)
|
|
||||||
|
|
||||||
self.doc = self.cls.__doc__ or module.__doc__ or ""
|
|
||||||
|
|
||||||
if hasattr(self.cls, "_endstring"):
|
|
||||||
self.endstring = self.cls._endstring
|
|
||||||
|
|
||||||
self.read_settings()
|
|
||||||
|
|
||||||
def read_settings(self):
|
|
||||||
for setting in self.cls.settings:
|
|
||||||
self.settings.append(Setting(self.cls, setting))
|
|
||||||
|
|
||||||
def format_settings(self):
|
|
||||||
return "\n".join(map(str, self.settings))
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return MODULE_FORMAT.format(
|
|
||||||
name=self.name,
|
|
||||||
doc=textwrap.dedent(self.doc),
|
|
||||||
settings=self.format_settings(),
|
|
||||||
heading=self.heading * len(self.name),
|
|
||||||
endstring=self.endstring
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Setting:
|
|
||||||
doc = ""
|
|
||||||
required = False
|
|
||||||
default = sentinel = object()
|
|
||||||
|
|
||||||
def __init__(self, cls, setting):
|
|
||||||
if isinstance(setting, tuple):
|
|
||||||
self.name = setting[0]
|
|
||||||
self.doc = setting[1]
|
|
||||||
else:
|
|
||||||
self.name = setting
|
|
||||||
|
|
||||||
if setting in cls.required:
|
|
||||||
self.required = True
|
|
||||||
elif hasattr(cls, self.name):
|
|
||||||
self.default = getattr(cls, self.name)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
attrs = []
|
|
||||||
if self.required:
|
|
||||||
attrs.append("required")
|
|
||||||
if self.default is not self.sentinel:
|
|
||||||
attrs.append("default: ``{default}``".format(default=self.default))
|
|
||||||
|
|
||||||
formatted = ":{name}: {doc}".format(name=self.name, doc=self.doc)
|
|
||||||
if attrs:
|
|
||||||
formatted += " ({attrs})".format(attrs=", ".join(attrs))
|
|
||||||
|
|
||||||
return formatted
|
|
||||||
|
|
||||||
|
|
||||||
def get_modules(path):
|
|
||||||
modules = []
|
|
||||||
for finder, modname, ispkg in pkgutil.iter_modules(path):
|
|
||||||
if modname not in IGNORE:
|
|
||||||
modules.append(get_module(finder, modname))
|
|
||||||
return modules
|
|
||||||
|
|
||||||
|
|
||||||
def get_module(finder, modname):
|
|
||||||
fullname = "i3pystatus.{modname}".format(modname=modname)
|
|
||||||
return (modname, finder.find_loader(fullname)[0].load_module(fullname))
|
|
||||||
|
|
||||||
|
|
||||||
def get_all(module_path, heading, finder=None, ignore=None):
|
|
||||||
mods = []
|
|
||||||
if not finder:
|
|
||||||
finder = ClassFinder(i3pystatus.Module)
|
|
||||||
|
|
||||||
for name, module in get_modules(module_path):
|
|
||||||
classes = finder.get_matching_classes(module)
|
|
||||||
found = []
|
|
||||||
for cls in classes:
|
|
||||||
if cls.__name__ not in found:
|
|
||||||
found.append(cls.__name__)
|
|
||||||
mods.append(
|
|
||||||
Module(cls, neighbours=len(classes), module_name=name, module=module, heading=heading))
|
|
||||||
|
|
||||||
return sorted(mods, key=lambda module: module.name)
|
|
||||||
|
|
||||||
|
|
||||||
def generate_doc_for_module(module_path, heading="+", finder=None, ignore=None):
|
|
||||||
return "".join(map(str, get_all(module_path, heading, finder, ignore or [])))
|
|
||||||
|
|
||||||
|
|
||||||
with open("README.tpl.rst", "r") as template:
|
|
||||||
tpl = template.read()
|
|
||||||
tpl = tpl.replace(
|
|
||||||
"!!module_doc!!", generate_doc_for_module(i3pystatus.__path__))
|
|
||||||
finder = ClassFinder(baseclass=i3pystatus.mail.Backend)
|
|
||||||
tpl = tpl.replace("!!i3pystatus.mail!!", generate_doc_for_module(
|
|
||||||
i3pystatus.mail.__path__, "~", finder, ["Backend"]))
|
|
||||||
with open("README.rst", "w") as output:
|
|
||||||
output.write(tpl + "\n")
|
|
@ -9,13 +9,13 @@ class MPD(IntervalModule):
|
|||||||
"""
|
"""
|
||||||
Displays various information from MPD (the music player daemon)
|
Displays various information from MPD (the music player daemon)
|
||||||
|
|
||||||
Available formatters (uses `formatp`_)
|
Available formatters (uses :ref:`formatp`)
|
||||||
|
|
||||||
* `{title}` — (the title of the current song)
|
* `{title}` — (the title of the current song)
|
||||||
* `{album}` — (the album of the current song, can be an empty string (e.g. for online streams))
|
* `{album}` — (the album of the current song, can be an empty string (e.g. for online streams))
|
||||||
* `{artist}` — (can be empty, too)
|
* `{artist}` — (can be empty, too)
|
||||||
* `{filename}` — (file name with out extension and path; empty unless title is empty)
|
* `{filename}` — (file name with out extension and path; empty unless title is empty)
|
||||||
* `{song_elapsed}` — (Position in the currently playing song, uses `TimeWrapper`_, default is `%m:%S`)
|
* `{song_elapsed}` — (Position in the currently playing song, uses :ref:`TimeWrapper`, default is `%m:%S`)
|
||||||
* `{song_length}` — (Length of the current song, same as song_elapsed)
|
* `{song_length}` — (Length of the current song, same as song_elapsed)
|
||||||
* `{pos}` — (Position of current song in playlist, one-based)
|
* `{pos}` — (Position of current song in playlist, one-based)
|
||||||
* `{len}` — (Songs in playlist)
|
* `{len}` — (Songs in playlist)
|
||||||
|
@ -74,7 +74,7 @@ class Network(IntervalModule):
|
|||||||
|
|
||||||
Requires the PyPI package `netifaces`.
|
Requires the PyPI package `netifaces`.
|
||||||
|
|
||||||
Available formatters:
|
.. rubric:: Available formatters
|
||||||
|
|
||||||
* `{interface}` — same as setting
|
* `{interface}` — same as setting
|
||||||
* `{name}` — same as setting
|
* `{name}` — same as setting
|
||||||
|
@ -12,10 +12,10 @@ class NetworkGraph(NetworkTraffic, ColorRangeModule):
|
|||||||
|
|
||||||
Requires the PyPI packages `psutil` and `colour`.
|
Requires the PyPI packages `psutil` and `colour`.
|
||||||
|
|
||||||
Available formatters:
|
.. rubric:: Available formatters
|
||||||
|
|
||||||
{kbs} Float representing kb\s
|
* {kbs} – Float representing kb\s
|
||||||
{network_graph} Unicode network graph
|
* {network_graph} – Unicode network graph
|
||||||
|
|
||||||
"""
|
"""
|
||||||
settings = (
|
settings = (
|
||||||
|
@ -8,7 +8,7 @@ class NetworkTraffic(IntervalModule):
|
|||||||
|
|
||||||
Requires the PyPI packages `psutil`.
|
Requires the PyPI packages `psutil`.
|
||||||
|
|
||||||
Available formatters:
|
.. rubric:: Available formatters
|
||||||
|
|
||||||
* `{interface}` — the configured network interface
|
* `{interface}` — the configured network interface
|
||||||
* `{bytes_sent}` — bytes sent per second (divided by divisor)
|
* `{bytes_sent}` — bytes sent per second (divided by divisor)
|
||||||
|
@ -12,13 +12,13 @@ class NowPlaying(IntervalModule):
|
|||||||
"""
|
"""
|
||||||
Shows currently playing track information, supports most media players
|
Shows currently playing track information, supports most media players
|
||||||
|
|
||||||
Available formatters (uses `formatp`_)
|
Available formatters (uses :ref:`formatp`)
|
||||||
|
|
||||||
* `{title}` — (the title of the current song)
|
* `{title}` — (the title of the current song)
|
||||||
* `{album}` — (the album of the current song, can be an empty string (e.g. for online streams))
|
* `{album}` — (the album of the current song, can be an empty string (e.g. for online streams))
|
||||||
* `{artist}` — (can be empty, too)
|
* `{artist}` — (can be empty, too)
|
||||||
* `{filename}` — (file name with out extension and path; empty unless title is empty)
|
* `{filename}` — (file name with out extension and path; empty unless title is empty)
|
||||||
* `{song_elapsed}` — (Position in the currently playing song, uses `TimeWrapper`_, default is `%m:%S`)
|
* `{song_elapsed}` — (Position in the currently playing song, uses :ref:`TimeWrapper`, default is `%m:%S`)
|
||||||
* `{song_length}` — (Length of the current song, same as song_elapsed)
|
* `{song_length}` — (Length of the current song, same as song_elapsed)
|
||||||
* `{status}` — (play, pause, stop mapped through the `status` dictionary)
|
* `{status}` — (play, pause, stop mapped through the `status` dictionary)
|
||||||
* `{volume}` — (Volume)
|
* `{volume}` — (Volume)
|
||||||
|
@ -12,7 +12,7 @@ class pyLoad(IntervalModule):
|
|||||||
"""
|
"""
|
||||||
Shows pyLoad status
|
Shows pyLoad status
|
||||||
|
|
||||||
Available formatters:
|
.. rubric:: Available formatters
|
||||||
|
|
||||||
* `{captcha}` (see captcha_true and captcha_false, which are the values filled in for this formatter)
|
* `{captcha}` (see captcha_true and captcha_false, which are the values filled in for this formatter)
|
||||||
* `{progress}` (average over all running downloads)
|
* `{progress}` (average over all running downloads)
|
||||||
|
@ -15,7 +15,7 @@ class Reddit(IntervalModule):
|
|||||||
submission directly. Depends on the Python Reddit API Wrapper (PRAW)
|
submission directly. Depends on the Python Reddit API Wrapper (PRAW)
|
||||||
<https://github.com/praw-dev/praw>.
|
<https://github.com/praw-dev/praw>.
|
||||||
|
|
||||||
Available formatters:
|
.. rubric:: Available formatters
|
||||||
|
|
||||||
* {submission_title}
|
* {submission_title}
|
||||||
* {submission_author}
|
* {submission_author}
|
||||||
|
@ -7,7 +7,7 @@ class Weather(IntervalModule):
|
|||||||
"""
|
"""
|
||||||
This module gets the weather from weather.com using pywapi module
|
This module gets the weather from weather.com using pywapi module
|
||||||
First, you need to get the code for the location from the www.weather.com
|
First, you need to get the code for the location from the www.weather.com
|
||||||
Available formatters:
|
.. rubric:: Available formatters
|
||||||
|
|
||||||
* {current_temp}
|
* {current_temp}
|
||||||
* {current_wind}
|
* {current_wind}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
pytest>=2.5
|
pytest>=2.5
|
||||||
sphinx>=1.2
|
sphinx>=1.2
|
||||||
colour>=0.0.5
|
colour>=0.0.5
|
||||||
|
mock>=1.0
|
||||||
|
Loading…
Reference in New Issue
Block a user