Closes #175: cached a bunch of calls that hit the database a lot from the DBus Manager

This commit is contained in:
Sumner Evans
2020-05-10 09:32:13 -06:00
parent 60063a12a9
commit 65aafd111d
9 changed files with 73 additions and 65 deletions

6
Pipfile.lock generated
View File

@@ -157,10 +157,10 @@
},
"marshmallow": {
"hashes": [
"sha256:56663fa1d5385c14c6a1236badd166d6dee987a5f64d2b6cc099dadf96eb4f09",
"sha256:f12203bf8d94c410ab4b8d66edfde4f8a364892bde1f6747179765559f93d62a"
"sha256:c2673233aa21dde264b84349dc2fd1dce5f30ed724a0a00e75426734de5b84ab",
"sha256:f88fe96434b1f0f476d54224d59333eba8ca1a203a2695683c1855675c4049a7"
],
"version": "==3.5.2"
"version": "==3.6.0"
},
"marshmallow-enum": {
"hashes": [

View File

@@ -8,7 +8,6 @@ from termcolor import cprint
todo_re = re.compile(r"\s*#\s*TODO:?\s*")
accounted_for_todo = re.compile(r"\s*#\s*TODO:?\s*\((#\d+)\)")
print_re = re.compile(r"\s+print\(.*\)")
def noqa_re(error_id: str = ""):
@@ -29,10 +28,6 @@ def check_file(path: Path) -> bool:
eprint(f"{i}: {line}")
valid = False
if print_re.search(line) and not noqa_re("T001").search(line):
eprint(f"{i}: {line}")
valid = False
file.close()
return valid

View File

@@ -1,8 +1,7 @@
[flake8]
select = C,E,F,W,B,B950
ignore = E203, E402, E501, W503, ANN002, ANN003, ANN101, ANN102, ANN204
extend-ignore = E203, E402, E722, W503, ANN002, ANN003, ANN101, ANN102, ANN204
exclude = .git,__pycache__,build,dist,flatpak
max-line-length = 80
max-line-length = 88
suppress-none-returning = True
suppress-dummy-args = True
application-import-names = sublime
@@ -47,15 +46,6 @@ ignore_missing_imports = True
[mypy-peewee]
ignore_missing_imports = True
[yapf]
based_on_style = pep8
split_before_bitwise_operator = true
split_before_arithmetic_operator = true
split_before_dot = true
split_before_logical_operator = true
split_complex_comprehension = true
split_before_first_argument = true
[tool:pytest]
python_files = tests/**/*.py tests/*.py
python_functions = test_* *_test

View File

@@ -383,6 +383,7 @@ class AdapterManager:
def get_playlists(
before_download: Callable[[], None] = lambda: None,
force: bool = False, # TODO: rename to use_ground_truth_adapter?
allow_download: bool = True,
) -> Result[Sequence[Playlist]]:
assert AdapterManager._instance
partial_playlists_data = None
@@ -396,6 +397,9 @@ class AdapterManager:
except Exception:
logging.exception(f'Error on {"get_playlists"} retrieving from cache.')
if not allow_download:
raise CacheMissError(partial_data=partial_playlist_data)
if AdapterManager._instance.caching_adapter and force:
AdapterManager._instance.caching_adapter.invalidate_data(
CachingAdapter.CachedDataKey.PLAYLISTS, ()

View File

@@ -348,7 +348,7 @@ class SublimeMusicApp(Gtk.Application):
self.on_song_clicked(
None,
song_idx,
[s.id for s in playlist.songs],
tuple(s.id for s in playlist.songs),
{"active_playlist_id": playlist_id},
)
@@ -598,7 +598,7 @@ class SublimeMusicApp(Gtk.Application):
self.update_window()
@dbus_propagate()
def on_play_next(self, action: Any, song_ids: List[str]):
def on_play_next(self, action: Any, song_ids: Tuple[str, ...]):
if self.app_config.state.current_song is None:
insert_at = 0
else:
@@ -606,16 +606,18 @@ class SublimeMusicApp(Gtk.Application):
self.app_config.state.play_queue = (
self.app_config.state.play_queue[:insert_at]
+ list(song_ids)
+ song_ids
+ self.app_config.state.play_queue[insert_at:]
)
self.app_config.state.old_play_queue.extend(song_ids)
self.app_config.state.old_play_queue += song_ids
self.update_window()
@dbus_propagate()
def on_add_to_queue(self, action: Any, song_ids: GLib.Variant):
self.app_config.state.play_queue.extend(song_ids)
self.app_config.state.old_play_queue.extend(song_ids)
print(song_ids)
print(type(song_ids))
self.app_config.state.play_queue += tuple(song_ids)
self.app_config.state.old_play_queue += tuple(song_ids)
self.update_window()
def on_go_to_album(self, action: Any, album_id: GLib.Variant):
@@ -714,12 +716,14 @@ class SublimeMusicApp(Gtk.Application):
self,
win: Any,
song_index: int,
song_queue: List[str],
song_queue: Tuple[str, ...],
metadata: Dict[str, Any],
):
print(type(song_queue), song_queue)
song_queue = tuple(song_queue)
# Reset the play queue so that we don't ever revert back to the
# previous one.
old_play_queue = song_queue.copy()
old_play_queue = song_queue
if (force_shuffle := metadata.get("force_shuffle_state")) is not None:
self.app_config.state.shuffle_on = force_shuffle
@@ -729,10 +733,11 @@ class SublimeMusicApp(Gtk.Application):
# If shuffle is enabled, then shuffle the playlist.
if self.app_config.state.shuffle_on and not metadata.get("no_reshuffle"):
song_id = song_queue[song_index]
del song_queue[song_index]
random.shuffle(song_queue)
song_queue = [song_id] + song_queue
song_queue_list = list(
song_queue[:song_index] + song_queue[song_index + 1 :]
)
random.shuffle(song_queue_list)
song_queue = tuple(song_id, *song_queue_list)
song_index = 0
self.play_song(
@@ -743,11 +748,11 @@ class SublimeMusicApp(Gtk.Application):
)
def on_songs_removed(self, win: Any, song_indexes_to_remove: List[int]):
self.app_config.state.play_queue = [
self.app_config.state.play_queue = tuple(
song_id
for i, song_id in enumerate(self.app_config.state.play_queue)
if i not in song_indexes_to_remove
]
)
# Determine how many songs before the currently playing one were also
# deleted.
@@ -902,7 +907,7 @@ class SublimeMusicApp(Gtk.Application):
def do_update(f: Future):
play_queue = f.result()
new_play_queue = [s.id for s in play_queue.entry]
new_play_queue = tuple(s.id for s in play_queue.entry)
new_current_song_id = str(play_queue.current)
new_song_progress = play_queue.position / 1000
@@ -965,8 +970,8 @@ class SublimeMusicApp(Gtk.Application):
self,
song_index: int,
reset: bool = False,
old_play_queue: List[str] = None,
play_queue: List[str] = None,
old_play_queue: Tuple[str, ...] = None,
play_queue: Tuple[str, ...] = None,
):
# Do this the old fashioned way so that we can have access to ``reset``
# in the callback.

View File

@@ -137,6 +137,7 @@ class AppConfiguration:
return self._state
def load_state(self):
self._state = UIState()
if not self.server:
return

View File

@@ -170,27 +170,9 @@ class DBusManager:
elif has_current_song:
has_next_song = state.current_song_index < len(state.play_queue) - 1
active_playlist = (False, GLib.Variant("(oss)", ("/", "", "")))
if state.active_playlist_id and AdapterManager.can_get_playlist_details():
try:
playlist = AdapterManager.get_playlist_details(
state.active_playlist_id, allow_download=False
).result()
active_playlist = self.get_active_playlist(state.active_playlist_id)
cover_art = AdapterManager.get_cover_art_filename(
playlist.cover_art, allow_download=False
).result()
active_playlist = (
True,
GLib.Variant(
"(oss)", ("/playlist/" + playlist.id, playlist.name, cover_art)
),
)
except CacheMissError:
pass
get_playlists_result = AdapterManager.get_playlists()
get_playlists_result = AdapterManager.get_playlists(allow_download=False)
if get_playlists_result.data_is_available:
playlist_count = len(get_playlists_result.result())
else:
@@ -249,7 +231,38 @@ class DBusManager:
},
}
def get_mpris_metadata(self, idx: int, play_queue: List[str],) -> Dict[str, Any]:
@functools.lru_cache(maxsize=10)
def get_active_playlist(
self, active_playlist_id: Optional[str]
) -> Tuple[bool, GLib.Variant]:
if not active_playlist_id or not AdapterManager.can_get_playlist_details():
return (False, GLib.Variant("(oss)", ("/", "", "")))
try:
playlist = AdapterManager.get_playlist_details(
active_playlist_id, allow_download=False
).result()
try:
cover_art = AdapterManager.get_cover_art_filename(
playlist.cover_art, allow_download=False
).result()
except CacheMissError:
cover_art = ""
return (
True,
GLib.Variant(
"(oss)", ("/playlist/" + playlist.id, playlist.name, cover_art)
),
)
except CacheMissError:
return (False, GLib.Variant("(oss)", ("/", "", "")))
@functools.lru_cache(maxsize=10)
def get_mpris_metadata(
self, idx: int, play_queue: Tuple[str, ...]
) -> Dict[str, Any]:
try:
song = AdapterManager.get_song_details(
play_queue[idx], allow_download=False
@@ -283,7 +296,8 @@ class DBusManager:
"xesam:title": song.title,
}
def get_dbus_playlist(self, play_queue: List[str]) -> List[str]:
@functools.lru_cache(maxsize=10)
def get_dbus_playlist(self, play_queue: Tuple[str, ...]) -> List[str]:
seen_counts: DefaultDict[str, int] = defaultdict(int)
tracks = []
for song_id in play_queue:

View File

@@ -2,7 +2,7 @@ import math
from datetime import datetime, timedelta
from pathlib import Path
from typing import Any, Callable, List, Optional
from typing import Any, Callable, List, Optional, Tuple
import gi
@@ -46,7 +46,7 @@ class PlayerControls(Gtk.ActionBar):
reordering_play_queue_song_list: bool = False
current_song = None
current_device = None
current_play_queue: List[str] = []
current_play_queue: Tuple[str, ...] = ()
chromecasts: List[ChromecastPlayer] = []
cover_art_update_order_token = 0
play_queue_update_order_token = 0
@@ -154,7 +154,6 @@ class PlayerControls(Gtk.ActionBar):
self.update_device_list()
# Short circuit if no changes to the play queue
print(self.current_play_queue, app_config.state.play_queue)
if self.current_play_queue == app_config.state.play_queue:
return
self.current_play_queue = app_config.state.play_queue

View File

@@ -1,6 +1,6 @@
from dataclasses import dataclass, field
from enum import Enum
from typing import Dict, List, Optional
from typing import Dict, Optional, Tuple
from sublime.adapters.api_objects import Song
@@ -36,8 +36,8 @@ class UIState:
version: int = 1
playing: bool = False
current_song_index: int = -1
play_queue: List[str] = field(default_factory=list)
old_play_queue: List[str] = field(default_factory=list)
play_queue: Tuple[str, ...] = field(default_factory=tuple)
old_play_queue: Tuple[str, ...] = field(default_factory=tuple)
_volume: Dict[str, float] = field(default_factory=lambda: {"this device": 100.0})
is_muted: bool = False
repeat_type: RepeatType = RepeatType.NO_REPEAT