first commit

main
pineafan 3 years ago
commit a7c7027073
Signed by: Pinea
GPG Key ID: E5E1C2D43B0E4AB3

@ -0,0 +1,9 @@
{
"cSpell.ignoreWords": [
"mpris",
"playerctl",
"stty",
"trackid",
"xesam"
]
}

@ -0,0 +1,60 @@
import os
import time
import structures
from select import select
import sys
from modules import renderer
focus = 0
while True:
# Get the terminal size
rows, columns = os.popen('stty size', 'r').read().split()
rows, columns = int(rows), int(columns)
sources = os.popen("playerctl -l -s", "r").read().splitlines()
processed_sources = []
for source in sources:
metadata = os.popen(f"playerctl metadata -p {source} -s", "r").read().splitlines()
status = os.popen(f'playerctl status -p {source} -s', 'r').read().strip()
watched = float(os.popen(f'playerctl position -p {source} -s', 'r').read().strip() or "0")
metadata_dict = {}
for line in metadata:
split = line.split()
key = split[1]
value = " ".join(split[2:]) if len(split) > 2 else None
metadata_dict[key] = value
if "mpris:length" in metadata_dict:
metadata_dict["mpris:length"] = round(float(metadata_dict.get("mpris:length", 1)) / 10**6)
watched = round(watched)
if "xesam:url" in metadata_dict:
# Get everything after the last slash
metadata_dict["xesam:url"] = metadata_dict["xesam:url"].split("/")[-1]
title = ["xesam:title", "xesam:url"]
source_title = "Unknown Title"
for t in title:
if t in metadata_dict:
source_title = metadata_dict[t]
break
artist = ["xesam:artist", "xesam:albumArtist", "vlc:publisher"]
source_artist = None
for a in artist:
if a in metadata_dict:
source_artist = metadata_dict[a]
break
processed_sources.append(structures.Source(
source=source.split(".")[0],
name=source_title,
artist=source_artist,
length=metadata_dict.get('mpris:length', 1),
watched=watched,
status=status
))
focus = min(max(focus, 0), len(processed_sources) - 1) if processed_sources else -1
processed_sources = sorted(processed_sources, key=lambda source: source.source)
out = renderer.render(rows, columns, processed_sources, focus) or {}
time.sleep(0.25 * out.get("delay_multiplier", 1))

@ -0,0 +1,118 @@
import structures
styles = {
"block triangle": "   ",
"block circle": "   ",
"block square": "█ ██ 🮈-",
"triangle": "|=|> | "
}
def seconds_to_time(seconds):
hours = f"{seconds // (60 * 60):02}"
minutes = f"{seconds // 60:02}"
seconds = f"{seconds % 60:02}"
all_units = [seconds, minutes, hours]
all_units = [unit for i, unit in enumerate(all_units) if int(unit) != 0 or i <= 1]
return ":".join(reversed(all_units))
def standard_progress(width, padding, source: structures.Source | None, options):
width = width - 2 * padding
playing = source.status == "Playing"
style = styles[options.get("bar_style", "block triangle")]
if options.get("bar_style", "block triangle").startswith("block "):
background = "\033[42m" if playing else "\033[41m"
background_accent = "\033[106m" if playing else "\033[105m"
text_colour = "\033[32m" if playing else "\033[31m"
text_accent = "\033[36m" if playing else "\033[35m"
background_readable_text = "\033[97m"
else:
background = ""
background_accent = ""
text_colour = "\033[32m" if playing else "\033[31m"
text_accent = "\033[36m" if playing else "\033[35m"
background_readable_text = text_accent
clear = "\033[0m"
timestamp = seconds_to_time(source.watched)
duration = seconds_to_time(source.length)
remaining = "-" + seconds_to_time(source.length - source.watched)
full_timestamp = f"{remaining if options['negative_duration'] else timestamp} / {duration}"
extra_padding = style[6] != "-"
remaining_width = width - len(full_timestamp) - 3 - (2 if extra_padding else 0)
progress = round(source.watched_percent * remaining_width)
finished = progress == remaining_width
full_timestamp = f" {full_timestamp} " if extra_padding else f"{full_timestamp}"
bar = text_accent + style[0] + background_accent + background_readable_text + full_timestamp + text_accent + background + style[2]
bar += clear + background + text_colour + (style[1] * progress) + clear + text_colour + ("" if finished else style[3])
bar += style[4] * (remaining_width - progress - 1) + text_colour + style[3 if finished else 5]
return " " * padding + bar + clear + " " * padding
def custom_progress(width, padding, source: structures.Source, options):
return ""
def standard_details(width, padding, source: structures.Source, options):
width = width - 2 * padding
playing = source.status == "Playing"
style = styles[options.get("bar_style", "block triangle")]
colours = options["colours"]
if options.get("bar_style", "block triangle").startswith("block "):
blocked = True
background = colours["playing_highlight"] if playing else colours["paused_highlight"]
background_accent = colours["playing_accent"] if playing else colours["paused_accent"]
secondary_background = colours["details_highlight"]
text_colour = colours["playing_text"] if playing else colours["paused_text"]
text_accent = colours["playing_text_accent"] if playing else colours["paused_text_accent"]
secondary_accent = colours["details_text_accent"]
background_readable_text = colours["background_readable_text"]
secondary_text_colour = colours["details_text"]
else:
blocked = False
background = ""
background_accent = ""
secondary_background = ""
text_colour = colours["playing_text"] if playing else colours["paused_text"]
text_accent = colours["playing_text_accent"] if playing else colours["paused_text_accent"]
secondary_accent = ""
background_readable_text = text_accent
secondary_text_colour = text_accent
clear = "\033[0m"
remaining_width = width - 5
items = [getattr(source, i) for i in options["details_bar"] if getattr(source, i)]
pad_string = lambda string: " " + string + " "
if len(items) == "0":
return " " * width
string_width = len(items[0]) + 2
bar = text_accent + style[0] + background_accent + background_readable_text + pad_string(items[0])
if len(items) == 1:
bar += clear + text_accent + style[2]
else:
bar += text_accent + secondary_background + style[3]
for i, item in enumerate(items[1:]):
bar += secondary_text_colour + pad_string(item)
string_width += len(item) + 2
if i != len(items) - 2:
bar += style[5 if blocked else 3]
else:
bar += clear + (secondary_accent if blocked else text_accent) + style[2]
return " " * padding + bar + clear + " " * padding
def custom_details(width, padding, source: structures.Source, options):
return ""
def progress(width, padding, source: structures.Source, options):
# return custom_progress(width, padding, source, options)
return standard_progress(width, padding, source, options)
def details(width, padding, source: structures.Source, options):
# return custom_details(width, padding, source, options)
return standard_details(width, padding, source, options)

@ -0,0 +1,62 @@
import structures
from modules import bar
from modules import tabs
config = {
"header_align": "left",
"padding": 2,
"gap": 1,
"bar_style": "block triangle",
"tab_style": "block",
"negative_duration": True,
"colours": {
"paused_highlight": "\033[41m",
"playing_highlight": "\033[42m",
"unknown_highlight": "\033[100m",
"details_highlight": "\033[103m",
"paused_accent": "\033[105m",
"playing_accent": "\033[106m",
"unknown_accent": "\033[101m",
"paused_text": "\033[31m",
"playing_text": "\033[32m",
"unknown_text": "\033[97m",
"details_text": "\033[90m",
"paused_text_accent": "\033[35m",
"playing_text_accent": "\033[36m",
"unknown_text_accent": "\033[97m",
"details_text_accent": "\033[93m",
"background_readable_text": "\033[97m",
"tab_highlight_inactive": "\033[100m",
"tab_highlight_inactive_text": "\033[97m",
"tab_highlight_selected": "\033[107m",
"tab_highlight_selected_text": "\033[090m"
},
"details_bar": ["name", "artist", "status"]
}
def render(rows: int, columns: int, sources: list[structures.Source], focus):
out = {}
padding = " " * config["padding"]
allowed_width = columns - 2 * config["padding"]
if focus < 0:
focus_source = structures.Source(
source="N/A",
name="No applications playing audio",
artist=None,
length=1,
watched=0,
status="Unknown"
)
out["delay_multiplier"] = 4
else:
focus_source = sources[focus]
out["delay_multiplier"] = 1 if focus_source.status == "Playing" else 2
print("\n" * rows)
print(tabs.generate(columns, len(padding), sources, focus, config))
print()
print(bar.progress(columns, len(padding), focus_source, config))
print(bar.details(columns, len(padding), focus_source, config))

@ -0,0 +1,43 @@
import structures
def standard_tabs(width, padding, sources: list[structures.Source], active_index, options):
tabs = [source.source.capitalize() for source in sources]
if len(tabs) == 0:
tabs = ["No applications playing audio"]
active_index = 0
colours = options["colours"]
out = ""
style = options.get("tab_style", "block")
if style == "block":
inactive = colours["tab_highlight_inactive"] + colours["tab_highlight_inactive_text"]
active = colours["tab_highlight_selected"] + colours["tab_highlight_selected_text"]
out += inactive + " " * options["padding"]
tab_width = 0
for i, tab in enumerate(tabs):
if i == active_index:
out += active
out += f" {tab} " + inactive + " " * options["gap"]
tab_width += len(tab) + 2 + options["gap"]
out += inactive
# Add extra space to the end
out += " " * (width - tab_width - padding)
else:
out += " " * padding
tab_width = 0
for i, tab in enumerate(tabs):
if i == active_index:
out += colours["tab_highlight_selected_text"]
else:
out += colours["tab_highlight_inactive_text"]
out += f" [{tab}] "
tab_width += len(tab) + 4
return out + "\033[0m"
def custom_tabs(width, padding, sources: list[structures.Source], active_index, options):
return " " * width
def generate(width, padding, sources: list[structures.Source], active_index, options):
# return custom_tabs(width, padding, sources, active_index, options)
return standard_tabs(width, padding, sources, active_index, options)

@ -0,0 +1,16 @@
class Source:
def __init__(self,
source: str = None,
name: str = None,
artist: str = None,
length: int = None,
watched: int = None,
status: str = None
):
self.source = (source or "Unknown Source").strip()
self.name = (name or "N/A").strip()
self.artist = artist
self.length = length or 1
self.watched = watched or 0
self.watched_percent = min(max(self.watched / self.length, 0), 1)
self.status = status or "Playing"
Loading…
Cancel
Save