Skip to content

Instantly share code, notes, and snippets.

@kubinka0505
Created June 29, 2022 08:52
Show Gist options
  • Save kubinka0505/000b77ae8b33be086d271ad067343ada to your computer and use it in GitHub Desktop.
Save kubinka0505/000b77ae8b33be086d271ad067343ada to your computer and use it in GitHub Desktop.
Automatic script for Gothic saves backup.
"""Gothic Saves Backup
Automatic script for Gothic saves backup."""
from os import *
from tkinter import *
from zipfile import *
from pathlib import Path
from shutil import rmtree
from tkinter import filedialog as fd
from distutils.dir_util import copy_tree
del open
#-=-=-=-#
__author__ = "kubinka0505"
__credits__ = __author__
__version__ = "1.0"
__date__ = "29.06.2022"
#-=-=-=-=-=-#
# Game location
#
# Gothic I - r"C:/Program Files (x86)/Piranha Bytes/Gothic"
# Gothic II - r"C:/Program Files (x86)/JoWood/Gothic II Zlota Edycja"
Game = r"C:/Program Files (x86)/JoWood/Gothic II Zlota Edycja"
# Saveslot number
#
# "savegameX", where X is number (10 stands for "savegame10" etc.)
Save_Slot = 10
Output_Directory = r"~/Documents/Gothic_Saves_Backup"
# Keep first unnamed savegame
#
# True if first savegame named "---" will be archived, False for last
Keep_First = True
#-=-=-=-=-=-#
def Clamp(Number: float, Minimum: float, Maximum: float) -> float:
"""Limits `Number` in range (`Minimum`, `Maximum`)."""
return max(min(Maximum, Number), Minimum)
def Path(Path: str):
"""Resolves path using `pathlib.Path.resolve`."""
return str(Path.resolve())
#-=-=-=-#
root = Tk()
root.withdraw()
Counter = 0
Saves_Folders = []
Sorted_Saves = {"Main": {}, "Cleared": {}}
Save_Slot = str(Clamp(Save_Slot), 1, 20)
Output_Directory = path.expanduser(Output_Directory)
Game = NormPath(Game)
chdir(Game)
#-=-=-=-#
# Find latest save folder
for Folder in Path(Game).glob("*"):
Folder = NormPath(Folder).lower()
#-=-=-=-#
if "saves_" in Folder:
Saves_Folders.append(Folder.split(sep)[-1])
Saves_Folders = sorted(Saves_Folders, key = path.getmtime)
Latest_Save_Folder = Saves_Folders[-1]
# Select folder
Save_Folder = fd.askdirectory(
title = "Open saves directory",
initialdir = path.abspath(Latest_Save_Folder)
)
Save_Folder = path.basename(Save_Folder).split("saves_")[-1]
# Go to output directory
Output_Directory = NormPath(
path.join(
Output_Directory,
Save_Folder
)
)
print(f'Output directory is "{Output_Directory}"')
print(f'Game directory is "{Game}"')
# Remove existing saves
if path.exists(Output_Directory):
print(f'\nRemoving existing "{path.basename(Save_Folder)}" saves...')
rmtree(Output_Directory)
else:
makedirs(Output_Directory)
# Copy saves
try:
copy_tree("saves_" + Save_Folder, Output_Directory)
print("Copied saves")
except OSError:
raise SystemExit("File selection aborted")
chdir(Output_Directory)
# Remove "current" directory
try:
rmtree("current")
except OSError:
pass
# Get save states names
for Folder in next(walk("."))[1][::1 if Keep_First else -1]:
File = path.abspath(path.join(Folder, "SaveInfo.sav"))
File = open(File).read()
Sorted_Saves["Main"][
File.split("Title=string:")[-1].split("\n")[0]
] = Folder
# Remove duplicate savestates with "---" name
for Key, Value in Sorted_Saves["Main"].items():
if Value not in Sorted_Saves["Cleared"].values():
Sorted_Saves["Cleared"][Key] = Value
# Copy saves to named folders
for Key, Value in Sorted_Saves["Cleared"].items():
mkdir(Key)
copy_tree(
Value,
Key.replace("_", " ").title() + "/savegame" + Save_Slot
)
rmtree(Value)
# Remove junk
for Folder in next(walk("."))[1]:
if Folder not in Sorted_Saves["Cleared"].keys():
rmtree(Folder)
# Making archives
print("\nMaking archives...")
try:
for Folder in next(walk("."))[1]:
Counter += 1
print(
"\t",
f"[{Counter}/{len(listdir())}]",
f"\t\t{Folder}",
"\t" * 3,
#-=-=-=-#
end = "\r"
)
#-=-=-=-#
with ZipFile(Folder + ".zip", "w", ZIP_DEFLATED, 0, 9) as ZIP:
for File in Path(Folder).glob("**/*"):
ZIP.write(File)
rmtree(Folder)
except (KeyboardInterrupt, EOFError):
raise SystemExit("Making archives aborted")
# Open containing directory
print("Done!\a")
system(fr'start /max C:\Windows\explorer.exe "{Output_Directory}"')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment