Skip to content

Commit

Permalink
Refresh on filesystem changes implemented
Browse files Browse the repository at this point in the history
  • Loading branch information
Edgiest05 committed May 5, 2024
1 parent db6e96b commit 3d21f0c
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 4 deletions.
51 changes: 49 additions & 2 deletions tagstudio/src/core/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@
import os
import sys
import time
from typing import Callable
import traceback
import xml.etree.ElementTree as ET
from enum import Enum
import ujson
from watchdog.observers import Observer
from watchdog.events import DirModifiedEvent, FileSystemEventHandler

from src.core.json_typing import JsonCollation, JsonEntry, JsonLibary, JsonTag
from src.core import ts_core
Expand Down Expand Up @@ -427,6 +430,9 @@ def __init__(self) -> None:
{"id": 30, "name": "Comments", "type": "text_box"},
]

# Refresh on changes
self.observer = Observer()

def create_library(self, path) -> int:
"""
Creates a TagStudio library in the given directory.\n
Expand Down Expand Up @@ -882,6 +888,10 @@ def clear_internal_vars(self):
self._tag_id_to_index_map: dict[int, int] = {}
self._tag_entry_ref_map.clear()

if self.observer.is_alive():
self.observer.stop()
self.observer.join()

def refresh_dir(self):
"""Scans a directory for files, and adds those relative filenames to internal variables."""

Expand Down Expand Up @@ -944,13 +954,50 @@ def refresh_dir(self):
f"[LIBRARY][INFO] Not bothering to sort files because there's OVER 100,000! Better sorting methods will be added in the future."
)

def refresh_on_changes(self, callback: Callable[[], None]) -> None:
"""Activates the automatic refreshing of the Library on filesystem modifications"""
class IsDirModifiedHandler(FileSystemEventHandler):
def __init__(self, lib: Library) -> None:
self.library: Library = lib
self.file_cache: dict[str, int] = {} # TODO: Cache invalidation
super().__init__()

def on_any_event(self, event):
filepath = event.dest_path if event.dest_path else event.src_path
if not event.is_directory and round(time.time()) != self.file_cache.get(filepath, 0):
# Update cache
self.file_cache[filepath] = int(time.time())

# Here update internal vars with single file
if ('$RECYCLE.BIN' in filepath or 'tagstudio_thumbs' in filepath):
return

if os.path.splitext(filepath)[1][1:].lower() not in self.library.ignored_extensions:
self.library.dir_file_count += 1
file = os.path.relpath(filepath, self.library.library_dir)

if os.name == 'nt':
id = self.library.filename_to_entry_id_map.get(file.lower())
else:
id = self.library.filename_to_entry_id_map.get(file)

if (id is None):
self.library.files_not_in_library.append(file)
new_ids = self.library.add_new_files_as_entries()
assert len(new_ids) == 1
id = new_ids[0]

callback()

self.observer.schedule(IsDirModifiedHandler(self), path=self.library_dir, recursive=True)
self.observer.start()

def refresh_missing_files(self):
"""Tracks the number of Entries that point to an invalid file path."""
self.missing_files.clear()
for i, entry in enumerate(self.entries):
full_path = os.path.normpath(
f"{self.library_dir}/{entry.path}/{entry.filename}"
)
f'{self.library_dir}/{entry.path}/{entry.filename}')
if not os.path.isfile(full_path):
self.missing_files.append(full_path)
yield i
Expand Down
3 changes: 1 addition & 2 deletions tagstudio/src/qt/ts_qt.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
from datetime import datetime as dt
from pathlib import Path
from queue import Empty, Queue
from watchdog.observers import Observer
from watchdog.events import DirModifiedEvent, FileSystemEventHandler
from typing import Optional

from PIL import Image
Expand Down Expand Up @@ -527,6 +525,7 @@ def start(self):
QColor("#9782ff"),
)
self.open_library(lib)
self.lib.refresh_on_changes(self.filter_items)

app.exec_()

Expand Down

0 comments on commit 3d21f0c

Please sign in to comment.