mirror of
https://github.com/c9moser/sgbackup.git
synced 2026-01-20 03:50:13 +00:00
2025.02.17 02:21:41 (desktop)
This commit is contained in:
parent
35d8b71751
commit
0abb7db5c3
@ -1,24 +0,0 @@
|
|||||||
[build-system]
|
|
||||||
builbackend = 'setuptools.build_meta'
|
|
||||||
requires = ['setuptools >= 61.0']
|
|
||||||
|
|
||||||
[project]
|
|
||||||
dynamic = ["version"]
|
|
||||||
name = 'sgbackup'
|
|
||||||
version = '0.0.0'
|
|
||||||
requires_python = '>= 3.11'
|
|
||||||
description = 'Savegame Backup Tool'
|
|
||||||
readme = 'README.md'
|
|
||||||
license = {file = 'LICENSE'}
|
|
||||||
authors = [
|
|
||||||
{name = 'Christian Moser', email = 'christian@mydevel.at'},
|
|
||||||
]
|
|
||||||
dependencies = ['gi','yaml']
|
|
||||||
|
|
||||||
[project.scripts]
|
|
||||||
sgbackup = 'sgbackup:cli_main'
|
|
||||||
csgbackup = 'sgbackup:curses_main'
|
|
||||||
|
|
||||||
[project.gui-scripts]
|
|
||||||
gsgbackup = 'sgbackup:gui_main'
|
|
||||||
|
|
||||||
2
requirements.txt
Normal file
2
requirements.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
rapidfuzz
|
||||||
|
|
||||||
38
setup.py
Normal file
38
setup.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from setuptools import setup
|
||||||
|
import subprocess
|
||||||
|
import bz2
|
||||||
|
|
||||||
|
PACKAGE_ROOT=os.path.dirname(__file__)
|
||||||
|
|
||||||
|
sys.path.insert(0,PACKAGE_ROOT)
|
||||||
|
import sgbackup
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='sgbackup',
|
||||||
|
version=sgbackup.__version__
|
||||||
|
description='A backup tool for savegames.',
|
||||||
|
author="Christian Moser",
|
||||||
|
author_email="christian@cmoser.eu",
|
||||||
|
packages=[
|
||||||
|
'sgbackup',
|
||||||
|
'sgbackup.archivers',
|
||||||
|
'sgbackup.commands',
|
||||||
|
'sgbackup.curses',
|
||||||
|
'sgbackup.help',
|
||||||
|
'sgbackup.gui',
|
||||||
|
],
|
||||||
|
package_data={
|
||||||
|
'sgbackup':[
|
||||||
|
'icons/sgbackup.ico',
|
||||||
|
'icons/hicolor/symbolic/*/*.svg'
|
||||||
|
],
|
||||||
|
'sgbackup.gui': [
|
||||||
|
'*.ui'
|
||||||
|
],
|
||||||
|
},
|
||||||
|
platforms=['win32','linux']
|
||||||
|
)
|
||||||
@ -21,7 +21,7 @@ from . import _import_gtk
|
|||||||
__version__ = "0.0.1"
|
__version__ = "0.0.1"
|
||||||
from .settings import settings
|
from .settings import settings
|
||||||
from . import _logging
|
from . import _logging
|
||||||
from .main import cli_main,curses_main,gui_main
|
from .main import cli_main,gui_main
|
||||||
from . import game
|
from . import game
|
||||||
from .command import Command
|
from .command import Command
|
||||||
from . import commands
|
from . import commands
|
||||||
@ -31,7 +31,7 @@ __ALL__ = [
|
|||||||
"settings"
|
"settings"
|
||||||
"cli_main",
|
"cli_main",
|
||||||
"gui_main",
|
"gui_main",
|
||||||
"curses_main",
|
#"curses_main",
|
||||||
'game',
|
'game',
|
||||||
"Command",
|
"Command",
|
||||||
"commands",
|
"commands",
|
||||||
|
|||||||
@ -164,9 +164,6 @@ class GameView(Gtk.Box):
|
|||||||
pass
|
pass
|
||||||
self.__liststore.append(g)
|
self.__liststore.append(g)
|
||||||
self.__sort_model = Gtk.SortListModel.new(self._liststore,self.__name_sorter)
|
self.__sort_model = Gtk.SortListModel.new(self._liststore,self.__name_sorter)
|
||||||
self.__sort_model
|
|
||||||
self.__action_dialog = None
|
|
||||||
self.__backup_dialog = None
|
|
||||||
|
|
||||||
factory_icon = Gtk.SignalListItemFactory.new()
|
factory_icon = Gtk.SignalListItemFactory.new()
|
||||||
factory_icon.connect('setup',self._on_icon_column_setup)
|
factory_icon.connect('setup',self._on_icon_column_setup)
|
||||||
@ -319,12 +316,14 @@ class GameView(Gtk.Box):
|
|||||||
def _on_key_column_setup(self,factory,item):
|
def _on_key_column_setup(self,factory,item):
|
||||||
label = Gtk.Label()
|
label = Gtk.Label()
|
||||||
label.set_xalign(0.0)
|
label.set_xalign(0.0)
|
||||||
|
label.set_use_markup(True)
|
||||||
item.set_child(label)
|
item.set_child(label)
|
||||||
|
|
||||||
def _on_key_column_bind(self,factory,item):
|
def _on_key_column_bind(self,factory,item):
|
||||||
label = item.get_child()
|
label = item.get_child()
|
||||||
game = item.get_item()
|
game = item.get_item()
|
||||||
game.bind_property('key',label,'label',BindingFlags.SYNC_CREATE)
|
game.bind_property('key',label,'label',BindingFlags.SYNC_CREATE,
|
||||||
|
lambda _binding,s: '<span size="large">{}</span>'.format(GLib.markup_escape_text(s)))
|
||||||
|
|
||||||
def _on_name_column_setup(self,factory,item):
|
def _on_name_column_setup(self,factory,item):
|
||||||
label = Gtk.Label()
|
label = Gtk.Label()
|
||||||
@ -424,8 +423,13 @@ class GameView(Gtk.Box):
|
|||||||
game = item.get_item()
|
game = item.get_item()
|
||||||
archiver_manager = ArchiverManager.get_global()
|
archiver_manager = ArchiverManager.get_global()
|
||||||
|
|
||||||
if not hasattr(child.backup_button,'_signal_clicked_connection'):
|
# check if we are already connected.
|
||||||
|
# if we dont check we might have more than one dialog open or execute backups more than once
|
||||||
|
# due to Gtk4 reusing the widgets. When selecting a row in the columnview this method is called.
|
||||||
|
if hasattr(child.backup_button,'_signal_clicked_connection'):
|
||||||
|
child.backup_button.disconnect(child.backup_button._signal_clicked_connection)
|
||||||
child.backup_button._signal_clicked_connection = child.backup_button.connect('clicked',self._on_columnview_backup_button_clicked,item)
|
child.backup_button._signal_clicked_connection = child.backup_button.connect('clicked',self._on_columnview_backup_button_clicked,item)
|
||||||
|
|
||||||
if not hasattr(child.backup_button,'_property_backup_in_progress_binding'):
|
if not hasattr(child.backup_button,'_property_backup_in_progress_binding'):
|
||||||
child.backup_button._property_backup_in_progress_binding = archiver_manager.bind_property('backup-in-progress',
|
child.backup_button._property_backup_in_progress_binding = archiver_manager.bind_property('backup-in-progress',
|
||||||
child.backup_button,
|
child.backup_button,
|
||||||
@ -433,7 +437,8 @@ class GameView(Gtk.Box):
|
|||||||
BindingFlags.SYNC_CREATE,
|
BindingFlags.SYNC_CREATE,
|
||||||
lambda binding,x: False if x else True)
|
lambda binding,x: False if x else True)
|
||||||
|
|
||||||
if not hasattr(child.edit_button,'_signal_clicked_connection'):
|
if hasattr(child.edit_button,'_signal_clicked_connection'):
|
||||||
|
child.edit_button.disconnect(child.edit_button._signal_clicked_connection)
|
||||||
child.edit_button._signal_clicked_connection = child.edit_button.connect('clicked',self._on_columnview_edit_button_clicked,item)
|
child.edit_button._signal_clicked_connection = child.edit_button.connect('clicked',self._on_columnview_edit_button_clicked,item)
|
||||||
|
|
||||||
if not hasattr(child.edit_button,'_property_backup_in_progress_binding'):
|
if not hasattr(child.edit_button,'_property_backup_in_progress_binding'):
|
||||||
@ -443,8 +448,10 @@ class GameView(Gtk.Box):
|
|||||||
BindingFlags.SYNC_CREATE,
|
BindingFlags.SYNC_CREATE,
|
||||||
lambda binding,x: False if x else True)
|
lambda binding,x: False if x else True)
|
||||||
|
|
||||||
if not hasattr(child.remove_button,'_signal_clicked_connection'):
|
if hasattr(child.remove_button,'_signal_clicked_connection'):
|
||||||
|
child.remove_button.disconnect(child.remove_button._signal_clicked_connection)
|
||||||
child.remove_button._signal_clicked_connection = child.remove_button.connect('clicked',self._on_columnview_remove_button_clicked,item)
|
child.remove_button._signal_clicked_connection = child.remove_button.connect('clicked',self._on_columnview_remove_button_clicked,item)
|
||||||
|
|
||||||
if not hasattr(child.remove_button,'_property_backup_in_progress_binding'):
|
if not hasattr(child.remove_button,'_property_backup_in_progress_binding'):
|
||||||
child.remove_button._property_backup_in_progress_binding = archiver_manager.bind_property('backup-in-progress',
|
child.remove_button._property_backup_in_progress_binding = archiver_manager.bind_property('backup-in-progress',
|
||||||
child.remove_button,'sensitive',
|
child.remove_button,'sensitive',
|
||||||
@ -458,30 +465,22 @@ class GameView(Gtk.Box):
|
|||||||
child.backup_button.set_sensitive(False)
|
child.backup_button.set_sensitive(False)
|
||||||
|
|
||||||
def _on_columnview_backup_button_clicked(self,button,item):
|
def _on_columnview_backup_button_clicked(self,button,item):
|
||||||
def on_dialog_response(dialog,response):
|
|
||||||
self.__backup_dialog = None
|
|
||||||
|
|
||||||
if self.__backup_dialog is None:
|
|
||||||
game = item.get_item()
|
game = item.get_item()
|
||||||
self.__backup_dialog = BackupSingleDialog(self.get_root(),game)
|
dialog = BackupSingleDialog(self.get_root(),game)
|
||||||
self.__backup_dialog.connect('response',on_dialog_response)
|
dialog.connect('response',on_dialog_response)
|
||||||
self.__backup_dialog.run()
|
dialog.run()
|
||||||
|
|
||||||
def _on_columnview_edit_button_clicked(self,button,item):
|
def _on_columnview_edit_button_clicked(self,button,item):
|
||||||
def on_dialog_response(dialog,response):
|
def on_dialog_response(dialog,response):
|
||||||
if response == Gtk.ResponseType.APPLY:
|
if response == Gtk.ResponseType.APPLY:
|
||||||
self.refresh()
|
self.refresh()
|
||||||
self.__action_dialog = None
|
|
||||||
|
|
||||||
if self.__action_dialog is None:
|
|
||||||
game = item.get_item()
|
game = item.get_item()
|
||||||
|
|
||||||
self.__action_dialog = GameDialog(self.get_root(),game)
|
dialog = GameDialog(self.get_root(),game)
|
||||||
self.__action_dialog.set_modal(False)
|
dialog.set_modal(False)
|
||||||
self.__action_dialog.connect('response',on_dialog_response)
|
dialog.connect('response',on_dialog_response)
|
||||||
self.__action_dialog.present()
|
dialog.present()
|
||||||
else:
|
|
||||||
self.__action_dialog.present()
|
|
||||||
|
|
||||||
|
|
||||||
def _on_columnview_remove_button_clicked(self,button,item):
|
def _on_columnview_remove_button_clicked(self,button,item):
|
||||||
@ -497,21 +496,17 @@ class GameView(Gtk.Box):
|
|||||||
|
|
||||||
dialog.hide()
|
dialog.hide()
|
||||||
dialog.destroy()
|
dialog.destroy()
|
||||||
self.__action_dialog = None
|
|
||||||
|
|
||||||
game = item.get_item()
|
game = item.get_item()
|
||||||
if self.__action_dialog is None:
|
dialog = Gtk.MessageDialog(buttons=Gtk.ButtonsType.YES_NO,
|
||||||
self.__action_dialog = Gtk.MessageDialog(buttons=Gtk.ButtonsType.YES_NO,
|
|
||||||
text="Do you really want to remove the game <span weight='bold'>{game}</span>?".format(
|
text="Do you really want to remove the game <span weight='bold'>{game}</span>?".format(
|
||||||
game=game.name),
|
game=game.name),
|
||||||
use_markup=True,
|
use_markup=True,
|
||||||
secondary_text="Removing games cannot be undone!!!")
|
secondary_text="Removing games cannot be undone!!!")
|
||||||
self.__action_dialog.set_transient_for(self.get_root())
|
dialog.set_transient_for(self.get_root())
|
||||||
self.__action_dialog.set_modal(False)
|
dialog.set_modal(False)
|
||||||
self.__action_dialog.connect('response',on_dialog_response,game)
|
dialog.connect('response',on_dialog_response,game)
|
||||||
self.__action_dialog.present()
|
dialog.present()
|
||||||
else:
|
|
||||||
self.__action_dialog.present()
|
|
||||||
|
|
||||||
# GameView class
|
# GameView class
|
||||||
|
|
||||||
|
|||||||
@ -100,7 +100,10 @@ class RegistryKeyData(GObject):
|
|||||||
"""
|
"""
|
||||||
GObject.__init__(self)
|
GObject.__init__(self)
|
||||||
if not regkey:
|
if not regkey:
|
||||||
self.__regkey = ""
|
self.regkey = ""
|
||||||
|
else:
|
||||||
|
self.regkey = regkey
|
||||||
|
|
||||||
|
|
||||||
@Property(type=str)
|
@Property(type=str)
|
||||||
def regkey(self)->str:
|
def regkey(self)->str:
|
||||||
@ -972,12 +975,12 @@ class GameDialog(Gtk.Dialog):
|
|||||||
irk = []
|
irk = []
|
||||||
|
|
||||||
for i in range(grk_model.get_n_items()):
|
for i in range(grk_model.get_n_items()):
|
||||||
item = grk.model.get_item(i)
|
item = grk_model.get_item(i)
|
||||||
if item.regkey:
|
if item.regkey:
|
||||||
grk.append(item.regkey)
|
grk.append(item.regkey)
|
||||||
|
|
||||||
for i in range(irk_model.get_n_items()):
|
for i in range(irk_model.get_n_items()):
|
||||||
item = irk.model.get_item(i)
|
item = irk_model.get_item(i)
|
||||||
if item.regkey:
|
if item.regkey:
|
||||||
irk.append(item.regkey)
|
irk.append(item.regkey)
|
||||||
|
|
||||||
@ -1255,8 +1258,8 @@ class GameDialog(Gtk.Dialog):
|
|||||||
label = item.get_child()
|
label = item.get_child()
|
||||||
data = item.get_item()
|
data = item.get_item()
|
||||||
label.set_text(data.regkey)
|
label.set_text(data.regkey)
|
||||||
label.bind_property('text',data,'regkey',GObject.BindingFlags.DEFAULT)
|
label.bind_property('text',data,'regkey',BindingFlags.DEFAULT)
|
||||||
label.connect('changed',self._on_windows_regkey_label_changed,widget)
|
label.connect('notify::editing',self._on_windows_regkey_label_notify_editing,widget)
|
||||||
if not label.get_text():
|
if not label.get_text():
|
||||||
label.start_editing()
|
label.start_editing()
|
||||||
label.grab_focus()
|
label.grab_focus()
|
||||||
@ -1316,16 +1319,15 @@ class GameDialog(Gtk.Dialog):
|
|||||||
def _on_windows_regkey_add_button_clicked(self,button,widget):
|
def _on_windows_regkey_add_button_clicked(self,button,widget):
|
||||||
widget.listview.get_model().get_model().append(RegistryKeyData())
|
widget.listview.get_model().get_model().append(RegistryKeyData())
|
||||||
|
|
||||||
def _on_windows_regkey_label_changed(self,label,widget):
|
def _on_windows_regkey_label_notify_editing(self,label,state,widget):
|
||||||
|
if not label.get_editing():
|
||||||
if not label.get_text():
|
if not label.get_text():
|
||||||
model = widget.listview.get_model().get_model()
|
model = widget.listview.get_model().get_model()
|
||||||
i = 0
|
i = 0
|
||||||
while i < model.get_n_items():
|
for i in reversed(range(model.get_n_items())):
|
||||||
item = model.get_item(i)
|
item = model.get_item(i)
|
||||||
if not item.regkey:
|
if not item.regkey:
|
||||||
model.remove(i)
|
model.remove(i)
|
||||||
continue
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
def do_response(self,response):
|
def do_response(self,response):
|
||||||
if (response == Gtk.ResponseType.APPLY):
|
if (response == Gtk.ResponseType.APPLY):
|
||||||
|
|||||||
@ -172,8 +172,17 @@ class SteamLibrariesDialog(Gtk.Dialog):
|
|||||||
lib = item.get_item()
|
lib = item.get_item()
|
||||||
child.label.set_text(lib.directory)
|
child.label.set_text(lib.directory)
|
||||||
child.label.bind_property('text',lib,'directory',BindingFlags.DEFAULT)
|
child.label.bind_property('text',lib,'directory',BindingFlags.DEFAULT)
|
||||||
child.chooser_button.connect('clicked',self._on_list_chooser_button_clicked,child.label)
|
if hasattr(child.chooser_button,'_signal_clicked_connector'):
|
||||||
child.remove_button.connect('clicked',self._on_list_remove_button_clicked,child.label)
|
child.chooser_button.disconnect(child.chooser_button._signal_clicked_connector)
|
||||||
|
child.chooser_button._signal_clicked_connector = child.chooser_button.connect('clicked',
|
||||||
|
self._on_list_chooser_button_clicked,
|
||||||
|
child.label)
|
||||||
|
|
||||||
|
if hasattr(child.remove_button,'_signal_clicked_connector'):
|
||||||
|
child.remove_button.disconnect(child.remove_button._signal_clicked_connector)
|
||||||
|
child.remove_button._signal_clicked_connector = child.remove_button.connect('clicked',
|
||||||
|
self._on_list_remove_button_clicked,
|
||||||
|
child.label)
|
||||||
|
|
||||||
def do_response(self,response):
|
def do_response(self,response):
|
||||||
if response == Gtk.ResponseType.APPLY:
|
if response == Gtk.ResponseType.APPLY:
|
||||||
@ -219,6 +228,7 @@ class NewSteamAppsDialog(Gtk.Dialog):
|
|||||||
factory = Gtk.SignalListItemFactory()
|
factory = Gtk.SignalListItemFactory()
|
||||||
factory.connect('setup',self._on_listitem_setup)
|
factory.connect('setup',self._on_listitem_setup)
|
||||||
factory.connect('bind',self._on_listitem_bind)
|
factory.connect('bind',self._on_listitem_bind)
|
||||||
|
factory.connect('unbind',self._on_listitem_unbind)
|
||||||
|
|
||||||
self.__listview = Gtk.ListView.new(selection,factory)
|
self.__listview = Gtk.ListView.new(selection,factory)
|
||||||
self.__listview.set_vexpand(True)
|
self.__listview.set_vexpand(True)
|
||||||
@ -287,23 +297,32 @@ class NewSteamAppsDialog(Gtk.Dialog):
|
|||||||
child.name_label.set_markup("<span weight='bold' size='large'>{}</span>".format(GLib.markup_escape_text(data.name)))
|
child.name_label.set_markup("<span weight='bold' size='large'>{}</span>".format(GLib.markup_escape_text(data.name)))
|
||||||
child.appid_label.set_text(str(data.appid))
|
child.appid_label.set_text(str(data.appid))
|
||||||
child.installdir_label.set_text(data.installdir)
|
child.installdir_label.set_text(data.installdir)
|
||||||
if not hasattr(child.add_app_button,'_signal_clicked_connector'):
|
|
||||||
|
# Check if we are already connected.
|
||||||
|
# if we dont check we might have more than one dialog open
|
||||||
|
# due to Gtk4 reusing the widgets.
|
||||||
|
# When selecting a row in the columnview this method is called so we
|
||||||
|
# need to ensure that the last binding is used to work as expected.
|
||||||
|
if hasattr(child.add_app_button,'_signal_clicked_connector'):
|
||||||
|
child.add_app_button.disconnect(child.add_app_button._signal_clicked_connector)
|
||||||
child.add_app_button._signal_clicked_connector = child.add_app_button.connect('clicked',self._on_add_steamapp_button_clicked,data)
|
child.add_app_button._signal_clicked_connector = child.add_app_button.connect('clicked',self._on_add_steamapp_button_clicked,data)
|
||||||
if not hasattr(child.ignore_app_button,'_signal_clicked_connector'):
|
|
||||||
|
if hasattr(child.ignore_app_button,'_signal_clicked_connector'):
|
||||||
|
child.ignore_app_button.disconnect(child.ignore_app_button._signal_clicked_connector)
|
||||||
child.ignore_app_button._signal_clicked_connector = child.ignore_app_button.connect('clicked',self._on_ignore_steamapp_button_clicked,data)
|
child.ignore_app_button._signal_clicked_connector = child.ignore_app_button.connect('clicked',self._on_ignore_steamapp_button_clicked,data)
|
||||||
|
|
||||||
|
def _on_listitem_unbind(self,factory,item):
|
||||||
|
child = item.get_child()
|
||||||
|
data = item.get_item()
|
||||||
|
|
||||||
def _on_add_steamapp_button_clicked(self,button,data:SteamApp,*args):
|
def _on_add_steamapp_button_clicked(self,button,data:SteamApp,*args):
|
||||||
def on_dialog_response(dialog,response):
|
def on_dialog_response(dialog,response):
|
||||||
self.__gamedialog = None
|
|
||||||
if response == Gtk.ResponseType.APPLY:
|
if response == Gtk.ResponseType.APPLY:
|
||||||
for i in range(self.__listmodel.get_n_items()):
|
for i in range(self.__listmodel.get_n_items()):
|
||||||
if data.appid == self.__listmodel.get_item(i).appid:
|
if data.appid == self.__listmodel.get_item(i).appid:
|
||||||
self.__listmodel.remove(i)
|
self.__listmodel.remove(i)
|
||||||
break
|
break
|
||||||
|
|
||||||
if self.__gamedialog is not None:
|
|
||||||
return
|
|
||||||
|
|
||||||
game = Game("Enter key",data.name,"")
|
game = Game("Enter key",data.name,"")
|
||||||
if PLATFORM_WINDOWS:
|
if PLATFORM_WINDOWS:
|
||||||
game.steam_windows = SteamWindowsGame(data.appid,"","",installdir=data.installdir)
|
game.steam_windows = SteamWindowsGame(data.appid,"","",installdir=data.installdir)
|
||||||
|
|||||||
0
sgbackup/help/__init__.py
Normal file
0
sgbackup/help/__init__.py
Normal file
@ -29,9 +29,9 @@ def cli_main():
|
|||||||
logger.debug("Running cli_main()")
|
logger.debug("Running cli_main()")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def curses_main():
|
#def curses_main():
|
||||||
logger.debug("Running curses_main()")
|
# logger.debug("Running curses_main()")
|
||||||
return 0
|
# return 0
|
||||||
|
|
||||||
def gui_main():
|
def gui_main():
|
||||||
logger.debug("Running gui_main()")
|
logger.debug("Running gui_main()")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user