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:
Sumner Evans
2021-04-17 10:22:26 -06:00
parent 73990e5a1e
commit 08f4224014
7 changed files with 50 additions and 51 deletions

View File

@@ -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()

View File

@@ -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",

View File

@@ -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()

View File

@@ -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,

View File

@@ -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",

View File

@@ -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,

View File

@@ -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 &amp; <a href='ohea'>test</a>"
>>> esc(None)
''
"""
if string is None:
return ""
return string.replace("&", "&amp;").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.