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