mirror of
https://git.srhtnin.garden/sarah/SaraSort.git
synced 2026-10-13 18:28:18 +02:00
Flowchart of inputs/outputs with editable arrows, service page (status, controls, autostart, version, logs), config editor (form + raw), templates, tools (warnings, filename tester, failed files) and settings with SaraFem-compatible export/import. AppImage build and a SaraSuite manifest in Packaging/. Co-Authored-By: Claude Opus 5.5 <[email protected]>
131 lines
4.8 KiB
Python
131 lines
4.8 KiB
Python
"""Ready-made connections ("Pictures sorting" and so on): a list of patterns
|
|
plus a few settings, installed between an input and an output you pick.
|
|
|
|
Built-ins live here. Your own are TOML files in
|
|
~/.config/SaraSuite/SaraSort/Templates/, same keys as SortTemplate:
|
|
|
|
Name = "3D prints"
|
|
Description = "Models and slicer files."
|
|
Icon = "VIEW_IN_AR"
|
|
Patterns = ["*.stl", "*.3mf"]
|
|
NewFileName = "~^" # optional; OutputDirConf.toml's default otherwise
|
|
SuggestedOutput = "~/Prints" # optional
|
|
[OutputSettings] # optional, top-level keys of the output's config
|
|
DeleteOrg = 1
|
|
[InputSettings] # optional, top-level keys of the input's config
|
|
SortDirs = 0
|
|
"""
|
|
|
|
import re
|
|
from dataclasses import asdict, dataclass, field
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
import tomlkit
|
|
|
|
from Core import UserTemplatesDir
|
|
|
|
|
|
@dataclass
|
|
class SortTemplate:
|
|
Name: str
|
|
Description: str = ""
|
|
Icon: str = "FOLDER_COPY_OUTLINED"
|
|
Patterns: list[str] = field(default_factory=list)
|
|
NewFileName: str = "" # empty: OutputDirConf.toml's default
|
|
SuggestedOutput: str = ""
|
|
OutputSettings: dict = field(default_factory=dict)
|
|
InputSettings: dict = field(default_factory=dict)
|
|
FilePath: Optional[Path] = None # set for your own templates
|
|
|
|
@property
|
|
def BuiltIn(self) -> bool:
|
|
return self.FilePath is None
|
|
|
|
|
|
BuiltInTemplates = [
|
|
SortTemplate(
|
|
"Pictures", "Photos, screenshots and other images.", "IMAGE_OUTLINED",
|
|
["*.jp*g", "*.png", "*.gif", "*.webp", "*.bmp", "*.svg", "*.heic", "*.tif*", "*.avif"],
|
|
SuggestedOutput="~/Pictures",
|
|
),
|
|
SortTemplate(
|
|
"Videos", "Video files.", "MOVIE_OUTLINED",
|
|
["*.mp4", "*.mkv", "*.webm", "*.mov", "*.avi", "*.m4v"],
|
|
SuggestedOutput="~/Videos",
|
|
),
|
|
SortTemplate(
|
|
"Music", "Audio files.", "MUSIC_NOTE_OUTLINED",
|
|
["*.mp3", "*.flac", "*.ogg", "*.opus", "*.wav", "*.m4a", "*.aac"],
|
|
SuggestedOutput="~/Music",
|
|
),
|
|
SortTemplate(
|
|
"Documents", "PDFs, office files and text.", "DESCRIPTION_OUTLINED",
|
|
["*.pdf", "*.doc*", "*.odt", "*.rtf", "*.txt", "*.md", "*.xls*", "*.ods", "*.csv", "*.ppt*", "*.odp", "*.epub"],
|
|
SuggestedOutput="~/Documents",
|
|
),
|
|
SortTemplate(
|
|
"Archives (unpacked)", "Archives, unpacked in the output and the archive removed.", "FOLDER_ZIP_OUTLINED",
|
|
["*.zip", "*.tar", "*.tar.gz", "*.tgz", "*.tar.xz", "*.tar.bz2"],
|
|
OutputSettings={"Unzip": ["zip", "tar", "tar.gz", "tgz", "tar.xz", "tar.bz2"]},
|
|
),
|
|
SortTemplate(
|
|
"Git repositories", "Folders (e.g. cloned repos) are zipped by the input, moved and unzipped in the output.",
|
|
"ACCOUNT_TREE_OUTLINED", ["*.zip"],
|
|
SuggestedOutput="~/Applications",
|
|
OutputSettings={"Unzip": ["zip"]},
|
|
InputSettings={"SortDirs": 1},
|
|
),
|
|
SortTemplate(
|
|
"Logs", "Log files, renamed with today's date in front.", "RECEIPT_LONG_OUTLINED",
|
|
["*.log", "*.log.*"], NewFileName="[y].[m].[d]_~^",
|
|
),
|
|
SortTemplate(
|
|
"3D printing", "Models, OpenSCAD files and slicer output.", "VIEW_IN_AR_OUTLINED",
|
|
["*.stl", "*.3mf", "*.scad", "*.step", "*.stp", "*.obj", "*.gcode", "*.bgcode"],
|
|
),
|
|
SortTemplate(
|
|
"Installers", "AppImages, packages and Flatpak refs.", "INSTALL_DESKTOP_OUTLINED",
|
|
["*.AppImage", "*.rpm", "*.deb", "*.flatpak", "*.flatpakref"],
|
|
),
|
|
SortTemplate(
|
|
"Backup copy", "Copies everything instead of moving it (DeleteOrg = 0).", "CONTENT_COPY_OUTLINED",
|
|
["*"], OutputSettings={"DeleteOrg": 0},
|
|
),
|
|
]
|
|
|
|
|
|
def UserTemplates() -> list[SortTemplate]:
|
|
if not UserTemplatesDir.is_dir():
|
|
return []
|
|
Found = []
|
|
Known = set(SortTemplate.__dataclass_fields__) - {"FilePath"}
|
|
for FilePath in sorted(UserTemplatesDir.glob("*.toml")):
|
|
try:
|
|
Data = tomlkit.parse(FilePath.read_text()).unwrap()
|
|
except (OSError, tomlkit.exceptions.TOMLKitError):
|
|
continue
|
|
Values = {Key: Value for Key, Value in Data.items() if Key in Known}
|
|
Values.setdefault("Name", FilePath.stem)
|
|
Found.append(SortTemplate(**Values, FilePath=FilePath))
|
|
return Found
|
|
|
|
|
|
def AllTemplates() -> list[SortTemplate]:
|
|
return BuiltInTemplates + UserTemplates()
|
|
|
|
|
|
def SaveUserTemplate(Template: SortTemplate) -> Path:
|
|
UserTemplatesDir.mkdir(parents=True, exist_ok=True)
|
|
FileName = re.sub(r"[^A-Za-z0-9]+", "", Template.Name.title()) or "Template"
|
|
FilePath = UserTemplatesDir / f"{FileName}.toml"
|
|
Data = {Key: Value for Key, Value in asdict(Template).items() if Key != "FilePath" and Value not in ("", {}, [])}
|
|
Data["Patterns"] = Template.Patterns
|
|
FilePath.write_text(tomlkit.dumps(Data))
|
|
return FilePath
|
|
|
|
|
|
def DeleteUserTemplate(Template: SortTemplate) -> None:
|
|
if Template.FilePath:
|
|
Template.FilePath.unlink(missing_ok=True)
|