mirror of
https://git.srhtnin.garden/sarah/SaraTag.git
synced 2026-10-13 18:28:16 +02:00
133 lines
5.3 KiB
Python
133 lines
5.3 KiB
Python
"""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)
|