Merge branch 'master' of https://github.com/enkore/i3pystatus into yaourt
This commit is contained in:
commit
675ddd8d08
@ -24,6 +24,7 @@ gacekjk
|
|||||||
Georg Sieber
|
Georg Sieber
|
||||||
Goran Mekić
|
Goran Mekić
|
||||||
Gordon Schulz
|
Gordon Schulz
|
||||||
|
Holden Salomon
|
||||||
Hugo Osvaldo Barrera
|
Hugo Osvaldo Barrera
|
||||||
Iliyas Jorio
|
Iliyas Jorio
|
||||||
Ismael
|
Ismael
|
||||||
|
@ -47,7 +47,7 @@ Changelog
|
|||||||
Contributors
|
Contributors
|
||||||
------------
|
------------
|
||||||
|
|
||||||
A list of all contributors can be found in `CONTRIBUTORS <http://github.com/enkore/i3pystatus/CONTRIBUTORS>`_.
|
A list of all contributors can be found in `CONTRIBUTORS <https://github.com/enkore/i3pystatus/blob/master/CONTRIBUTORS>`_.
|
||||||
Particular noteworthy contributors are former maintainer Jan Oliver Oelerich and
|
Particular noteworthy contributors are former maintainer Jan Oliver Oelerich and
|
||||||
current maintainer enkore.
|
current maintainer enkore.
|
||||||
|
|
||||||
|
@ -28,12 +28,14 @@ class CpuUsage(IntervalModule):
|
|||||||
format_all = "{core}:{usage:02}%"
|
format_all = "{core}:{usage:02}%"
|
||||||
exclude_average = False
|
exclude_average = False
|
||||||
interval = 1
|
interval = 1
|
||||||
|
color = None
|
||||||
settings = (
|
settings = (
|
||||||
("format", "format string."),
|
("format", "format string."),
|
||||||
("format_all", ("format string used for {usage_all} per core. "
|
("format_all", ("format string used for {usage_all} per core. "
|
||||||
"Available formaters are {core} and {usage}. ")),
|
"Available formaters are {core} and {usage}. ")),
|
||||||
("exclude_average", ("If True usage average of all cores will "
|
("exclude_average", ("If True usage average of all cores will "
|
||||||
"not be in format_all."))
|
"not be in format_all.")),
|
||||||
|
("color", "HTML color code #RRGGBB")
|
||||||
)
|
)
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
@ -117,5 +119,6 @@ class CpuUsage(IntervalModule):
|
|||||||
usage['usage'] = usage['usage_cpu']
|
usage['usage'] = usage['usage_cpu']
|
||||||
|
|
||||||
self.output = {
|
self.output = {
|
||||||
"full_text": self.format.format_map(usage)
|
"full_text": self.format.format_map(usage),
|
||||||
|
"color": self.color
|
||||||
}
|
}
|
||||||
|
111
i3pystatus/moon.py
Normal file
111
i3pystatus/moon.py
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
from i3pystatus import IntervalModule, formatp
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import math
|
||||||
|
|
||||||
|
import decimal
|
||||||
|
import os
|
||||||
|
|
||||||
|
from i3pystatus.core.util import TimeWrapper
|
||||||
|
|
||||||
|
dec = decimal.Decimal
|
||||||
|
|
||||||
|
|
||||||
|
class MoonPhase(IntervalModule):
|
||||||
|
"""
|
||||||
|
Available Formatters
|
||||||
|
|
||||||
|
status: Allows for mapping of current moon phase
|
||||||
|
- New Moon:
|
||||||
|
- Waxing Crescent:
|
||||||
|
- First Quarter:
|
||||||
|
- Waxing Gibbous:
|
||||||
|
- Full Moon:
|
||||||
|
- Waning Gibbous:
|
||||||
|
- Last Quarter:
|
||||||
|
- Waning Crescent:
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
settings = (
|
||||||
|
"format",
|
||||||
|
("status", "Current moon phase"),
|
||||||
|
("illum", "Percentage that is illuminated"),
|
||||||
|
("color", "Set color"),
|
||||||
|
)
|
||||||
|
|
||||||
|
format = "{illum} {status}"
|
||||||
|
|
||||||
|
interval = 60 * 60 * 2 # every 2 hours
|
||||||
|
|
||||||
|
status = {
|
||||||
|
"New Moon": "NM",
|
||||||
|
"Waxing Crescent": "WaxCres",
|
||||||
|
"First Quarter": "FQ",
|
||||||
|
"Waxing Gibbous": "WaxGib",
|
||||||
|
"Full Moon": "FM",
|
||||||
|
"Waning Gibbous": "WanGib",
|
||||||
|
"Last Quarter": "LQ",
|
||||||
|
"Waning Cresent": "WanCres",
|
||||||
|
}
|
||||||
|
|
||||||
|
color = {
|
||||||
|
"New Moon": "#00BDE5",
|
||||||
|
"Waxing Crescent": "#138DD8",
|
||||||
|
"First Quarter": "#265ECC",
|
||||||
|
"Waxing Gibbous": "#392FBF",
|
||||||
|
"Full Moon": "#4C00B3",
|
||||||
|
"Waning Gibbous": "#871181",
|
||||||
|
"Last Quarter": "#C32250",
|
||||||
|
"Waning Crescent": "#FF341F",
|
||||||
|
}
|
||||||
|
|
||||||
|
def pos(now=None):
|
||||||
|
days_in_second = 86400
|
||||||
|
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
difference = now - datetime.datetime(2001, 1, 1)
|
||||||
|
|
||||||
|
days = dec(difference.days) + (dec(difference.seconds) / dec(days_in_second))
|
||||||
|
lunarCycle = dec("0.20439731") + (days * dec("0.03386319269"))
|
||||||
|
|
||||||
|
return lunarCycle % dec(1)
|
||||||
|
|
||||||
|
def current_phase(self):
|
||||||
|
|
||||||
|
lunarCycle = self.pos()
|
||||||
|
|
||||||
|
index = (lunarCycle * dec(8)) + dec("0.5")
|
||||||
|
index = math.floor(index)
|
||||||
|
|
||||||
|
return {
|
||||||
|
0: "New Moon",
|
||||||
|
1: "Waxing Crescent",
|
||||||
|
2: "First Quarter",
|
||||||
|
3: "Waxing Gibbous",
|
||||||
|
4: "Full Moon",
|
||||||
|
5: "Waning Gibbous",
|
||||||
|
6: "Last Quarter",
|
||||||
|
7: "Waning Crescent",
|
||||||
|
}[int(index) & 7]
|
||||||
|
|
||||||
|
def illum(self):
|
||||||
|
phase = 0
|
||||||
|
lunarCycle = float(self.pos()) * 100
|
||||||
|
|
||||||
|
if lunarCycle > 50:
|
||||||
|
phase = 100 - lunarCycle
|
||||||
|
else:
|
||||||
|
phase = lunarCycle * 2
|
||||||
|
|
||||||
|
return phase
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
fdict = {
|
||||||
|
"status": self.status[self.current_phase()],
|
||||||
|
"illum": self.illum(),
|
||||||
|
}
|
||||||
|
self.output = {
|
||||||
|
"full_text": formatp(self.format, **fdict),
|
||||||
|
"color": self.color[self.current_phase()],
|
||||||
|
}
|
@ -38,7 +38,7 @@ class MPD(IntervalModule):
|
|||||||
("max_field_len", "Defines max length for in truncate_fields defined fields, if truncated, ellipsis are appended as indicator. It's applied *before* max_len. Value of 0 disables this."),
|
("max_field_len", "Defines max length for in truncate_fields defined fields, if truncated, ellipsis are appended as indicator. It's applied *before* max_len. Value of 0 disables this."),
|
||||||
("max_len", "Defines max length for the hole string, if exceeding fields specefied in truncate_fields are truncated equaly. If truncated, ellipsis are appended as indicator. It's applied *after* max_field_len. Value of 0 disables this."),
|
("max_len", "Defines max length for the hole string, if exceeding fields specefied in truncate_fields are truncated equaly. If truncated, ellipsis are appended as indicator. It's applied *after* max_field_len. Value of 0 disables this."),
|
||||||
("truncate_fields", "fields that will be truncated if exceeding max_field_len or max_len."),
|
("truncate_fields", "fields that will be truncated if exceeding max_field_len or max_len."),
|
||||||
|
("hide_inactive", "Hides status information when MPD is not running"),
|
||||||
)
|
)
|
||||||
|
|
||||||
host = "localhost"
|
host = "localhost"
|
||||||
@ -54,6 +54,7 @@ class MPD(IntervalModule):
|
|||||||
max_field_len = 25
|
max_field_len = 25
|
||||||
max_len = 100
|
max_len = 100
|
||||||
truncate_fields = ("title", "album", "artist")
|
truncate_fields = ("title", "album", "artist")
|
||||||
|
hide_inactive = False
|
||||||
on_leftclick = "switch_playpause"
|
on_leftclick = "switch_playpause"
|
||||||
on_rightclick = "next_song"
|
on_rightclick = "next_song"
|
||||||
on_upscroll = on_rightclick
|
on_upscroll = on_rightclick
|
||||||
@ -78,8 +79,16 @@ class MPD(IntervalModule):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
status = self._mpd_command(self.s, "status")
|
try:
|
||||||
currentsong = self._mpd_command(self.s, "currentsong")
|
status = self._mpd_command(self.s, "status")
|
||||||
|
currentsong = self._mpd_command(self.s, "currentsong")
|
||||||
|
except Exception:
|
||||||
|
if self.hide_inactive:
|
||||||
|
self.output = {
|
||||||
|
"full_text": ""
|
||||||
|
}
|
||||||
|
return
|
||||||
|
|
||||||
fdict = {
|
fdict = {
|
||||||
"pos": int(status.get("song", 0)) + 1,
|
"pos": int(status.get("song", 0)) + 1,
|
||||||
"len": int(status["playlistlength"]),
|
"len": int(status["playlistlength"]),
|
||||||
|
@ -1,78 +1,103 @@
|
|||||||
import threading
|
|
||||||
import math
|
import math
|
||||||
|
from i3pystatus import formatp
|
||||||
from i3pystatus import Module
|
from i3pystatus import IntervalModule
|
||||||
from gi.repository import Playerctl, GLib
|
from gi.repository import Playerctl
|
||||||
|
|
||||||
|
|
||||||
class Spotify(Module):
|
class Spotify(IntervalModule):
|
||||||
"""
|
"""
|
||||||
This class shows information from Spotify.
|
Gets Spotify info using playerctl
|
||||||
|
|
||||||
Left click will toggle pause/play of the current song.
|
.. rubric:: Available formatters
|
||||||
Right click will skip the song.
|
|
||||||
|
|
||||||
Dependent on Playerctl ( https://github.com/acrisci/playerctl ) and GLib
|
* `{status}` — current status icon (paused/playing)
|
||||||
|
* `{length}` — total song duration (mm:ss format)
|
||||||
|
* `{artist}` — artist
|
||||||
|
* `{title}` — title
|
||||||
|
* `{album}` — album
|
||||||
"""
|
"""
|
||||||
|
|
||||||
format = "{artist} - {title}"
|
|
||||||
color = "#ffffff"
|
|
||||||
|
|
||||||
settings = (
|
settings = (
|
||||||
("format", "Format string. {artist}, {title}, {album}, {volume}, and {length} are available for output."),
|
('format', 'formatp string'),
|
||||||
("color", "color of the output"),
|
('format_not_running', 'Text to show if cmus is not running'),
|
||||||
|
('color', 'The color of the text'),
|
||||||
|
('color_not_running', 'The color of the text, when cmus is not running'),
|
||||||
|
('status', 'Dictionary mapping status to output'),
|
||||||
)
|
)
|
||||||
|
|
||||||
on_leftclick = "switch_playpause"
|
# default settings
|
||||||
on_rightclick = "next_song"
|
color = '#ffffff'
|
||||||
|
color_not_running = '#ffffff'
|
||||||
|
format = '{status} {length} {artist} - {title}'
|
||||||
|
format_not_running = 'Not running'
|
||||||
|
interval = 1
|
||||||
|
status = {
|
||||||
|
'paused': '▷',
|
||||||
|
'playing': '▶',
|
||||||
|
}
|
||||||
|
|
||||||
def main_loop(self):
|
on_leftclick = 'playpause'
|
||||||
""" Mainloop blocks so we thread it."""
|
on_rightclick = 'next_song'
|
||||||
self.player = Playerctl.Player()
|
on_upscroll = 'next_song'
|
||||||
self.player.on('metadata', self.set_status)
|
|
||||||
|
|
||||||
if self.player.props.status != "":
|
def get_info(self, player):
|
||||||
self.set_status(self.player)
|
"""gets spotify track info from playerctl"""
|
||||||
|
|
||||||
main = GLib.MainLoop()
|
|
||||||
main.run()
|
|
||||||
|
|
||||||
def init(self):
|
|
||||||
try:
|
|
||||||
t = threading.Thread(target=self.main_loop)
|
|
||||||
t.daemon = True
|
|
||||||
t.start()
|
|
||||||
except Exception as e:
|
|
||||||
self.output = {
|
|
||||||
"full_text": "Error creating new thread!",
|
|
||||||
"color": "#FF0000"
|
|
||||||
}
|
|
||||||
|
|
||||||
def set_status(self, player, e=None):
|
|
||||||
artist = player.get_artist()
|
artist = player.get_artist()
|
||||||
title = player.get_title()
|
title = player.get_title()
|
||||||
album = player.get_album()
|
album = player.get_album()
|
||||||
volume = player.props.volume
|
status = player.props.status
|
||||||
|
|
||||||
|
# gets the length of spotify through the metadata command
|
||||||
length = ""
|
length = ""
|
||||||
if e is not None:
|
|
||||||
time = e["mpris:length"] / 60.0e6
|
# stores the metadata and checks if it is valid
|
||||||
|
metadata = player.props.metadata
|
||||||
|
if metadata is not None:
|
||||||
|
# math to convert the number stored in mpris:length to a human readable format
|
||||||
|
time = dict(metadata)["mpris:length"] / 60.0e6
|
||||||
minutes = math.floor(time)
|
minutes = math.floor(time)
|
||||||
seconds = round(time % 1 * 60)
|
seconds = round(time % 1 * 60)
|
||||||
if seconds < 10:
|
if seconds < 10:
|
||||||
seconds = "0" + str(seconds)
|
seconds = "0" + str(seconds)
|
||||||
length = "{}:{}".format(minutes, seconds)
|
length = "{}:{}".format(minutes, seconds)
|
||||||
|
|
||||||
self.output = {
|
# sets length to an empty string if it does not exist for whatever reason. This should usually not happen
|
||||||
"full_text": self.format.format(
|
else:
|
||||||
artist=artist, title=title,
|
length = ""
|
||||||
album=album, length=length,
|
|
||||||
volume=volume),
|
|
||||||
"color": self.color
|
|
||||||
}
|
|
||||||
|
|
||||||
def switch_playpause(self):
|
# returns a dictionary of all spotify data
|
||||||
|
return {"artist": artist, "title": title, "album": album, "status": status, "length": length}
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""Main statement, executes all code every interval"""
|
||||||
|
|
||||||
|
# tries to create player object and get data from player
|
||||||
|
try:
|
||||||
|
self.player = Playerctl.Player()
|
||||||
|
|
||||||
|
response = self.get_info(self.player)
|
||||||
|
|
||||||
|
# creates a dictionary of the spotify data captured
|
||||||
|
fdict = {
|
||||||
|
'status': self.status[response['status'].lower()],
|
||||||
|
'title': response["title"],
|
||||||
|
'album': response.get('album', ''),
|
||||||
|
'artist': response.get('artist', ''),
|
||||||
|
'length': response.get('length', 0),
|
||||||
|
}
|
||||||
|
self.output = {"full_text": formatp(self.format, **fdict),
|
||||||
|
"color": self.color}
|
||||||
|
|
||||||
|
# outputs the not running string if spotify is closed
|
||||||
|
except:
|
||||||
|
self.output = {"full_text": self.format_not_running,
|
||||||
|
"color": self.color_not_running}
|
||||||
|
|
||||||
|
def playpause(self):
|
||||||
|
"""Pauses and plays spotify"""
|
||||||
self.player.play_pause()
|
self.player.play_pause()
|
||||||
|
|
||||||
def next_song(self):
|
def next_song(self):
|
||||||
|
"""skips to the next song"""
|
||||||
self.player.next()
|
self.player.next()
|
||||||
|
Loading…
Reference in New Issue
Block a user