Compare commits

..

10 Commits

Author SHA1 Message Date
Profitroll
7a2c28d2d9 Updated ignore 2023-01-29 17:05:46 +01:00
Profitroll
217c1c4691 Fixed folder removal technique 2023-01-29 17:04:58 +01:00
Profitroll
ac8b60c775 Changed saves fetching 2023-01-29 12:30:40 +01:00
Profitroll
fba043a052 Got tired of re-downloading reqs all the time 2023-01-29 12:30:19 +01:00
Profitroll
3bab4faa46 Changed run tasks behavior 2023-01-29 11:06:23 +01:00
Profitroll
e631d1717e Fixed dirs in tasks 2023-01-28 18:50:40 +01:00
Profitroll
b39a0253d1 Updated tasks even more 2023-01-28 18:45:57 +01:00
Profitroll
3bae2b646a Updated ignores 2023-01-28 18:35:39 +01:00
Profitroll
76cbf53789 New project tree 2023-01-28 17:50:19 +01:00
Profitroll
fb53eec810 Updated tasks for new project tree 2023-01-28 17:50:11 +01:00
47 changed files with 321 additions and 161 deletions

7
.gitignore vendored
View File

@@ -165,9 +165,14 @@ cython_debug/
# Built Visual Studio Code Extensions # Built Visual Studio Code Extensions
*.vsix *.vsix
# InstallForge projects
*.ifp
# Project # Project
venv venv
buildif buildif
buildenv buildenv
sv_ttk sv_ttk
distassets distassets
testbinary
testpython

92
.vscode/tasks.json vendored
View File

@@ -5,6 +5,7 @@
"tasks": [ "tasks": [
{ {
"label": "Clean up", "label": "Clean up",
"detail": "Remove all .pyco and and __pycache__ in the whole project",
"type": "shell", "type": "shell",
"windows": { "windows": {
"command": "./.vscode/tasks/windows/cleanup.bat" "command": "./.vscode/tasks/windows/cleanup.bat"
@@ -16,6 +17,7 @@
}, },
{ {
"label": "Clean up everything", "label": "Clean up everything",
"detail": "Remove all .pyco and __pycache__ as well as virtual envs, build and dist dirs",
"type": "shell", "type": "shell",
"windows": { "windows": {
"command": "./.vscode/tasks/windows/cleanup_everything.bat" "command": "./.vscode/tasks/windows/cleanup_everything.bat"
@@ -23,36 +25,81 @@
"linux": { "linux": {
"command": "bash ./.vscode/tasks/linux/cleanup_everything.sh" "command": "bash ./.vscode/tasks/linux/cleanup_everything.sh"
}, },
"problemMatcher": [] "problemMatcher": [],
"dependsOn": ["Clean up"]
}, },
{ {
"label": "Build", "label": "Run (Python) [Dirty]",
"detail": "Remove all cache files and start main.py within venv",
"type": "shell", "type": "shell",
"windows": { "windows": {
"command": "./.vscode/tasks/windows/build.bat" "command": "./.vscode/tasks/windows/run_python.bat"
}, },
"linux": { "linux": {
"command": "bash ./.vscode/tasks/linux/build.sh" "command": "bash ./.vscode/tasks/linux/run_python.sh"
},
"group": {
"kind": "test",
"isDefault": true
}, },
"problemMatcher": [], "problemMatcher": [],
"group": { "dependsOn": ["Clean up"]
"kind": "build",
"isDefault": true
}
}, },
{ {
"label": "Test", "label": "Run (Python) [Clean]",
"detail": "Needs to be ran before the dirty version can be used. Copy source code from 'src' dir into 'testpython', install requirements and start main.py within venv",
"type": "shell", "type": "shell",
"windows": { "windows": {
"command": "./.vscode/tasks/windows/test.bat" "command": "./.vscode/tasks/windows/flush_and_run_python.bat"
}, },
"linux": { "linux": {
"command": "bash ./.vscode/tasks/linux/test.sh" "command": "bash ./.vscode/tasks/linux/flush_and_run_python.sh"
}, },
"problemMatcher": [] "group": {
"kind": "test",
"isDefault": true
},
"problemMatcher": [],
"dependsOn": ["Clean up"]
//, "Install requirements"]
},
{
"label": "Run (Binary) [Dirty]",
"detail": "Copy compiled binaries from 'dest/%os%' dir into 'testbinary/%os%' and start it",
"type": "shell",
"windows": {
"command": "./.vscode/tasks/windows/run_binary.bat"
},
"linux": {
"command": "bash ./.vscode/tasks/linux/run_binary.sh"
},
"group": {
"kind": "test",
"isDefault": false
},
"problemMatcher": [],
"dependsOn": ["Build"]
},
{
"label": "Run (Binary) [Clean]",
"detail": "Needs to be ran before the dirty version can be used. Copy compiled binaries from 'dest/%os%' dir into 'testbinary/%os%' and start it",
"type": "shell",
"windows": {
"command": "./.vscode/tasks/windows/flush_and_run_binary.bat"
},
"linux": {
"command": "bash ./.vscode/tasks/linux/flush_and_run_binary.sh"
},
"group": {
"kind": "test",
"isDefault": false
},
"problemMatcher": [],
"dependsOn": ["Build"]
}, },
{ {
"label": "Configure Setup", "label": "Configure Setup",
"detail": "Configure IF setup file on Windows and .deb package on Linux",
"type": "shell", "type": "shell",
"windows": { "windows": {
"command": "./.vscode/tasks/windows/configure_setup.bat" "command": "./.vscode/tasks/windows/configure_setup.bat"
@@ -60,10 +107,12 @@
"linux": { "linux": {
"command": "echo \"Not implemented\"" "command": "echo \"Not implemented\""
}, },
"problemMatcher": [] "problemMatcher": [],
"dependsOn": ["Clean up"]
}, },
{ {
"label": "Install build requirements", "label": "Install build requirements",
"detail": "Create buildenv and install the modules to run Pyinstaller's build",
"type": "shell", "type": "shell",
"windows": { "windows": {
"command": "./.vscode/tasks/windows/install_build_requirements.bat" "command": "./.vscode/tasks/windows/install_build_requirements.bat"
@@ -75,6 +124,7 @@
}, },
{ {
"label": "Install requirements", "label": "Install requirements",
"detail": "Create venv and install the modules to run 'src/main.py'",
"type": "shell", "type": "shell",
"windows": { "windows": {
"command": "./.vscode/tasks/windows/install_requirements.bat" "command": "./.vscode/tasks/windows/install_requirements.bat"
@@ -85,15 +135,21 @@
"problemMatcher": [] "problemMatcher": []
}, },
{ {
"label": "Run", "label": "Build",
"detail": "Configure .spec and run Pyinstaller",
"type": "shell", "type": "shell",
"windows": { "windows": {
"command": "./.vscode/tasks/windows/run.bat" "command": "./.vscode/tasks/windows/build.bat"
}, },
"linux": { "linux": {
"command": "bash ./.vscode/tasks/linux/run.sh" "command": "bash ./.vscode/tasks/linux/build.sh"
}, },
"problemMatcher": [] "problemMatcher": [],
} "dependsOn": ["Clean up", "Install build requirements"],
"group": {
"kind": "build",
"isDefault": true
}
},
] ]
} }

View File

@@ -2,4 +2,4 @@
rm -rf dist/linux/StardewSync rm -rf dist/linux/StardewSync
source buildenv/bin/activate && pyi-makespec main.py -n "StardewSync" -p "buildenv" -i "assets/favicon.ico" --add-data "config.json:." --add-data "assets:assets" --add-data "buildenv/lib/python3.9/site-packages/sv_ttk/sv.tcl:sv_ttk/" --add-data "buildenv/lib/python3.9/site-packages/sv_ttk/theme/*:sv_ttk/theme/" --noconsole && pyinstaller "StardewSync.spec" --noconfirm --distpath=dist/linux --workpath=build/linux source buildenv/bin/activate && pyi-makespec ./src/main.py -n "StardewSync" -p "buildenv" -i "./src/assets/favicon.ico" --add-data "./src/config.json:." --add-data "./src/assets:assets" --add-data "buildenv/lib/python3.9/site-packages/sv_ttk/sv.tcl:sv_ttk/" --add-data "buildenv/lib/python3.9/site-packages/sv_ttk/theme/*:sv_ttk/theme/" --noconsole && pyinstaller "StardewSync.spec" --noconfirm --distpath=dist/linux --workpath=build/linux

View File

@@ -1,13 +1,6 @@
#!/bin/bash #!/bin/bash
python3 -Bc "import pathlib; [p.unlink() for p in pathlib.Path('.').rglob('*.py[co]')]" rm -rf ./build
python3 -Bc "import pathlib; [p.rmdir() for p in pathlib.Path('.').rglob('__pycache__')]" rm -rf ./dist/linux
rm -rf ./venv
rm -rf build/linux/* rm -rf ./buildenv
rm -rf build/windows/*
rm -rf "dist/linux/StardewSync"
rm -rf "dist/windows/StardewSync"
rm -rf venv
rm -rf buildenv

View File

@@ -0,0 +1,12 @@
#!/bin/bash
rm -rf ./testbinary/linux
mkdir ./testbinary/linux
cp -r ./dist/linux/* ./testbinary/linux/
cd "testbinary/linux/"
chmod +x "StardewSync"
"./StardewSync"

View File

@@ -0,0 +1,8 @@
#!/bin/bash
rm -rf testpython
mkdir testpython
cp -r ./src/* ./testpython/
source venv/bin/activate && cd ./testpython && python ./main.py && deactivate

View File

@@ -4,4 +4,4 @@ pip3 install virtualenv
virtualenv buildenv virtualenv buildenv
source buildenv/bin/activate && pip install --upgrade Pyinstaller && pip install --upgrade -r requirements.txt && deactivate source buildenv/bin/activate && pip install --upgrade Pyinstaller && pip install --upgrade -r ./src/requirements.txt && deactivate

View File

@@ -4,4 +4,4 @@ pip3 install virtualenv
virtualenv venv virtualenv venv
source venv/bin/activate && pip install --upgrade -r requirements.txt && deactivate source venv/bin/activate && pip install --upgrade -r ./src/requirements.txt && deactivate

View File

@@ -1,3 +0,0 @@
#!/bin/bash
source venv/bin/activate && bash .vscode/tasks/linux/cleanup.sh && python main.py && deactivate

7
.vscode/tasks/linux/run_binary.sh vendored Normal file
View File

@@ -0,0 +1,7 @@
#!/bin/bash
cd "testbinary/linux/"
chmod +x "StardewSync"
"./StardewSync"

3
.vscode/tasks/linux/run_python.sh vendored Normal file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
source venv/bin/activate && cd ./testpython && python ./main.py && deactivate

View File

@@ -1,7 +0,0 @@
#!/bin/bash
cd "dist/linux/StardewSync"
chmod +x "StardewSync"
"./StardewSync"

View File

@@ -1,3 +1,3 @@
rmdir /S /Q "dist\windows\StardewSync" rmdir /S /Q "dist\windows\StardewSync"
.\buildenv\scripts\activate && pyi-makespec main.py -n "StardewSync" -p "buildenv" -i "assets/favicon.ico" --add-data "config.json;." --add-data "assets;assets" --add-data "buildenv/Lib/site-packages/sv_ttk/sv.tcl;sv_ttk/" --add-data "buildenv/Lib/site-packages/sv_ttk/theme/*;sv_ttk/theme/" --noconsole && pyinstaller ".\StardewSync.spec" --noconfirm --distpath=dist\windows --workpath=build\windows .\buildenv\scripts\activate && pyi-makespec .\src\main.py -n "StardewSync" -p "buildenv" -i "src/assets/favicon.ico" --add-data "src/config.json;." --add-data "src/assets;assets" --add-data "buildenv/Lib/site-packages/sv_ttk/sv.tcl;sv_ttk/" --add-data "buildenv/Lib/site-packages/sv_ttk/theme/*;sv_ttk/theme/" --noconsole && pyinstaller ".\StardewSync.spec" --noconfirm --distpath=dist\windows --workpath=build\windows

View File

@@ -1,11 +1,4 @@
python -Bc "import pathlib; [p.unlink() for p in pathlib.Path('.').rglob('*.py[co]')]" rmdir /S /Q .\build
python -Bc "import pathlib; [p.rmdir() for p in pathlib.Path('.').rglob('__pycache__')]" rmdir /S /Q .\dist\windows
rmdir /S /Q .\venv
rmdir /S /Q build\linux\* rmdir /S /Q .\buildenv
rmdir /S /Q build\windows\*
rmdir /S /Q "dist\linux\StardewSync"
rmdir /S /Q "dist\windows\StardewSync"
rmdir /S /Q venv
rmdir /S /Q buildenv

View File

@@ -0,0 +1,7 @@
rmdir /S /Q testbinary\windows
mkdir testbinary\windows
xcopy ".\dist\windows\" ".\testbinary\windows\" /h /i /c /k /e /r /y
cd ".\testbinary\windows\StardewSync"
".\StardewSync.exe"

View File

@@ -0,0 +1,6 @@
rmdir /S /Q testpython
mkdir testpython
xcopy ".\src\" ".\testpython\" /h /i /c /k /e /r /y
venv\Scripts\activate && cd .\testpython && python .\main.py && deactivate

View File

@@ -2,4 +2,4 @@ pip install virtualenv
virtualenv buildenv virtualenv buildenv
buildenv\Scripts\activate && pip install --upgrade Pyinstaller && pip install --upgrade -r requirements.txt && deactivate buildenv\Scripts\activate && pip install --upgrade Pyinstaller && pip install --upgrade -r .\src\requirements.txt && deactivate

View File

@@ -2,4 +2,4 @@ pip install virtualenv
virtualenv venv virtualenv venv
venv\Scripts\activate && pip install --upgrade -r requirements.txt && deactivate venv\Scripts\activate && pip install --upgrade -r .\src\requirements.txt && deactivate

View File

@@ -1 +0,0 @@
.\.vscode\tasks\windows\cleanup.bat && venv\Scripts\activate && python main.py && deactivate

2
.vscode/tasks/windows/run_binary.bat vendored Normal file
View File

@@ -0,0 +1,2 @@
cd ".\testbinary\windows\StardewSync"
".\StardewSync.exe"

1
.vscode/tasks/windows/run_python.bat vendored Normal file
View File

@@ -0,0 +1 @@
venv\Scripts\activate && cd .\testpython && python .\main.py && deactivate

View File

@@ -1,2 +0,0 @@
cd "dist\windows\StardewSync"
".\StardewSync.exe"

View File

@@ -1,69 +0,0 @@
from datetime import datetime, timedelta, timezone
from tkinter import LEFT, NSEW, Misc, S, W, ttk
from classes.custom.themed_frame import ThemedFrame
from classes.enums import SaveState
from modules.utils import osname
class FrameSave(ThemedFrame):
def __init__(self, master: Misc, save_dict: dict, **kwargs) -> None:
super().__init__(master, style="Card.TFrame", **kwargs)
self.widget_width = 47 if osname == "nt" else 42
self.grid_columnconfigure(0, weight=1)
self.grid_columnconfigure(1, weight=3)
self.grid_columnconfigure(2, weight=3)
self.title = ttk.Label(self, text=f'{save_dict["data"]["farmer"]} ({save_dict["type"].value.upper()}, {save_dict["state"].value.upper()})', font=("SunValleyBodyStrongFont", 12, "bold"), justify=LEFT, width=self.widget_width)
self.title.grid(column=0, row=0, padx=9, pady=9, sticky=W)
self.description = ttk.Label(self, text=f'{self.convert_date(year=save_dict["data"]["year"], season=save_dict["data"]["season"], day=save_dict["data"]["day"])}\n{save_dict["data"]["money"]} Gold, {int((save_dict["data"]["played"]/(1000*60*60))%24)} hours played\nGame version: {save_dict["data"]["game_version"]}', width=self.widget_width)
self.description.grid(column=0, row=1, padx=9, pady=9, sticky=W)
self.buttons = ThemedFrame(self)
self.buttons.grid(column=0, columnspan=2, row=2, sticky=NSEW, padx=9, pady=9)
self.buttons.grid_columnconfigure(0, weight=1)
if save_dict["date"] != None:
upload_date = datetime.utcfromtimestamp(save_dict["date"]).replace(tzinfo=timezone.utc).astimezone(tz=None)
self.last_upload = ttk.Label(self.buttons, text=f'{upload_date.strftime("%A, %d %b %Y")}\nUploaded at {upload_date.strftime("%H:%M")} by {save_dict["device"]}', font=("SunValleyBodyFont", 8), justify=LEFT, width=self.widget_width)
else:
self.last_upload = ttk.Label(self.buttons, text=f'Exists only locally', font=("SunValleyBodyFont", 8), justify=LEFT, width=self.widget_width)
self.last_upload.grid(column=0, row=0, sticky=W+S)
# self.button_device_rename_action = partial(self.rename)
# self.button_device_rename = ttk.Button(self.buttons, text="Rename", width=11, command=self.button_device_rename_action)
# self.button_device_rename.grid(column=0, row=0, padx=9, sticky=E)
#self.button_device_delete_action = partial(self.delete)
self.button_synchronize = ttk.Button(self.buttons, text="Synchronize", style="Accent.TButton", width=11) #, command=self.button_device_delete_action)
self.button_synchronize.grid(column=1, row=0, sticky=W)
if save_dict["state"] is SaveState.CURRENT:
self.button_synchronize.state(["disabled"])
def convert_date(self, year: int, season: int, day: int) -> str:
if season == 0:
season = "Spring"
elif season == 1:
season = "Summer"
elif season == 2:
season = "Fall"
else:
season = "Winter"
return "Day {0} of {1}, Year {2}".format(day, season, year)
def convert_playtime(self, seconds: int) -> str:
pass
def upload(self):
pass
def download(self):
pass

View File

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 115 KiB

View File

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -11,7 +11,7 @@ from classes.custom.themed_frame import ThemedFrame
from classes.enums import ConnectionState, Theme from classes.enums import ConnectionState, Theme
from classes.frames.devices import FrameDevices, FrameDevicesEmpty from classes.frames.devices import FrameDevices, FrameDevicesEmpty
from classes.frames.errors import FrameErrorConnection, FrameErrorFirstStart, FrameErrorSavesFolder, FrameErrorUnconfigured from classes.frames.errors import FrameErrorConnection, FrameErrorFirstStart, FrameErrorSavesFolder, FrameErrorUnconfigured
from classes.frames.saves import FrameSaves, FrameSavesEmpty from classes.frames.saves import FrameSaves
from classes.frames.settings import FrameSettings from classes.frames.settings import FrameSettings
from classes.toplevel.welcome import ToplevelWelcome from classes.toplevel.welcome import ToplevelWelcome
from modules.theme_titlebar import theme_title_bar from modules.theme_titlebar import theme_title_bar
@@ -63,18 +63,19 @@ class App(ThemedTk):
def frame_saves(self): def frame_saves(self):
self.grid_rowconfigure(0, weight=1) self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(1, weight=1) self.grid_columnconfigure(1, weight=1)
try: # try:
self.frame_saves_saves = requests.get(f'{configGet("address")}/saves?only_ids=True&sort={(configGet("prefer_saves").split())[1]}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed")) # self.frame_saves_saves = requests.get(f'{configGet("address")}/saves?only_ids=True&sort={(configGet("prefer_saves").split())[1]}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed"))
except Exception as exp: # except Exception as exp:
messagebox.showerror(title="Connection error", message=f"We could not reach the server to check for save entries\n\n{exp}") # messagebox.showerror(title="Connection error", message=f"We could not reach the server to check for save entries\n\n{exp}")
logger.error(format_exc()) # logger.error(format_exc())
self.frame_saves_object = FrameErrorConnection(self) # self.frame_saves_object = FrameErrorConnection(self)
self.frame_saves_object.grid(column=1, row=0, sticky=NSEW) # self.frame_saves_object.grid(column=1, row=0, sticky=NSEW)
return # return
if self.frame_saves_saves.status_code == 200 and isinstance(self.frame_saves_saves.json(), list) is True and len(self.frame_saves_saves.json()) > 0: # if self.frame_saves_saves.status_code == 200 and isinstance(self.frame_saves_saves.json(), list) is True and len(self.frame_saves_saves.json()) > 0:
self.frame_saves_object = FrameSaves(self, self.frame_saves_saves.json(), vscroll=True) # self.frame_saves_object = FrameSaves(self, self.frame_saves_saves.json(), vscroll=True)
else: # else:
self.frame_saves_object = FrameSaves(self, [], vscroll=True) # self.frame_saves_object = FrameSaves(self, [], vscroll=True)
self.frame_saves_object = FrameSaves(self, vscroll=True)
self.frame_saves_object.grid(column=1, row=0, sticky=NSEW) self.frame_saves_object.grid(column=1, row=0, sticky=NSEW)
return return

124
src/classes/frames/save.py Normal file
View File

@@ -0,0 +1,124 @@
from datetime import datetime, timedelta, timezone
from functools import partial
from os import makedirs, path, remove
from tkinter import LEFT, NSEW, Misc, S, W, ttk
from urllib.parse import urlencode
from zipfile import ZipFile
import requests
from classes.custom.themed_frame import ThemedFrame
from classes.enums import SaveState, SaveType
from modules.utils import configGet, osname
class FrameSave(ThemedFrame):
def __init__(self, master: Misc, save_dict: dict, **kwargs) -> None:
super().__init__(master, style="Card.TFrame", **kwargs)
self.widget_width = 47 if osname == "nt" else 42
self.grid_columnconfigure(0, weight=1)
self.grid_columnconfigure(1, weight=3)
self.grid_columnconfigure(2, weight=3)
self.save_dict = save_dict
self.title = ttk.Label(self, text=f'{save_dict["data"]["farmer"]} ({save_dict["type"].value.upper()}, {save_dict["state"].value.upper()})', font=("SunValleyBodyStrongFont", 12, "bold"), justify=LEFT, width=self.widget_width)
self.title.grid(column=0, row=0, padx=9, pady=9, sticky=W)
self.description = ttk.Label(self, text=f'{self.convert_date(year=save_dict["data"]["year"], season=save_dict["data"]["season"], day=save_dict["data"]["day"])}\n{save_dict["data"]["money"]} Gold, {int((save_dict["data"]["played"]/(1000*60*60))%24)} hours played\nGame version: {save_dict["data"]["game_version"]}', width=self.widget_width)
self.description.grid(column=0, row=1, padx=9, pady=9, sticky=W)
self.buttons = ThemedFrame(self)
self.buttons.grid(column=0, columnspan=2, row=2, sticky=NSEW, padx=9, pady=9)
self.buttons.grid_columnconfigure(0, weight=1)
if save_dict["date"] != None:
upload_date = datetime.utcfromtimestamp(save_dict["date"]).replace(tzinfo=timezone.utc).astimezone(tz=None)
self.last_upload = ttk.Label(self.buttons, text=f'{upload_date.strftime("%A, %d %b %Y")}\nUploaded at {upload_date.strftime("%H:%M")} by {save_dict["device"]}', font=("SunValleyBodyFont", 8), justify=LEFT, width=self.widget_width)
else:
self.last_upload = ttk.Label(self.buttons, text=f'Exists only locally', font=("SunValleyBodyFont", 8), justify=LEFT, width=self.widget_width)
self.last_upload.grid(column=0, row=0, sticky=W+S)
# self.button_device_rename_action = partial(self.rename)
# self.button_device_rename = ttk.Button(self.buttons, text="Rename", width=11, command=self.button_device_rename_action)
# self.button_device_rename.grid(column=0, row=0, padx=9, sticky=E)
self.button_synchronize_action = partial(self.nothing)
if save_dict["type"] is SaveType.LOCAL:
if save_dict["state"] is SaveState.RECENT:
self.button_synchronize_action = partial(self.upload, save_dict["id"])
print(f'{save_dict["id"]}, local, recent')
elif save_dict["type"] is SaveType.REMOTE:
if save_dict["state"] is SaveState.RECENT:
self.button_synchronize_action = partial(self.download, save_dict["id"], save_dict["date"])
print(f'{save_dict["id"]}, remote, recent')
else:
if save_dict["state"] is SaveState.OUTDATED:
self.button_synchronize_action = partial(self.download, save_dict["id"], save_dict["date"])
print(f'{save_dict["id"]}, both, outdated')
elif save_dict["state"] is SaveState.RECENT:
self.button_synchronize_action = partial(self.upload, save_dict["id"])
print(f'{save_dict["id"]}, both, recent')
self.button_synchronize = ttk.Button(self.buttons, text="Synchronize", style="Accent.TButton", width=11, command=self.button_synchronize_action)
self.button_synchronize.grid(column=1, row=0, sticky=W)
if save_dict["state"] is SaveState.CURRENT:
self.button_synchronize.state(["disabled"])
def convert_date(self, year: int, season: int, day: int) -> str:
if season == 0:
season_name = "Spring"
elif season == 1:
season_name = "Summer"
elif season == 2:
season_name = "Fall"
else:
season_name = "Winter"
return "Day {0} of {1}, Year {2}".format(day, season_name, year)
def convert_playtime(self, seconds: int) -> str:
return ""
def upload(self, id: int):
print(f"Upload pressed for {id}")
files = [("files", open(path.join(configGet("saves_location"), f'{self.save_dict["data"]["farmer"]}_{self.save_dict["id"]}', f'{self.save_dict["data"]["farmer"]}_{self.save_dict["id"]}'), "rb")), ("files", open(path.join(configGet("saves_location"), f'{self.save_dict["data"]["farmer"]}_{self.save_dict["id"]}', "SaveGameInfo"), "rb"))]
response = requests.post(f'{configGet("address")}/saves?{urlencode({"device": configGet("name")})}', files=files, headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed"))
print(response.status_code)
self.master.render_saves()
def download(self, id: int, date: int):
print(f"Download pressed for {id}")
response = requests.get(f'{configGet("address")}/saves/{id}/{date}/download', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed"))
makedirs("tmp", exist_ok=True)
with open(path.join("tmp", f"{id}.svsave"), "wb") as file:
file.write(response.content)
makedirs(path.join(configGet("saves_location"), f'{self.save_dict["data"]["farmer"]}_{self.save_dict["id"]}'), exist_ok=True)
with ZipFile(path.join("tmp", f"{id}.svsave"), "r") as file:
file.extractall(path.join(configGet("saves_location"), f'{self.save_dict["data"]["farmer"]}_{self.save_dict["id"]}'))
remove(path.join("tmp", f"{id}.svsave"))
print(response.status_code)
self.master.render_saves()
def nothing(self):
pass

View File

@@ -2,6 +2,7 @@ from os import path, walk
from tkinter import E, NSEW, W, ttk from tkinter import E, NSEW, W, ttk
from traceback import print_exc from traceback import print_exc
import xmltodict import xmltodict
import requests
from ttkthemes import ThemedTk from ttkthemes import ThemedTk
@@ -14,18 +15,41 @@ from modules.utils import configGet
class FrameSaves(ScrollableFrame): class FrameSaves(ScrollableFrame):
def __init__(self, master: ThemedTk, saves: list, **kwargs) -> None: def __init__(self, master: ThemedTk, **kwargs) -> None:
super().__init__(master, **kwargs) super().__init__(master, **kwargs)
master.title("Saves - Stardew Sync") master.title("Saves - Stardew Sync")
self.saves = saves self.saves = self.fetch_saves()
self.saves_local = []
# self["borderwidth"] = 1 # self["borderwidth"] = 1
# self["relief"] = "solid" # self["relief"] = "solid"
master.columnconfigure(1, weight=1)
if len(self.saves) == 0:
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(0, weight=2)
master.columnconfigure(1, weight=1)
self.label = ttk.Label(self, text="No saves found")
self.label.grid(column=0, row=0, padx=9, pady=9)
else:
self.render_saves(refetch=False)
def fetch_saves_remote(self) -> list:
response = self.frame_saves_saves = requests.get(f'{configGet("address")}/saves?only_ids=True&sort={(configGet("prefer_saves").split())[1]}', headers={"apikey": configGet("apikey")}, verify=not configGet("allow_self_signed"))
return response.json() if response.status_code == 200 else []
def fetch_saves(self) -> list:
self.saves = self.fetch_saves_remote()
for index, entry in enumerate(self.saves): for index, entry in enumerate(self.saves):
self.saves[index]["state"] = SaveState.RECENT self.saves[index]["state"] = SaveState.RECENT
@@ -107,20 +131,20 @@ class FrameSaves(ScrollableFrame):
except: except:
print_exc() print_exc()
# Merge local and remote saves. return self.saves
# Maybe add something that indicates availability of an
# remote update to pull or local new version to push.
master.columnconfigure(1, weight=1) def render_saves(self, refetch: bool = True):
self.render_saves() if refetch is True:
self.saves = self.fetch_saves()
def render_saves(self): for widget in self.winfo_children():
widget.destroy()
i = 0 i = 0
for save in self.saves: for save in self.saves:
print(save) # print(save)
save_frame = FrameSave(self, save_dict=save) save_frame = FrameSave(self, save_dict=save)
save_frame.grid(column=0, row=i, pady=9, padx=9, sticky=W+E) save_frame.grid(column=0, row=i, pady=9, padx=9, sticky=W+E)
@@ -132,18 +156,18 @@ class FrameSaves(ScrollableFrame):
divider.grid(column=0, row=i+1, pady=9) divider.grid(column=0, row=i+1, pady=9)
i += 1 i += 1
class FrameSavesEmpty(ThemedFrame): # class FrameSavesEmpty(ThemedFrame):
def __init__(self, master: ThemedTk, **kwargs) -> None: # def __init__(self, master: ThemedTk, **kwargs) -> None:
super().__init__(master, **kwargs) # super().__init__(master, **kwargs)
master.title("Saves - Stardew Sync") # master.title("Saves - Stardew Sync")
self.grid_columnconfigure(0, weight=1) # self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(0, weight=2) # self.grid_rowconfigure(0, weight=2)
master.columnconfigure(1, weight=1) # master.columnconfigure(1, weight=1)
self.label = ttk.Label(self, text="No saves found") # self.label = ttk.Label(self, text="No saves found")
self.label.grid(column=0, row=0, padx=9, pady=9) # self.label.grid(column=0, row=0, padx=9, pady=9)