Skip to content

Commit

Permalink
music modules: implement sanitize_words support for all music modules
Browse files Browse the repository at this point in the history
  • Loading branch information
dpeukert committed Feb 16, 2024
1 parent 137201b commit 6ade1f8
Show file tree
Hide file tree
Showing 9 changed files with 173 additions and 80 deletions.
13 changes: 13 additions & 0 deletions py3status/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,3 +270,16 @@
MARKUP_LANGUAGES = ["pango", "none"]

ON_ERROR_VALUES = ["hide", "show"]

DEFAULT_SANITIZE_WORDS = [
"bonus",
"demo",
"edit",
"explicit",
"extended",
"feat",
"mono",
"remaster",
"stereo",
"version",
]
12 changes: 12 additions & 0 deletions py3status/modules/cmus.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
this interval will be used. this allows some flexible timing where one
might want to refresh constantly with some placeholders... or to refresh
only once every minute rather than every few seconds. (default 20)
sanitize_titles: whether to remove meta data from album/track title
(default True)
sanitize_words: which meta data to remove
*(default ['bonus', 'demo', 'edit', 'explicit', 'extended',
'feat', 'mono', 'remaster', 'stereo', 'version'])*
Control placeholders:
{is_paused} a boolean based on cmus status
Expand Down Expand Up @@ -83,6 +88,8 @@
{'color': '#FF0000', 'full_text': '.. cmus: waiting for user input'}
"""

from py3status.constants import DEFAULT_SANITIZE_WORDS

STRING_NOT_INSTALLED = "not installed"


Expand All @@ -101,6 +108,8 @@ class Py3status:
r"|\?show cmus: waiting for user input]]"
)
sleep_timeout = 20
sanitize_titles = True
sanitize_words = DEFAULT_SANITIZE_WORDS

def post_config_hook(self):
if not self.py3.check_commands("cmus-remote"):
Expand Down Expand Up @@ -149,6 +158,9 @@ def _manipulate_data(self, data):
temporary[key] = True
elif value in ("false", "disabled"):
temporary[key] = False
# sanitize album and title
elif self.sanitize_titles and key in ("album", "title"):
temporary[key] = self.py3.sanitize_title(self.sanitize_words, value)
# string not modified
else:
temporary[key] = value
Expand Down
17 changes: 17 additions & 0 deletions py3status/modules/deadbeef.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
to allow faster refreshes with time-related placeholders and/or
to refresh few times per minute rather than every few seconds
(default 20)
sanitize_titles: whether to remove meta data from album/track title
(default True)
sanitize_words: which meta data to remove
*(default ['bonus', 'demo', 'edit', 'explicit', 'extended',
'feat', 'mono', 'remaster', 'stereo', 'version'])*
Format placeholders:
{album} name of the album
Expand Down Expand Up @@ -49,6 +54,8 @@
{'color': '#ffff00', 'full_text': 'Music For Programming - Lackluster'}
"""

from py3status.constants import DEFAULT_SANITIZE_WORDS

STRING_NOT_INSTALLED = "not installed"


Expand All @@ -59,6 +66,8 @@ class Py3status:
cache_timeout = 5
format = "[{artist} - ][{title}]"
sleep_timeout = 20
sanitize_titles = True
sanitize_words = DEFAULT_SANITIZE_WORDS

class Meta:
deprecated = {
Expand Down Expand Up @@ -119,6 +128,14 @@ def deadbeef(self):
beef_data = dict(zip(self.placeholders, line.split(self.separator)))
cached_until = self.cache_timeout

# Sanitize album and title
if self.sanitize_titles:
if "album" in beef_data:
beef_data["album"] = self.py3.sanitize_title(self.sanitize_words, beef_data["album"])

if "title" in beef_data:
beef_data["title"] = self.py3.sanitize_title(self.sanitize_words, beef_data["title"])

if beef_data["isplaying"]:
color = self.color_playing
else:
Expand Down
17 changes: 17 additions & 0 deletions py3status/modules/moc.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
allow one to refresh constantly with time placeholders and/or
to refresh once every minute rather than every few seconds
(default 20)
sanitize_titles: whether to remove meta data from album/track title
(default True)
sanitize_words: which meta data to remove
*(default ['bonus', 'demo', 'edit', 'explicit', 'extended',
'feat', 'mono', 'remaster', 'stereo', 'version'])*
Control placeholders:
{is_paused} a boolean based on moc status
Expand Down Expand Up @@ -72,6 +77,8 @@
{'color': '#FF0000', 'full_text': '[] moc'}
"""

from py3status.constants import DEFAULT_SANITIZE_WORDS

STRING_NOT_INSTALLED = "not installed"


Expand All @@ -89,6 +96,8 @@ class Py3status:
r"[\?if=is_paused \|\|][\?if=is_playing >] {title}]"
)
sleep_timeout = 20
sanitize_titles = True
sanitize_words = DEFAULT_SANITIZE_WORDS

def post_config_hook(self):
if not self.py3.check_commands("mocp"):
Expand Down Expand Up @@ -122,6 +131,14 @@ def moc(self):
category, value = line.split(": ", 1)
data[category.lower()] = value

# Sanitize album and title
if self.sanitize_titles:
if "album" in data:
data["album"] = self.py3.sanitize_title(self.sanitize_words, data["album"])

if "title" in data:
data["title"] = self.py3.sanitize_title(self.sanitize_words, data["title"])

self.state = data["state"]
if self.state == "PLAY":
is_playing = True
Expand Down
69 changes: 39 additions & 30 deletions py3status/modules/mpd_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
state_stop: label to display for "stopped" state (default '[stop]')
use_idle: whether to use idling instead of polling. None to autodetect
(default None)
sanitize_titles: whether to remove meta data from album/track title
(default True)
sanitize_words: which meta data to remove
*(default ['bonus', 'demo', 'edit', 'explicit', 'extended',
'feat', 'mono', 'remaster', 'stereo', 'version'])*
Format placeholders:
{state} state (paused, playing. stopped) can be defined via `state_..`
Expand Down Expand Up @@ -74,33 +79,7 @@
from mpd import CommandError, ConnectionError, MPDClient

from py3status.composite import Composite


def song_attr(song, attr):
def parse_mtime(date_str):
return datetime.datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%SZ")

if attr == "time":
try:
duration = int(song["time"])
if duration > 0:
minutes, seconds = divmod(duration, 60)
return f"{minutes:d}:{seconds:02d}"
raise ValueError
except (KeyError, ValueError):
return ""
elif attr == "position":
try:
return "{}".format(int(song["pos"]) + 1)
except (KeyError, ValueError):
return ""
elif attr == "mtime":
return parse_mtime(song["last-modified"]).strftime("%c")
elif attr == "mdate":
return parse_mtime(song["last-modified"]).strftime("%x")

return song.get(attr, "")

from py3status.constants import DEFAULT_SANITIZE_WORDS

class Py3status:
""" """
Expand All @@ -121,6 +100,8 @@ class Py3status:
state_play = "[play]"
state_stop = "[stop]"
use_idle = None
sanitize_titles = True
sanitize_words = DEFAULT_SANITIZE_WORDS

def post_config_hook(self):
# Convert from %placeholder% to {placeholder}
Expand All @@ -133,6 +114,34 @@ def post_config_hook(self):
self.current_status = None
self.idle_thread = Thread()

def _song_attr(self, song, attr):
def parse_mtime(date_str):
return datetime.datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%SZ")

if attr == "time":
try:
duration = int(song["time"])
if duration > 0:
minutes, seconds = divmod(duration, 60)
return f"{minutes:d}:{seconds:02d}"
raise ValueError
except (KeyError, ValueError):
return ""
elif attr == "position":
try:
return "{}".format(int(song["pos"]) + 1)
except (KeyError, ValueError):
return ""
elif attr == "mtime":
return parse_mtime(song["last-modified"]).strftime("%c")
elif attr == "mdate":
return parse_mtime(song["last-modified"]).strftime("%x")
# Sanitize album and title
elif self.sanitize_titles and attr in ("album", "title"):
return self.py3.sanitize_title(self.sanitize_words, song.get(attr, ""))

return song.get(attr, "")

def _get_mpd(self, disconnect=False):
if disconnect:
try:
Expand Down Expand Up @@ -229,8 +238,8 @@ def _get_status(self):

def attr_getter(attr):
if attr.startswith("next_"):
return song_attr(next_song, attr[5:])
return song_attr(song, attr)
return self._song_attr(next_song, attr[5:])
return self._song_attr(song, attr)

text = self.py3.safe_format(self.format, attr_getter=attr_getter)
if isinstance(text, Composite):
Expand Down Expand Up @@ -277,4 +286,4 @@ def kill(self):
"""
from py3status.module_test import module_test

module_test(Py3status)
module_test(Py3status, config={"format": "{artist} - {title}"})
18 changes: 17 additions & 1 deletion py3status/modules/mpris.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,15 @@
state_pause: specify icon for pause state (default u'\u25eb')
state_play: specify icon for play state (default u'\u25b7')
state_stop: specify icon for stop state (default u'\u25a1')
sanitize_titles: whether to remove meta data from album/track title
(default True)
sanitize_words: which meta data to remove
*(default ['bonus', 'demo', 'edit', 'explicit', 'extended',
'feat', 'mono', 'remaster', 'stereo', 'version'])*
Format placeholders:
{album} album name
{artist} artiste name (first one)
{artist} artist name (first one)
{length} time duration of the song
{player} show name of the player
{player_shortname} show name of the player from busname (usually command line name)
Expand Down Expand Up @@ -117,6 +122,7 @@
from mpris2 import get_players_uri
from mpris2.types import Metadata_Map

from py3status.constants import DEFAULT_SANITIZE_WORDS

class STATE(IntEnum):
Playing = 0
Expand Down Expand Up @@ -282,6 +288,14 @@ def metadata(self, metadata=None):

self._metadata["nowplaying"] = metadata.get("vlc:nowplaying", None)

# Sanitize album and title
if self.parent.sanitize_titles:
if "album" in self._metadata:
self._metadata["album"] = self.parent.py3.sanitize_title(self.parent.sanitize_words, self._metadata["album"])

if "title" in self._metadata:
self._metadata["title"] = self.parent.py3.sanitize_title(self.parent.sanitize_words, self._metadata["title"])

if not self._metadata.get("title"):
self._metadata["title"] = "No Track"

Expand Down Expand Up @@ -385,6 +399,8 @@ class Py3status:
state_pause = "\u25eb"
state_play = "\u25b7"
state_stop = "\u25a1"
sanitize_titles = True
sanitize_words = DEFAULT_SANITIZE_WORDS

def post_config_hook(self):
self._name_owner_change_match = None
Expand Down
16 changes: 15 additions & 1 deletion py3status/modules/playerctl.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
r"""
Display song/video and control players supported by playerctl
Playerctl is a command-line utility for controlling media players
Playerctl is a command-line utility for controlling media players
that implement the MPRIS D-Bus Interface Specification. With Playerctl
you can bind player actions to keys and get metadata about the currently
playing song or video.
Expand Down Expand Up @@ -29,6 +29,11 @@
thresholds: specify color thresholds to use for different placeholders
(default {"status": [("Playing", "good"), ("Paused", "degraded"), ("Stopped", "bad")]})
volume_delta: percentage (from 0 to 100) to change the player's volume by (default 10)
sanitize_titles: whether to remove meta data from album/track title
(default True)
sanitize_words: which meta data to remove
*(default ['bonus', 'demo', 'edit', 'explicit', 'extended',
'feat', 'mono', 'remaster', 'stereo', 'version'])*
Not all players support every button action
Expand Down Expand Up @@ -73,6 +78,8 @@
import gi
from gi.repository import GLib, Playerctl

from py3status.constants import DEFAULT_SANITIZE_WORDS

gi.require_version("Playerctl", "2.0")


Expand Down Expand Up @@ -102,6 +109,8 @@ class Py3status:
seek_delta = 5
thresholds = {"status": [("Playing", "good"), ("Paused", "degraded"), ("Stopped", "bad")]}
volume_delta = 10
sanitize_titles = True
sanitize_words = DEFAULT_SANITIZE_WORDS

class Meta:
update_config = {
Expand Down Expand Up @@ -234,6 +243,11 @@ def _get_player_data(self, player):
data["status"] = player.props.status
data["volume"] = int(player.props.volume * 100)

# Sanitize album and title
if self.sanitize_titles:
data["album"] = self.py3.sanitize_title(self.sanitize_words, data["album"])
data["title"] = self.py3.sanitize_title(self.sanitize_words, data["title"])

return data

def _get_player_from_index(self, index):
Expand Down
Loading

0 comments on commit 6ade1f8

Please sign in to comment.