Cache thumbnails
This commit is contained in:
parent
a211bfd1b3
commit
86716e83b4
2 changed files with 54 additions and 7 deletions
lazy_player
|
@ -161,6 +161,8 @@ class MainWindow(Gtk.ApplicationWindow, Watcher):
|
|||
return cast(FileItem, selected_item) if selected_item else None
|
||||
|
||||
def _setup_list_item(self, factory: Gtk.SignalListItemFactory, list_item: Gtk.ListItem):
|
||||
factory = factory
|
||||
|
||||
# Create horizontal box to hold icon and label
|
||||
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
|
||||
box.set_spacing(8)
|
||||
|
@ -178,6 +180,8 @@ class MainWindow(Gtk.ApplicationWindow, Watcher):
|
|||
list_item.set_child(box)
|
||||
|
||||
def _bind_list_item(self, factory: Gtk.SignalListItemFactory, list_item: Gtk.ListItem):
|
||||
factory = factory
|
||||
|
||||
box = cast(Gtk.Box, list_item.get_child())
|
||||
icon = cast(Gtk.Image, box.get_first_child())
|
||||
label = cast(Gtk.Label, box.get_last_child())
|
||||
|
@ -206,6 +210,8 @@ class MainWindow(Gtk.ApplicationWindow, Watcher):
|
|||
update_icon()
|
||||
|
||||
def _on_activate(self, widget: Gtk.ListView, index: int):
|
||||
widget = widget
|
||||
|
||||
selected_item = self.selection_model.get_item(index)
|
||||
if selected_item:
|
||||
file_item = cast(FileItem, selected_item)
|
||||
|
@ -262,6 +268,8 @@ class MainWindow(Gtk.ApplicationWindow, Watcher):
|
|||
position: int,
|
||||
n_items: int,
|
||||
):
|
||||
n_items = n_items
|
||||
|
||||
position = selection_model.get_selected()
|
||||
|
||||
if position == Gtk.INVALID_LIST_POSITION:
|
||||
|
@ -289,6 +297,9 @@ class MainWindow(Gtk.ApplicationWindow, Watcher):
|
|||
keycode: int,
|
||||
state: Gdk.ModifierType,
|
||||
) -> bool:
|
||||
keycode = keycode
|
||||
state = state
|
||||
|
||||
if keyval == Gdk.keyval_from_name("space"):
|
||||
self._toggle_play_pause()
|
||||
return True
|
||||
|
@ -387,6 +398,9 @@ class MainWindow(Gtk.ApplicationWindow, Watcher):
|
|||
keycode: int,
|
||||
state: Gdk.ModifierType,
|
||||
) -> bool:
|
||||
keycode = keycode
|
||||
state = state
|
||||
|
||||
if keyval == Gdk.keyval_from_name("q"):
|
||||
self.close()
|
||||
return True
|
||||
|
@ -412,6 +426,8 @@ class MainWindow(Gtk.ApplicationWindow, Watcher):
|
|||
keycode: int,
|
||||
state: Gdk.ModifierType,
|
||||
) -> bool:
|
||||
controller = controller
|
||||
|
||||
# Handle keys differently based on which view is active
|
||||
if self.stack.get_visible_child_name() == "player":
|
||||
return self._on_player_key_pressed(keyval, keycode, state)
|
||||
|
@ -438,6 +454,9 @@ class MainWindow(Gtk.ApplicationWindow, Watcher):
|
|||
file_item.saved_duration.value = duration
|
||||
|
||||
def _on_tick(self, widget: Gtk.Widget, frame_clock: Gdk.FrameClock, data: Any) -> bool:
|
||||
widget = widget
|
||||
data = data
|
||||
|
||||
# Update all reactive values for whole application.
|
||||
update_all_computed()
|
||||
|
||||
|
|
|
@ -26,6 +26,11 @@ __all__ = ["Thumbnailer", "generate_thumbnail_sync"]
|
|||
|
||||
MAX_WORKERS = max(1, multiprocessing.cpu_count() // 2)
|
||||
|
||||
CACHE_HOME = os.environ.get(
|
||||
"XDG_CACHE_HOME", os.path.join(os.environ.get("HOME", "/tmp"), ".cache")
|
||||
)
|
||||
CACHE_PATH = os.path.join(CACHE_HOME, "lazy-player", "thumbnails")
|
||||
|
||||
|
||||
class Thumbnailer(ThreadPoolExecutor):
|
||||
def __init__(self):
|
||||
|
@ -51,7 +56,35 @@ class Thumbnailer(ThreadPoolExecutor):
|
|||
|
||||
def generate_thumbnail_sync_nicely(file_item: FileItem):
|
||||
os.nice(10)
|
||||
return generate_thumbnail_sync(file_item)
|
||||
|
||||
stat = os.stat(file_item.full_path)
|
||||
name = f"{stat.st_ino}-{stat.st_size}.jpeg"
|
||||
path = os.path.join(CACHE_PATH, name)
|
||||
|
||||
if os.path.exists(path):
|
||||
with open(path, "rb") as fp:
|
||||
thumbnail = fp.read()
|
||||
|
||||
def set_thumbnail():
|
||||
file_item.thumbnail.value = thumbnail
|
||||
|
||||
GLib.idle_add(set_thumbnail)
|
||||
return
|
||||
|
||||
else:
|
||||
os.makedirs(CACHE_PATH, exist_ok=True)
|
||||
thumbnail = generate_thumbnail_sync(file_item)
|
||||
|
||||
if thumbnail is None:
|
||||
return
|
||||
|
||||
with open(path, "wb") as fp:
|
||||
fp.write(thumbnail)
|
||||
|
||||
def set_thumbnail():
|
||||
file_item.thumbnail.value = thumbnail
|
||||
|
||||
GLib.idle_add(set_thumbnail)
|
||||
|
||||
|
||||
def generate_thumbnail_sync(file_item: FileItem):
|
||||
|
@ -118,12 +151,7 @@ def generate_thumbnail_sync(file_item: FileItem):
|
|||
for i in range(3):
|
||||
candidates.append(get_sample(duration // 3 - Gst.SECOND + i * Gst.SECOND))
|
||||
|
||||
thumbnail = max(candidates, key=len)
|
||||
|
||||
def set_thumbnail():
|
||||
file_item.thumbnail.value = thumbnail
|
||||
|
||||
GLib.idle_add(set_thumbnail)
|
||||
return max(candidates, key=len)
|
||||
|
||||
except Exception as err:
|
||||
print("[thumbnailer] Error:", file_item.full_path.name, file=sys.stderr)
|
||||
|
|
Loading…
Reference in a new issue