diff --git a/sublime_music/adapters/configure_server_form.py b/sublime_music/adapters/configure_server_form.py
index c82fcaa..47427b1 100644
--- a/sublime_music/adapters/configure_server_form.py
+++ b/sublime_music/adapters/configure_server_form.py
@@ -8,6 +8,8 @@ from pathlib import Path
from time import sleep
from typing import Any, Callable, cast, Dict, Iterable, Optional, Tuple, Type, Union
+import bleach
+
from gi.repository import GLib, GObject, Gtk, Pango
from . import ConfigurationStore
@@ -252,8 +254,6 @@ class ConfigureServerForm(Gtk.Box):
def _set_verification_status(
self, verifying: bool, is_valid: bool = False, error_text: str = None
):
- from sublime_music.ui import util
-
if verifying:
if not self.verifying_in_progress:
for c in self.config_verification_box.get_children():
@@ -288,7 +288,7 @@ class ConfigureServerForm(Gtk.Box):
set_icon_and_label(
"config-ok-symbolic", "Configuration is valid"
)
- elif escaped := util.esc(error_text):
+ elif escaped := bleach.clean(error_text or ""):
set_icon_and_label("config-error-symbolic", escaped)
self.config_verification_box.show_all()
diff --git a/sublime_music/app.py b/sublime_music/app.py
index d4e9e10..c0c258a 100644
--- a/sublime_music/app.py
+++ b/sublime_music/app.py
@@ -1191,14 +1191,12 @@ class SublimeMusicApp(Gtk.Application):
if glib_notify_exists:
notification_lines = []
if album := song.album:
- notification_lines.append(
- f"{bleach.clean(album.name)}"
- )
+ notification_lines.append(f"{album.name}")
if artist := song.artist:
- notification_lines.append(bleach.clean(artist.name))
+ notification_lines.append(artist.name)
song_notification = Notify.Notification.new(
song.title,
- "\n".join(notification_lines),
+ bleach.clean("\n".join(notification_lines)),
)
song_notification.add_action(
"clicked",
diff --git a/sublime_music/ui/artists.py b/sublime_music/ui/artists.py
index cfec212..32a54de 100644
--- a/sublime_music/ui/artists.py
+++ b/sublime_music/ui/artists.py
@@ -3,6 +3,8 @@ from functools import partial
from random import randint
from typing import cast, List, Sequence
+import bleach
+
from gi.repository import Gio, GLib, GObject, Gtk, Pango
from ..adapters import (
@@ -93,10 +95,9 @@ class ArtistList(Gtk.Box):
list_scroll_window = Gtk.ScrolledWindow(min_content_width=250)
def create_artist_row(model: _ArtistModel) -> Gtk.ListBoxRow:
- label_text = [f"{util.esc(model.name)}"]
+ label_text = [f"{model.name}"]
- album_count = model.album_count
- if album_count:
+ if album_count := model.album_count:
label_text.append(
"{} {}".format(album_count, util.pluralize("album", album_count))
)
@@ -107,7 +108,7 @@ class ArtistList(Gtk.Box):
)
row.add(
Gtk.Label(
- label="\n".join(label_text),
+ label=bleach.clean("\n".join(label_text)),
use_markup=True,
margin=12,
halign=Gtk.Align.START,
@@ -368,7 +369,7 @@ class ArtistDetailPanel(Gtk.Box):
"Collapse" if self.artist_details_expanded else "Expand"
)
- self.artist_name.set_markup(util.esc(f"{artist.name}"))
+ self.artist_name.set_markup(bleach.clean(f"{artist.name}"))
self.artist_name.set_tooltip_text(artist.name)
if self.artist_details_expanded:
@@ -378,7 +379,7 @@ class ArtistDetailPanel(Gtk.Box):
self.artist_stats.set_markup(self.format_stats(artist))
if artist.biography:
- self.artist_bio.set_markup(util.esc(artist.biography))
+ self.artist_bio.set_markup(bleach.clean(artist.biography))
self.artist_bio.show()
else:
self.artist_bio.hide()
diff --git a/sublime_music/ui/browse.py b/sublime_music/ui/browse.py
index f95f8ae..21d2fe1 100644
--- a/sublime_music/ui/browse.py
+++ b/sublime_music/ui/browse.py
@@ -1,6 +1,8 @@
from functools import partial
from typing import Any, cast, List, Optional, Tuple
+import bleach
+
from gi.repository import Gdk, Gio, GLib, GObject, Gtk, Pango
from ..adapters import AdapterManager, api_objects as API, CacheMissError, Result
@@ -383,7 +385,7 @@ class MusicDirectoryList(Gtk.Box):
in ("folder-download-symbolic", "view-pin-symbolic")
),
status_icon,
- util.esc(song.title),
+ bleach.clean(song.title),
util.format_song_duration(song.duration),
song.id,
]
@@ -442,7 +444,7 @@ class MusicDirectoryList(Gtk.Box):
rowbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
rowbox.add(
Gtk.Label(
- label=f"{util.esc(model.name)}",
+ label=bleach.clean(f"{model.name}"),
use_markup=True,
margin=8,
halign=Gtk.Align.START,
diff --git a/sublime_music/ui/main.py b/sublime_music/ui/main.py
index f7b1e51..ab858df 100644
--- a/sublime_music/ui/main.py
+++ b/sublime_music/ui/main.py
@@ -1,6 +1,8 @@
from functools import partial
from typing import Any, Callable, Dict, Optional, Set, Tuple
+import bleach
+
from gi.repository import Gdk, GLib, GObject, Gtk, Pango
from ..adapters import (
@@ -1089,13 +1091,13 @@ class MainWindow(Gtk.ApplicationWindow):
self._remove_all_from_widget(self.song_results)
for song in search_results.songs:
label_text = util.dot_join(
- f"{util.esc(song.title)}",
- util.esc(song.artist.name if song.artist else None),
+ f"{song.title}",
+ song.artist.name if song.artist else None,
)
assert song.album and song.album.id
self.song_results.add(
self._create_search_result_row(
- label_text, "album", song.album.id, song.cover_art
+ bleach.clean(label_text), "album", song.album.id, song.cover_art
)
)
@@ -1106,13 +1108,13 @@ class MainWindow(Gtk.ApplicationWindow):
self._remove_all_from_widget(self.album_results)
for album in search_results.albums:
label_text = util.dot_join(
- f"{util.esc(album.name)}",
- util.esc(album.artist.name if album.artist else None),
+ f"{album.name}",
+ album.artist.name if album.artist else None,
)
assert album.id
self.album_results.add(
self._create_search_result_row(
- label_text, "album", album.id, album.cover_art
+ bleach.clean(label_text), "album", album.id, album.cover_art
)
)
@@ -1122,11 +1124,13 @@ class MainWindow(Gtk.ApplicationWindow):
if search_results.artists is not None:
self._remove_all_from_widget(self.artist_results)
for artist in search_results.artists:
- label_text = util.esc(artist.name)
assert artist.id
self.artist_results.add(
self._create_search_result_row(
- label_text, "artist", artist.id, artist.artist_image_url
+ bleach.clean(artist.name),
+ "artist",
+ artist.id,
+ artist.artist_image_url,
)
)
@@ -1136,10 +1140,12 @@ class MainWindow(Gtk.ApplicationWindow):
if search_results.playlists:
self._remove_all_from_widget(self.playlist_results)
for playlist in search_results.playlists:
- label_text = util.esc(playlist.name)
self.playlist_results.add(
self._create_search_result_row(
- label_text, "playlist", playlist.id, playlist.cover_art
+ bleach.clean(playlist.name),
+ "playlist",
+ playlist.id,
+ playlist.cover_art,
)
)
@@ -1182,10 +1188,10 @@ class DownloadStatusBox(Gtk.Box):
)
self.add(image)
- artist = util.esc(self.song.artist.name if self.song.artist else None)
- label_text = util.dot_join(f"{util.esc(self.song.title)}", artist)
+ artist = self.song.artist.name if self.song.artist else None
+ label_text = util.dot_join(f"{self.song.title}", artist)
self.song_label = Gtk.Label(
- label=label_text,
+ label=bleach.clean(label_text),
ellipsize=Pango.EllipsizeMode.END,
max_width_chars=30,
name="currently-downloading-song-title",
diff --git a/sublime_music/ui/player_controls.py b/sublime_music/ui/player_controls.py
index cb80756..9a880f3 100644
--- a/sublime_music/ui/player_controls.py
+++ b/sublime_music/ui/player_controls.py
@@ -4,6 +4,8 @@ from datetime import timedelta
from functools import partial
from typing import Any, Callable, Dict, Optional, Set, Tuple
+import bleach
+
from gi.repository import Gdk, GdkPixbuf, GLib, GObject, Gtk, Pango
from . import util
@@ -168,18 +170,20 @@ class PlayerControls(Gtk.ActionBar):
order_token=self.cover_art_update_order_token,
)
- self.song_title.set_markup(util.esc(app_config.state.current_song.title))
+ self.song_title.set_markup(
+ bleach.clean(app_config.state.current_song.title)
+ )
# TODO (#71): use walrus once MYPY gets its act together
album = app_config.state.current_song.album
artist = app_config.state.current_song.artist
if album:
- self.album_name.set_markup(util.esc(album.name))
+ self.album_name.set_markup(bleach.clean(album.name))
self.artist_name.show()
else:
self.album_name.set_markup("")
self.album_name.hide()
if artist:
- self.artist_name.set_markup(util.esc(artist.name))
+ self.artist_name.set_markup(bleach.clean(artist.name))
self.artist_name.show()
else:
self.artist_name.set_markup("")
@@ -228,13 +232,13 @@ class PlayerControls(Gtk.ActionBar):
new_store = []
def calculate_label(song_details: Song) -> str:
- title = util.esc(song_details.title)
- # TODO (#71): use walrus once MYPY works with this
- # album = util.esc(album.name if (album := song_details.album) else None)
- # artist = util.esc(artist.name if (artist := song_details.artist) else None) # noqa
- album = util.esc(song_details.album.name if song_details.album else None)
- artist = util.esc(song_details.artist.name if song_details.artist else None)
- return f"{title}\n{util.dot_join(album, artist)}"
+ title = song_details.title
+ # TODO (#71): use walrus once MYPY gets its act together
+ # album = a.name if (a := song_details.album) else None
+ # artist = a.name if (a := song_details.artist) else None
+ album = song_details.album.name if song_details.album else None
+ artist = song_details.artist.name if song_details.artist else None
+ return bleach.clean(f"{title}\n{util.dot_join(album, artist)}")
def make_idle_index_capturing_function(
idx: int,
diff --git a/sublime_music/ui/util.py b/sublime_music/ui/util.py
index c49cd6b..ead25e7 100644
--- a/sublime_music/ui/util.py
+++ b/sublime_music/ui/util.py
@@ -94,18 +94,6 @@ def format_sequence_duration(duration: Optional[timedelta]) -> str:
return ", ".join(format_components)
-def esc(string: Optional[str]) -> str:
- """
- >>> esc("test & test")
- "test & test"
- >>> esc(None)
- ''
- """
- if string is None:
- return ""
- return string.replace("&", "&").replace(" target='_blank'", "")
-
-
def dot_join(*items: Any) -> str:
"""
Joins the given strings with a dot character. Filters out ``None`` values.