mirror of
https://git.srhtnin.garden/sarah/SaraSortd.git
synced 2026-10-15 02:53:17 +02:00
It works! Sorry for lack of pushes. :p
This commit is contained in:
1 parent
bb2056ed68
commit
3b06574b62
4 files changed
+199
-85
No files matched your search
+10
-9
@@ -2,10 +2,10 @@ Title = "SaraSortd Config"
|
|||||||
SafeMode = 1
|
SafeMode = 1
|
||||||
SilentMode = 0
|
SilentMode = 0
|
||||||
CheckInput = 10
|
CheckInput = 10
|
||||||
OutputDir = [ "Log",]
|
DotFiles = 1
|
||||||
|
|
||||||
[Variables]
|
[Variables]
|
||||||
NextNum = "*"
|
NextNum = "!"
|
||||||
NextChar = "&"
|
NextChar = "&"
|
||||||
Parent = "@"
|
Parent = "@"
|
||||||
OrgFileName = "~"
|
OrgFileName = "~"
|
||||||
@@ -20,20 +20,21 @@ VarCall = "%%"
|
|||||||
|
|
||||||
[DirectoryPaths]
|
[DirectoryPaths]
|
||||||
RootDir = "/home/sarah/TESTDIR"
|
RootDir = "/home/sarah/TESTDIR"
|
||||||
InputDir = [ "%RootDir%",]
|
InputDir = [ "%RootDir%"]
|
||||||
OutputDir = [ "%RootDir%/Output",]
|
OutputDir = [ "%RootDir%/Output"]
|
||||||
LogDir = "%RootDir%/.Logs"
|
LogDir = "%RootDir%/.Logs"
|
||||||
FailedDir = "%RootDir%/.Failed"
|
FailedDir = "%RootDir%/.Failed"
|
||||||
|
|
||||||
[Names]
|
[Names]
|
||||||
LogFileName = "[y].[m].[d]._*"
|
LogFileName = "[y].[m].[d]._!"
|
||||||
DirConfName = ".@Config"
|
DirConfName = ".@Config"
|
||||||
|
|
||||||
[Log]
|
[Log]
|
||||||
All = "[h]:[n]:[s] | "
|
All = "[h]:[n]:[s] | "
|
||||||
Start = "Started: SaraSortd"
|
Start = "Started SaraSortd."
|
||||||
NotStart = "Error: Failed to start SaraSortd."
|
NotStart = "Error: Failed to start SaraSortd."
|
||||||
Sorted = "Sorted: %% to %%."
|
MatchPattern = "Checking %%."
|
||||||
ValueSet = "Set: %% to be %% in %%."
|
Sorted = "Sorted %%."
|
||||||
WrongType = "Error: %% is not a %%."
|
NotSorted = "Error: Failed to sort %%. No valid output directory."
|
||||||
|
ValueSet = "Set %%."
|
||||||
Unset = "Error: %% is not set."
|
Unset = "Error: %% is not set."
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
Title = "Unset"
|
Title = "Unset"
|
||||||
|
|
||||||
Files = [
|
Files = [
|
||||||
{Pattern = "?", NewFileName = "~^", NextNum = 1, NextChar = "A"},
|
{Pattern = "*.png", NewFileName = "~^", NextNum = 1, NextChar = "A"},
|
||||||
]
|
]
|
||||||
|
|
||||||
LastFile = "Unset"
|
LastFile = "Unset"
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ Title = "Unset" # NOTE: Do not change the title.
|
|||||||
Files = [
|
Files = [
|
||||||
{Pattern = "?", NewFileName = "~^", NextNum = 1, NextChar = "A"},
|
{Pattern = "?", NewFileName = "~^", NextNum = 1, NextChar = "A"},
|
||||||
]
|
]
|
||||||
# Pattern: the pattern used to sort files here. ? is a wildcard.
|
# Pattern: the pattern used to sort files here. * is a wildcard, ? is a one-character wildcard.
|
||||||
# E.G: if Pattern is "?.png", all files ending with .png will end up here.
|
# E.G: if Pattern is "*.png", all files ending with .png will end up here.
|
||||||
|
|
||||||
# NewFileName: the pattern for the new names of the files that get sorted here.
|
# NewFileName: the pattern for the new names of the files that get sorted here.
|
||||||
|
|
||||||
|
|||||||
+186
-73
@@ -1,4 +1,6 @@
|
|||||||
import toml, os, datetime, re, shutil
|
import toml, os, datetime, re, shutil, fnmatch, time
|
||||||
|
|
||||||
|
ConfPath = "./Config.toml"
|
||||||
|
|
||||||
Conf = None
|
Conf = None
|
||||||
ConfVars = None
|
ConfVars = None
|
||||||
@@ -15,10 +17,10 @@ def Clear():
|
|||||||
os.system('clear')
|
os.system('clear')
|
||||||
|
|
||||||
|
|
||||||
def LoadConf():
|
def LoadGlobalConf():
|
||||||
global Conf, ConfVars, ConfDirs, ConfNames, ConfLog
|
global Conf, ConfVars, ConfDirs, ConfNames, ConfLog
|
||||||
|
|
||||||
LocalConf = toml.load("Config.toml")
|
LocalConf = toml.load(ConfPath)
|
||||||
Conf = LocalConf
|
Conf = LocalConf
|
||||||
ConfVars = Conf["Variables"]
|
ConfVars = Conf["Variables"]
|
||||||
ConfDirs = Conf["DirectoryPaths"]
|
ConfDirs = Conf["DirectoryPaths"]
|
||||||
@@ -26,44 +28,34 @@ def LoadConf():
|
|||||||
ConfLog = Conf["Log"]
|
ConfLog = Conf["Log"]
|
||||||
|
|
||||||
|
|
||||||
def CheckConf():
|
def CheckConf(Path = ConfPath):
|
||||||
for Parameter, Value in ConfVars.items():
|
ConfData = toml.load(Path)
|
||||||
if (Value == None or Value == "Unset"):
|
|
||||||
TextOutput = Parse(ConfLog["Unset"], Parameter)
|
|
||||||
LogWrite(TextOutput)
|
|
||||||
Speak(TextOutput)
|
|
||||||
Error()
|
|
||||||
|
|
||||||
for Parameter, Value in ConfDirs.items():
|
def CheckDict(Data):
|
||||||
if (Value == None or Value == "Unset"):
|
for Key, Value in Data.items():
|
||||||
TextOutput = Parse(ConfLog["Unset"], Parameter)
|
if isinstance(Value, dict):
|
||||||
LogWrite(TextOutput)
|
CheckDict(Value)
|
||||||
Speak(TextOutput)
|
else:
|
||||||
Error()
|
if Value is None or Value == "Unset":
|
||||||
|
TextOutput = Parse(String = ConfLog["Unset"], Path = Path, VarCall = Key)
|
||||||
|
LogWrite(TextOutput)
|
||||||
|
Speak(TextOutput)
|
||||||
|
Error()
|
||||||
|
|
||||||
for Parameter, Value in ConfNames.items():
|
CheckDict(ConfData)
|
||||||
if (Value == None or Value == "Unset"):
|
|
||||||
TextOutput = Parse(ConfLog["Unset"], Parameter)
|
|
||||||
LogWrite(TextOutput)
|
|
||||||
Speak(TextOutput)
|
|
||||||
Error()
|
|
||||||
|
|
||||||
for Parameter, Value in ConfLog.items():
|
|
||||||
if (Value == None or Value == "Unset"):
|
|
||||||
TextOutput = Parse(ConfLog["Unset"], Parameter)
|
|
||||||
LogWrite(TextOutput)
|
|
||||||
Speak(TextOutput)
|
|
||||||
Error()
|
|
||||||
|
|
||||||
|
|
||||||
def GetConf(Parameter):
|
def GetConf(Parameter, *Paths):
|
||||||
if Parameter in Conf:
|
for Path in Paths:
|
||||||
return (Conf[Parameter])
|
ConfData = toml.load(Path)
|
||||||
|
|
||||||
for Key, Value in Conf.items():
|
if Parameter in ConfData:
|
||||||
if (isinstance(Value, dict)):
|
return (ConfData[Parameter])
|
||||||
if (Parameter in Value):
|
|
||||||
return Value[Parameter]
|
for Key, Value in ConfData.items():
|
||||||
|
if (isinstance(Value, dict)):
|
||||||
|
if (Parameter in Value):
|
||||||
|
return Value[Parameter]
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -71,24 +63,41 @@ def GetConf(Parameter):
|
|||||||
def UpdateConf(Path, Parameter, Value, Append = False):
|
def UpdateConf(Path, Parameter, Value, Append = False):
|
||||||
ConfData = toml.load(Path)
|
ConfData = toml.load(Path)
|
||||||
|
|
||||||
if (not Append):
|
Section = None
|
||||||
ConfData[Parameter] = Value
|
for Table, Data in ConfData.items():
|
||||||
|
if (isinstance(Data, dict) and Parameter in Data):
|
||||||
|
Section = Table
|
||||||
|
break
|
||||||
|
|
||||||
|
if (Section == None):
|
||||||
|
TargetData = ConfData
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if (Parameter not in ConfData):
|
TargetData = ConfData[Section]
|
||||||
ConfData[Parameter] = []
|
|
||||||
|
|
||||||
elif (not isinstance(ConfData[Parameter], list)):
|
if (not Append):
|
||||||
TextOutput = Parse(ConfLog["WrongType"], Parameter, "list")
|
TargetData[Parameter] = Value
|
||||||
LogWrite(TextOutput)
|
|
||||||
Speak(TextOutput)
|
|
||||||
|
|
||||||
if (Value not in ConfData[Parameter]):
|
else:
|
||||||
ConfData[Parameter].append(Value)
|
if (Parameter not in TargetData):
|
||||||
|
TargetData[Parameter] = []
|
||||||
|
|
||||||
|
if (Value not in TargetData[Parameter]):
|
||||||
|
TargetData[Parameter].append(Value)
|
||||||
|
|
||||||
|
if (Section == None):
|
||||||
|
ConfData = TargetData
|
||||||
|
|
||||||
|
else:
|
||||||
|
ConfData[Section] = TargetData
|
||||||
|
|
||||||
with open(Path, 'w', encoding='utf-8') as File:
|
with open(Path, 'w', encoding='utf-8') as File:
|
||||||
toml.dump(ConfData, File)
|
toml.dump(ConfData, File)
|
||||||
|
|
||||||
|
TextOutput = Parse(String = ConfLog["ValueSet"], VarCall = f"{Parameter} to {Value}")
|
||||||
|
LogWrite(TextOutput)
|
||||||
|
Speak(TextOutput)
|
||||||
|
|
||||||
|
|
||||||
def Error():
|
def Error():
|
||||||
global Start
|
global Start
|
||||||
@@ -101,36 +110,47 @@ def Speak(Text):
|
|||||||
print(Text)
|
print(Text)
|
||||||
|
|
||||||
|
|
||||||
def Parse(String = None, Var = None, Path = None):
|
def Parse(String = None, Path = ConfPath,
|
||||||
|
NextNum = None,
|
||||||
|
NextChar = None,
|
||||||
|
Parent = None,
|
||||||
|
OrgFile = None,
|
||||||
|
VarCall = None):
|
||||||
|
|
||||||
def Replacer(Match):
|
def Replacer(Match):
|
||||||
Content = Match.group(1)
|
Content = Match.group(1)
|
||||||
|
|
||||||
if (Content == None or Content == ""):
|
if (Content == None or Content == ""):
|
||||||
if (Var != None):
|
if (VarCall != None):
|
||||||
return str(Var)
|
return str(VarCall)
|
||||||
else:
|
else:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
Value = GetConf(Content)
|
Value = GetConf(Content, Path)
|
||||||
if (Value != None):
|
if (Value != None):
|
||||||
return Value
|
return Value
|
||||||
|
|
||||||
|
|
||||||
Now = datetime.datetime.now()
|
Now = datetime.datetime.now()
|
||||||
|
if (OrgFile != None):
|
||||||
|
OrgFileName, OrgFileType = os.path.splitext(OrgFile)
|
||||||
|
else:
|
||||||
|
OrgFileName = None
|
||||||
|
OrgFileType = None
|
||||||
|
|
||||||
VarValues = {
|
VarValues = {
|
||||||
ConfVars["NextNum"]: "NOT ADDED",
|
ConfVars["NextNum"]: NextNum,
|
||||||
ConfVars["NextChar"]: "NOT ADDED",
|
ConfVars["NextChar"]: NextChar,
|
||||||
ConfVars["Parent"]: Var,
|
ConfVars["Parent"]: Parent,
|
||||||
ConfVars["OrgFileName"]: Var,
|
ConfVars["OrgFileName"]: OrgFileName,
|
||||||
ConfVars["OrgFileType"]: Var,
|
ConfVars["OrgFileType"]: OrgFileType,
|
||||||
ConfVars["Year"]: str(Now.year),
|
ConfVars["Year"]: str(Now.year),
|
||||||
ConfVars["Month"]: str(Now.month),
|
ConfVars["Month"]: str(Now.month),
|
||||||
ConfVars["Day"]: str(Now.day),
|
ConfVars["Day"]: str(Now.day),
|
||||||
ConfVars["Hour"]: str(Now.hour),
|
ConfVars["Hour"]: str(Now.hour),
|
||||||
ConfVars["Minute"]: str(Now.minute),
|
ConfVars["Minute"]: str(Now.minute),
|
||||||
ConfVars["Second"]: str(Now.second),
|
ConfVars["Second"]: str(Now.second),
|
||||||
ConfVars["VarCall"]: Var
|
ConfVars["VarCall"]: VarCall
|
||||||
}
|
}
|
||||||
|
|
||||||
for Key, Value in VarValues.items():
|
for Key, Value in VarValues.items():
|
||||||
@@ -146,52 +166,126 @@ def Parse(String = None, Var = None, Path = None):
|
|||||||
return String
|
return String
|
||||||
|
|
||||||
|
|
||||||
def Clone(Source, Destination, NewName):
|
def Clone(Source, Destination, NewName, Delete = False):
|
||||||
shutil.copy(Source, Destination)
|
Dir(Destination, Output = False, CopyConf = False)
|
||||||
|
shutil.copy2(Source, Destination)
|
||||||
|
|
||||||
NewPath = f"{Destination}/{NewName}"
|
BaseName = os.path.basename(Source)
|
||||||
shutil.move(f"{Destination}/{Source}", NewPath)
|
shutil.move(os.path.join(Destination, BaseName), os.path.join(Destination, NewName))
|
||||||
|
|
||||||
|
if (Delete):
|
||||||
|
os.remove(Source)
|
||||||
|
|
||||||
|
|
||||||
def Dir(Path, Output = True, CopyConf = True):
|
def Dir(Path, Output = True, CopyConf = True):
|
||||||
ParentName = os.path.basename(os.path.dirname(Path))
|
ParentName = os.path.basename(Path)
|
||||||
os.makedirs(Path, exist_ok=True)
|
os.makedirs(Path, exist_ok=True)
|
||||||
|
|
||||||
if (CopyConf):
|
if (CopyConf):
|
||||||
Clone("DirConfig.toml", Path, f"{Parse(ConfNames["DirConfName"], ParentName)}.toml")
|
Clone("DirConfig.toml", Path, f"{Parse(String = ConfNames["DirConfName"], Path = ConfPath, Parent = ParentName)}.toml")
|
||||||
|
|
||||||
UpdateConf(f"{Path}/{Parse(ConfNames["DirConfName"], ParentName)}.toml", "ParentDir", ParentName)
|
UpdateConf(f"{Path}/{Parse(String = ConfNames["DirConfName"], Path = ConfPath, Parent = ParentName)}.toml", "ParentDir", ParentName)
|
||||||
UpdateConf(f"{Path}/{Parse(ConfNames["DirConfName"], ParentName)}.toml", "Title", f"{ParentName} Config")
|
UpdateConf(f"{Path}/{Parse(String = ConfNames["DirConfName"], Path = ConfPath, Parent = ParentName)}.toml", "Title", f"{ParentName} Config")
|
||||||
|
|
||||||
if (Output):
|
if (Output):
|
||||||
UpdateConf("Config.toml", "OutputDir", Output, True)
|
ParsedPath = Parse(String = Path)
|
||||||
|
ParsedOutputs = [Parse(String = Dir) for Dir in ConfDirs["OutputDir"]]
|
||||||
|
if (ParsedPath not in ParsedOutputs):
|
||||||
|
UpdateConf(ConfPath, "OutputDir", Path, True)
|
||||||
|
|
||||||
|
|
||||||
def LogWrite(Text):
|
def LogWrite(Text):
|
||||||
if (ConfDirs["LogDir"] != None and ConfNames != "Unset"):
|
if (ConfDirs["LogDir"] != None and ConfNames != "Unset"):
|
||||||
if (ConfNames["LogFileName"] != None and ConfNames["LogFileName"] != "Unset"):
|
if (ConfNames["LogFileName"] != None and ConfNames["LogFileName"] != "Unset"):
|
||||||
Dir(Parse(ConfDirs["LogDir"]), "Log")
|
Dir(Parse(String = ConfDirs["LogDir"], Path = ConfPath), Output = False, CopyConf = False)
|
||||||
LogFile = f"{Parse(ConfDirs["LogDir"])}/{Parse(ConfNames["LogFileName"])}.log"
|
LogFile = f"{Parse(String = ConfDirs["LogDir"], Path = ConfPath)}/{Parse(String = ConfNames["LogFileName"], Path = ConfPath)}.log"
|
||||||
with open(LogFile, "w", encoding="utf-8") as File:
|
with open(LogFile, "a", encoding="utf-8", buffering=1) as File:
|
||||||
File.write(f"{Parse(ConfLog["All"])}{Text}\n")
|
File.write(f"{Parse(String = ConfLog["All"], Path = ConfPath)}{Text}\n")
|
||||||
|
|
||||||
|
|
||||||
|
def DecideNewPath(FilePath):
|
||||||
|
UnsortedFile = os.path.basename(FilePath)
|
||||||
|
|
||||||
|
for Output in ConfDirs["OutputDir"]:
|
||||||
|
Output = Parse(String = Output, Path = ConfPath)
|
||||||
|
|
||||||
|
ParentName = os.path.basename(Output)
|
||||||
|
|
||||||
|
DirConfName = Parse(String = ConfNames["DirConfName"], Path = ConfPath, Parent = ParentName)
|
||||||
|
DirConfPath = f"{Output}/{DirConfName}.toml"
|
||||||
|
|
||||||
|
if not os.path.exists(DirConfPath):
|
||||||
|
continue
|
||||||
|
|
||||||
|
FileConf = GetConf("Files", DirConfPath)
|
||||||
|
|
||||||
|
if not FileConf:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for File in FileConf:
|
||||||
|
Pattern = File["Pattern"]
|
||||||
|
|
||||||
|
TextOutput = Parse(ConfLog["MatchPattern"], VarCall = f"{UnsortedFile} against {Pattern}")
|
||||||
|
LogWrite(TextOutput)
|
||||||
|
Speak(TextOutput)
|
||||||
|
|
||||||
|
if fnmatch.fnmatch(UnsortedFile, Pattern):
|
||||||
|
NewFileName = File["NewFileName"]
|
||||||
|
NewFileName = Parse(String = NewFileName, Path = DirConfPath, OrgFile = UnsortedFile)
|
||||||
|
return f"{Output}/{NewFileName}"
|
||||||
|
|
||||||
|
|
||||||
|
def Sort(FilePath):
|
||||||
|
NewPath = DecideNewPath(FilePath)
|
||||||
|
|
||||||
|
if (NewPath == None):
|
||||||
|
Dir(Parse(String = ConfDirs["FailedDir"]), Output = False, CopyConf = False)
|
||||||
|
NewName = os.path.basename(FilePath)
|
||||||
|
Clone(FilePath, Parse(String = ConfDirs["FailedDir"]), NewName, True)
|
||||||
|
return
|
||||||
|
|
||||||
|
NewDirPath = os.path.dirname(NewPath)
|
||||||
|
|
||||||
|
NextNum = GetConf("NextNum", f"{NewDirPath}/{Parse(String = ConfNames["DirConfName"], Parent = os.path.basename(NewDirPath))}.toml")
|
||||||
|
NextChar = GetConf("NextChar", f"{NewDirPath}/{Parse(String = ConfNames["DirConfName"], Parent = os.path.basename(NewDirPath))}.toml")
|
||||||
|
|
||||||
|
NewName = Parse(os.path.basename(FilePath), NextNum = NextNum, NextChar = NextChar)
|
||||||
|
|
||||||
|
try:
|
||||||
|
Clone(FilePath, NewDirPath, NewName, True)
|
||||||
|
|
||||||
|
TextOutput = Parse(String = ConfLog["Sorted"], VarCall = f"{FilePath} to {NewDirPath}/{NewName}")
|
||||||
|
LogWrite(TextOutput)
|
||||||
|
Speak(TextOutput)
|
||||||
|
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
Dir(Parse(String = ConfDirs["FailedDir"]), Output = False, CopyConf = False)
|
||||||
|
NewName = os.path.basename(FilePath)
|
||||||
|
Clone(FilePath, Parse(String = ConfDirs["FailedDir"]), NewName, True)
|
||||||
|
|
||||||
|
TextOutput = Parse(String = ConfLog["NotSorted"], VarCall = FilePath)
|
||||||
|
LogWrite(TextOutput)
|
||||||
|
Speak(TextOutput)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
def Init():
|
def Init():
|
||||||
global Conf, ConfVars, ConfDirs, ConfNames, ConfLog
|
global Conf, ConfVars, ConfDirs, ConfNames, ConfLog
|
||||||
|
|
||||||
LoadConf()
|
LoadGlobalConf()
|
||||||
if (Conf != None):
|
if (Conf != None):
|
||||||
CheckConf()
|
CheckConf()
|
||||||
|
|
||||||
if (Start):
|
if (Start):
|
||||||
TextOutput = Parse(ConfLog["Start"])
|
TextOutput = Parse(String = ConfLog["Start"], Path = ConfPath)
|
||||||
LogWrite(TextOutput)
|
LogWrite(TextOutput)
|
||||||
Speak(TextOutput)
|
Speak(TextOutput)
|
||||||
|
|
||||||
Main()
|
Main()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
TextOutput = Parse(ConfLog["NotStart"])
|
TextOutput = Parse(String = ConfLog["NotStart"])
|
||||||
LogWrite(TextOutput)
|
LogWrite(TextOutput)
|
||||||
Speak(TextOutput)
|
Speak(TextOutput)
|
||||||
|
|
||||||
@@ -200,8 +294,27 @@ def Init():
|
|||||||
|
|
||||||
|
|
||||||
def Main():
|
def Main():
|
||||||
|
for Output in ConfDirs["OutputDir"]:
|
||||||
|
Output = Parse(String = Output)
|
||||||
|
Dir(Output)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
pass
|
for Input in ConfDirs["InputDir"]:
|
||||||
|
InputPath = Parse(Input)
|
||||||
|
|
||||||
|
if not os.path.exists(InputPath):
|
||||||
|
continue
|
||||||
|
|
||||||
|
for FileName in os.listdir(InputPath):
|
||||||
|
FilePath = os.path.join(InputPath, FileName)
|
||||||
|
|
||||||
|
if os.path.isfile(FilePath):
|
||||||
|
FileName = os.path.basename(FilePath)
|
||||||
|
if (FileName.startswith(".") and Conf["DotFiles"] == 0):
|
||||||
|
continue
|
||||||
|
Sort(FilePath)
|
||||||
|
|
||||||
|
time.sleep(Conf.get("CheckInput", 10))
|
||||||
|
|
||||||
|
|
||||||
Init()
|
Init()
|
||||||
Reference in new issue
Block a user