mirror of
https://git.srhtnin.garden/sarah/SaraTag.git
synced 2026-10-13 18:28:16 +02:00
SaraTag, a Flet GUI for tagging files.
This commit is contained in:
commit
845d6c6ee6
27 files changed
+6035
No files matched your search
+132
@@ -0,0 +1,132 @@
|
||||
"""Session history in .SaraTagHistory.toml: where each Record or Library was
|
||||
left (directory, filter, sort, selected file), recent files and the last
|
||||
updater runs. SaraTagConf.toml's [History] section says what's remembered and
|
||||
how much. Same schema as the terminal version wrote, so nothing is lost."""
|
||||
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import tomlkit
|
||||
|
||||
from Library import ConfValue, DataError, HistoryPath, ReadToml, TagCore, WriteAtomically
|
||||
|
||||
|
||||
def _Settings() -> dict[str, Any]:
|
||||
Defaults = {
|
||||
"Enabled": True, "MaxFileHistory": 30, "MaxDirectoryHistory": 20, "MaxUpdateHistory": 20,
|
||||
"RememberFilter": True, "RememberSorting": True, "RememberLastDirectory": True,
|
||||
"RememberLastSelectedFile": True, "RememberRecentFiles": True, "RememberUpdaterMode": True,
|
||||
"RememberUpdates": True,
|
||||
}
|
||||
return {Key: ConfValue("History", Key, Value) for Key, Value in Defaults.items()}
|
||||
|
||||
|
||||
def _Load() -> dict[str, Any]:
|
||||
TagCore.EnsureConfigFiles()
|
||||
try:
|
||||
return ReadToml(HistoryPath)
|
||||
except DataError:
|
||||
return {"ConfigVersion": 1} # a broken history file never blocks anything
|
||||
|
||||
|
||||
def _Save(History: dict[str, Any]) -> None:
|
||||
Document = tomlkit.document()
|
||||
Document.add(tomlkit.comment("SaraTag session history."))
|
||||
Document.add(tomlkit.comment("This file is managed automatically."))
|
||||
Document.add(tomlkit.nl())
|
||||
for Key, Value in History.items():
|
||||
Document[Key] = Value
|
||||
try:
|
||||
WriteAtomically(HistoryPath, tomlkit.dumps(Document))
|
||||
except OSError:
|
||||
pass # history is a convenience; failing to save it isn't worth an error
|
||||
|
||||
|
||||
def _Now() -> str:
|
||||
return datetime.now().astimezone().isoformat(timespec="seconds")
|
||||
|
||||
|
||||
def _Key(Root: Path | None, Library: str | None) -> tuple[str, str]:
|
||||
return ("Library", Library) if Library is not None else ("Root", str(Root.resolve()) if Root else "")
|
||||
|
||||
|
||||
def ExplorerState(Root: Path | None = None, Library: str | None = None) -> dict[str, Any]:
|
||||
"""Where a Record (by Root) or Library (by name) was left, filtered by
|
||||
what [History] says to remember."""
|
||||
Settings = _Settings()
|
||||
if not Settings["Enabled"]:
|
||||
return {}
|
||||
KeyName, KeyValue = _Key(Root, Library)
|
||||
State = next((Item for Item in _Load().get("ExplorerState", []) if Item.get(KeyName) == KeyValue), {})
|
||||
State = dict(State)
|
||||
if "Sorts" not in State and State.get("SortType"):
|
||||
State["Sorts"] = [f"Tag:{State['SortTag']}" if State["SortType"] == "Tag" and State.get("SortTag") else State["SortType"]]
|
||||
for Setting, Keys in (("RememberFilter", ["Filter"]), ("RememberSorting", ["Sorts", "SortDirection"]),
|
||||
("RememberLastDirectory", ["Directory"]), ("RememberLastSelectedFile", ["SelectedFile"])):
|
||||
if not Settings[Setting]:
|
||||
for Key in Keys:
|
||||
State.pop(Key, None)
|
||||
return State
|
||||
|
||||
|
||||
def SaveExplorerState(Root: Path | None, Library: str | None, Directory: Path | None, Filter: str,
|
||||
Sorts: list[str], Descending: bool, SelectedFile: Path | None) -> None:
|
||||
Settings = _Settings()
|
||||
if not Settings["Enabled"]:
|
||||
return
|
||||
History = _Load()
|
||||
KeyName, KeyValue = _Key(Root, Library)
|
||||
States = [Item for Item in History.get("ExplorerState", []) if Item.get(KeyName) != KeyValue]
|
||||
First = Sorts[0] if Sorts else "Name"
|
||||
State: dict[str, Any] = {KeyName: KeyValue}
|
||||
if Directory is not None:
|
||||
State["Directory"] = str(Directory)
|
||||
State.update({
|
||||
"Filter": Filter,
|
||||
"SortType": "Tag" if First.startswith("Tag:") else First,
|
||||
"SortDirection": "Descending" if Descending else "Ascending",
|
||||
"Sorts": list(Sorts),
|
||||
"Updated": _Now(),
|
||||
})
|
||||
if First.startswith("Tag:"):
|
||||
State["SortTag"] = First[4:]
|
||||
if SelectedFile is not None:
|
||||
State["SelectedFile"] = str(SelectedFile)
|
||||
History["ExplorerState"] = [State] + States[: max(0, int(Settings["MaxDirectoryHistory"]) - 1)]
|
||||
_Save(History)
|
||||
|
||||
|
||||
def RecordRecentFile(FilePath: Path) -> None:
|
||||
Settings = _Settings()
|
||||
if not (Settings["Enabled"] and Settings["RememberRecentFiles"]):
|
||||
return
|
||||
History = _Load()
|
||||
Others = [Item for Item in History.get("RecentFile", []) if Item.get("Path") != str(FilePath)]
|
||||
History["RecentFile"] = ([{"Path": str(FilePath), "Time": _Now()}] + Others)[: int(Settings["MaxFileHistory"])]
|
||||
_Save(History)
|
||||
|
||||
|
||||
def RecentFiles() -> list[Path]:
|
||||
return [Path(Item["Path"]) for Item in _Load().get("RecentFile", []) if Item.get("Path")]
|
||||
|
||||
|
||||
def UpdaterState() -> dict[str, Any]:
|
||||
Settings = _Settings()
|
||||
if not (Settings["Enabled"] and Settings["RememberUpdaterMode"]):
|
||||
return {}
|
||||
return dict(_Load().get("Updater", {}))
|
||||
|
||||
|
||||
def RecordUpdaterRun(Mode: str, DryRun: bool, Scope: str, ChangedBooks: list[Path]) -> None:
|
||||
Settings = _Settings()
|
||||
if not Settings["Enabled"]:
|
||||
return
|
||||
History = _Load()
|
||||
Now = _Now()
|
||||
if Settings["RememberUpdaterMode"]:
|
||||
History["Updater"] = {"LastMode": Mode, "LastRun": Now, "LastDryRun": DryRun, "LastScope": Scope}
|
||||
if Settings["RememberUpdates"] and ChangedBooks and not DryRun:
|
||||
New = [{"Path": str(BookPath), "Time": Now, "Mode": Mode, "DryRun": DryRun, "Scope": Scope} for BookPath in ChangedBooks]
|
||||
History["RecentUpdate"] = (New + list(History.get("RecentUpdate", [])))[: int(Settings["MaxUpdateHistory"])]
|
||||
_Save(History)
|
||||
Reference in new issue
Block a user