Files

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)