mirror of
https://github.com/aclist/dztui.git
synced 2024-12-28 21:32:36 +01:00
fix: error handling for no local mods
This commit is contained in:
parent
32a43cd787
commit
8b9f751ff1
4 changed files with 108 additions and 50 deletions
|
@ -1,5 +1,13 @@
|
|||
# Changelog
|
||||
|
||||
## [5.6.0-beta.3] 2024-11-18
|
||||
### Fixed
|
||||
- Improved handling for cases where there are no locally installed mods
|
||||
- Set up mod symlinks at boot, rather than only on server connect
|
||||
- Prevent context menus from opening when table is empty
|
||||
- When reloading table in-place, prevent duplicate panel elements from being added if already present
|
||||
- Clean up signal emission
|
||||
|
||||
## [5.6.0-beta.2] 2024-11-15
|
||||
### Fixed
|
||||
- Clean up local mod signatures from versions file when deleting mods
|
||||
|
|
8
dzgui.sh
8
dzgui.sh
|
@ -569,10 +569,10 @@ fetch_helpers_by_sum(){
|
|||
[[ -f "$config_file" ]] && source "$config_file"
|
||||
declare -A sums
|
||||
sums=(
|
||||
["ui.py"]="680ff0e4071681f26409fa3592a41e46"
|
||||
["ui.py"]="4663cdda7bf91a0c594103d6f4382f15"
|
||||
["query_v2.py"]="55d339ba02512ac69de288eb3be41067"
|
||||
["vdf2json.py"]="2f49f6f5d3af919bebaab2e9c220f397"
|
||||
["funcs"]="acd5d85b27141082b25e07138f8b5b54"
|
||||
["funcs"]="5eae515ea2cac2ab38212a529415e86b"
|
||||
["lan"]="c62e84ddd1457b71a85ad21da662b9af"
|
||||
)
|
||||
local author="aclist"
|
||||
|
@ -874,6 +874,9 @@ stale_mod_signatures(){
|
|||
fi
|
||||
|
||||
}
|
||||
create_new_links(){
|
||||
"$HOME/.local/share/$app_name/helpers/funcs" "update_symlinks"
|
||||
}
|
||||
initial_setup(){
|
||||
setup_dirs
|
||||
setup_state_files
|
||||
|
@ -895,6 +898,7 @@ initial_setup(){
|
|||
migrate_files
|
||||
stale_symlinks
|
||||
stale_mod_signatures
|
||||
create_new_links
|
||||
local_latlon
|
||||
is_steam_running
|
||||
is_dzg_downloading
|
||||
|
|
|
@ -116,7 +116,7 @@ declare -A funcs=(
|
|||
["query_config"]="query_config"
|
||||
["start_cooldown"]="start_cooldown"
|
||||
["list_mods"]="list_mods"
|
||||
["delete"]="delete_local_mod"
|
||||
["Delete selected mods"]="delete_local_mod"
|
||||
["align_local"]="align_versions_file"
|
||||
["show_server_modlist"]="show_server_modlist"
|
||||
["test_ping"]="test_ping"
|
||||
|
@ -131,6 +131,7 @@ declare -A funcs=(
|
|||
["Handshake"]="final_handshake"
|
||||
["get_player_count"]="get_player_count"
|
||||
["lan_scan"]="lan_scan"
|
||||
["update_symlinks"]="update_symlinks"
|
||||
)
|
||||
|
||||
lan_scan(){
|
||||
|
@ -588,19 +589,34 @@ align_versions_file(){
|
|||
mv $versions_file.new $versions_file
|
||||
logger INFO "Removed local signatures for the mod '$mod'"
|
||||
}
|
||||
pluralize(){
|
||||
local plural="$1"
|
||||
local count="$2"
|
||||
local mod
|
||||
local suffix
|
||||
local base
|
||||
local ct
|
||||
local s
|
||||
|
||||
if [[ "${plural: -2}" == "es" ]]; then
|
||||
base="${plural::-2}"
|
||||
suffix="${plural: -2}"
|
||||
ct=$((count^2))
|
||||
[[ $ct -ne 3 ]] && s="$suffix"
|
||||
else
|
||||
base="${plural::-1}"
|
||||
suffix="${plural: -1}"
|
||||
ct=$((count^1))
|
||||
[[ $ct -gt 0 ]] && s="$suffix"
|
||||
fi
|
||||
|
||||
printf "%s%s" "$base" "$s"
|
||||
}
|
||||
delete_local_mod(){
|
||||
shift
|
||||
if [[ -z $1 ]]; then
|
||||
# use multi mode
|
||||
readarray -t symlinks < <(awk '{print $1}' $_cache_mods_temp)
|
||||
readarray -t ids < <(awk '{print $2}' $_cache_mods_temp)
|
||||
rm "$_cache_mods_temp"
|
||||
else
|
||||
local symlink="$1"
|
||||
local dir="$2"
|
||||
readarray -t symlinks <<< "$symlink"
|
||||
readarray -t ids <<< "$dir"
|
||||
fi
|
||||
readarray -t symlinks < <(awk '{print $1}' $_cache_mods_temp)
|
||||
readarray -t ids < <(awk '{print $2}' $_cache_mods_temp)
|
||||
rm "$_cache_mods_temp"
|
||||
for ((i=0; i<${#symlinks[@]}; i++)); do
|
||||
[[ ! -d $workshop_dir/${ids[$i]} ]] && return 1
|
||||
[[ ! -L $game_dir/${symlinks[$i]} ]] && return 1
|
||||
|
@ -608,16 +624,17 @@ delete_local_mod(){
|
|||
rm -rf "${workshop_dir:?}/${ids[$i]}" && unlink "$game_dir/${symlinks[$i]}" || return 1
|
||||
align_versions_file "align" "${ids[$i]}"
|
||||
done
|
||||
printf "Successfully deleted %s %s." "${#symlinks[@]}" "$(pluralize "mods" ${#symlinks[@]})"
|
||||
return 95
|
||||
}
|
||||
test_cooldown(){
|
||||
[[ ! -f $_cache_cooldown ]] && return 0
|
||||
local old_time=$(< $_cache_cooldown)
|
||||
local cur_time=$(date +%s)
|
||||
local delta=$(($cur_time - $old_time))
|
||||
local suffix="seconds"
|
||||
if [[ $delta -lt 60 ]]; then
|
||||
local remains=$((60 - $delta))
|
||||
[[ $remains -eq 1 ]] && suffix="second"
|
||||
local suffix=$(pluralize "seconds" $remains)
|
||||
printf "Global API cooldown in effect. Please wait %s %s." "$remains" "$suffix"
|
||||
exit 1
|
||||
fi
|
||||
|
@ -1104,7 +1121,11 @@ legacy_symlinks(){
|
|||
unlink "$d"
|
||||
fi
|
||||
done
|
||||
for d in "$workshop_dir"/*; do
|
||||
readarray -t mod_dirs < <(find "$workshop_dir" -maxdepth 1 -mindepth 1 -type d)
|
||||
[[ ${#mod_dirs[@]} -eq 0 ]] && return
|
||||
for d in "${mod_dirs[@]}"; do
|
||||
# suppress errors if mods are downloading at boot
|
||||
[[ ! -f "$d/meta.cpp" ]] && continue
|
||||
local id=$(awk -F"= " '/publishedid/ {print $2}' "$d"/meta.cpp | awk -F\; '{print $1}')
|
||||
local encoded_id=$(echo "$id" | awk '{printf("%c",$1)}' | base64 | sed 's/\//_/g; s/=//g; s/+/]/g')
|
||||
if [[ -h "$game_dir/@$encoded_id" ]]; then
|
||||
|
@ -1113,7 +1134,11 @@ legacy_symlinks(){
|
|||
done
|
||||
}
|
||||
symlinks(){
|
||||
for d in "$workshop_dir"/*; do
|
||||
readarray -t mod_dirs < <(find "$workshop_dir" -maxdepth 1 -mindepth 1 -type d)
|
||||
[[ ${#mod_dirs[@]} -eq 0 ]] && return
|
||||
for d in "${mod_dirs[@]}"; do
|
||||
# suppress errors if mods are downloading at boot
|
||||
[[ ! -f "$d/meta.cpp" ]] && continue
|
||||
id=$(awk -F"= " '/publishedid/ {print $2}' "$d"/meta.cpp | awk -F\; '{print $1}')
|
||||
encoded_id=$(encode "$id")
|
||||
link="@$encoded_id"
|
||||
|
|
|
@ -330,8 +330,8 @@ def spawn_dialog(transient_parent, msg, mode):
|
|||
|
||||
|
||||
def process_shell_return_code(transient_parent, msg, code, original_input):
|
||||
logger.info("Processing return code '%s' for the input '%s', returned message '%s'" %(code, original_input, msg))
|
||||
match code:
|
||||
#TODO: add logger output to each
|
||||
case 0:
|
||||
# success with notice popup
|
||||
spawn_dialog(transient_parent, msg, Popup.NOTIFY)
|
||||
|
@ -369,6 +369,13 @@ def process_shell_return_code(transient_parent, msg, code, original_input):
|
|||
transient_parent.grid.update_statusbar(tooltip)
|
||||
spawn_dialog(transient_parent, msg, Popup.NOTIFY)
|
||||
return
|
||||
case 95:
|
||||
# reload mods list
|
||||
spawn_dialog(transient_parent, msg, Popup.NOTIFY)
|
||||
treeview = transient_parent.grid.scrollable_treelist.treeview
|
||||
# re-block this signal before redrawing table contents
|
||||
toggle_signal(treeview, treeview, '_on_keypress', False)
|
||||
treeview.update_quad_column("List installed mods")
|
||||
case 100:
|
||||
# final handoff before launch
|
||||
final_conf = spawn_dialog(transient_parent, msg, Popup.CONFIRM)
|
||||
|
@ -427,6 +434,8 @@ def process_tree_option(input, treeview):
|
|||
else:
|
||||
# non-blocking subprocess
|
||||
subprocess.Popen(['/usr/bin/env', 'bash', funcs, "Open link", command])
|
||||
case "Delete selected mods":
|
||||
call_on_thread(True, context, "Deleting mods", command)
|
||||
case "Handshake":
|
||||
call_on_thread(True, context, "Waiting for DayZ", command)
|
||||
case _:
|
||||
|
@ -605,7 +614,9 @@ class ButtonBox(Gtk.Box):
|
|||
|
||||
# only applicable when returning from mod list
|
||||
grid = widgets["grid"]
|
||||
grid.right_panel.remove(grid.sel_panel)
|
||||
grid_last_child = grid.right_panel.get_children()[-1]
|
||||
if isinstance(grid_last_child, ModSelectionPanel):
|
||||
grid.right_panel.remove(grid.sel_panel)
|
||||
right_panel = self.get_parent()
|
||||
right_panel.set_filter_visibility(False)
|
||||
|
||||
|
@ -780,15 +791,15 @@ class TreeView(Gtk.TreeView):
|
|||
success_msg = "Successfully deleted the mod '%s'." %(value)
|
||||
fail_msg = "An error occurred during deletion. Aborting."
|
||||
res = spawn_dialog(parent, conf_msg, Popup.CONFIRM)
|
||||
symlink = self.get_column_at_index(1)
|
||||
dir = self.get_column_at_index(2)
|
||||
if res == 0:
|
||||
proc = call_out(parent, "delete", symlink, dir)
|
||||
if proc.returncode == 0:
|
||||
spawn_dialog(parent, success_msg, Popup.NOTIFY)
|
||||
self.update_quad_column("List installed mods")
|
||||
else:
|
||||
spawn_dialog(parent, fail_msg, Popup.NOTIFY)
|
||||
mods = []
|
||||
symlink = self.get_column_at_index(1)
|
||||
dir = self.get_column_at_index(2)
|
||||
concat = symlink + " " + dir + "\n"
|
||||
mods.append(concat)
|
||||
with open(mods_temp_file, "w") as outfile:
|
||||
outfile.writelines(mods)
|
||||
process_tree_option(["Delete selected mods", ""], self)
|
||||
case "Open in Steam Workshop":
|
||||
record = self.get_column_at_index(2)
|
||||
call_out(parent, "open_workshop_page", record)
|
||||
|
@ -851,6 +862,11 @@ class TreeView(Gtk.TreeView):
|
|||
self.menu.show_all()
|
||||
|
||||
if event.type is Gdk.EventType.KEY_PRESS and event.keyval is Gdk.KEY_l:
|
||||
sel = self.get_selection()
|
||||
sels = sel.get_selected_rows()
|
||||
(model, pathlist) = sels
|
||||
if len(pathlist) < 1:
|
||||
return
|
||||
self.menu.popup_at_widget(widget, Gdk.Gravity.CENTER, Gdk.Gravity.WEST)
|
||||
else:
|
||||
self.menu.popup_at_pointer(event)
|
||||
|
@ -973,8 +989,11 @@ class TreeView(Gtk.TreeView):
|
|||
|
||||
def _focus_first_row(self):
|
||||
path = Gtk.TreePath(0)
|
||||
it = mod_store.get_iter(path)
|
||||
self.get_selection().select_path(path)
|
||||
try:
|
||||
it = mod_store.get_iter(path)
|
||||
self.get_selection().select_path(path)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def get_column_at_index(self, index):
|
||||
select = self.get_selection()
|
||||
|
@ -1056,31 +1075,42 @@ class TreeView(Gtk.TreeView):
|
|||
def _background_quad(self, dialog, mode):
|
||||
def load():
|
||||
dialog.destroy()
|
||||
# detach button panel if store is empty
|
||||
if isinstance(panel_last_child, ModSelectionPanel):
|
||||
if total_mods == 0:
|
||||
right_panel.remove(grid.sel_panel)
|
||||
grid.show_all()
|
||||
right_panel.set_filter_visibility(False)
|
||||
self.set_model(mod_store)
|
||||
self.grab_focus()
|
||||
if abort is False:
|
||||
size = locale.format_string('%.3f', total_size, grouping=True)
|
||||
pretty = pluralize("mods", total_mods)
|
||||
grid.update_statusbar(f"Found {total_mods:n} {pretty} taking up {size} MiB")
|
||||
size = locale.format_string('%.3f', total_size, grouping=True)
|
||||
pretty = pluralize("mods", total_mods)
|
||||
grid.update_statusbar(f"Found {total_mods:n} {pretty} taking up {size} MiB")
|
||||
#2024-11-12
|
||||
toggle_signal(self, self.selected_row, '_on_tree_selection_changed', True)
|
||||
toggle_signal(self, self, '_on_keypress', True)
|
||||
self._focus_first_row()
|
||||
if total_mods == 0:
|
||||
spawn_dialog(self.get_outer_window(), data.stdout, Popup.NOTIFY)
|
||||
|
||||
grid = self.get_outer_grid()
|
||||
widgets = relative_widget(self)
|
||||
grid = widgets["grid"]
|
||||
right_panel = grid.right_panel
|
||||
|
||||
abort = False
|
||||
right_panel.set_filter_visibility(False)
|
||||
data = call_out(self, "list_mods", mode)
|
||||
panel_last_child = right_panel.get_children()[-1]
|
||||
|
||||
# suppress errors if no mods available on system
|
||||
if data.returncode == 1:
|
||||
abort = True
|
||||
total_mods = 0
|
||||
total_size = 0
|
||||
GLib.idle_add(load)
|
||||
spawn_dialog(self.get_outer_window(), data.stdout, Popup.NOTIFY)
|
||||
return 1
|
||||
|
||||
# attach button panel only if missing (prevents duplication when reloading in-place)
|
||||
if not isinstance(panel_last_child, ModSelectionPanel):
|
||||
right_panel.pack_start(grid.sel_panel, False, False, 0)
|
||||
grid.show_all()
|
||||
right_panel.set_filter_visibility(False)
|
||||
result = parse_mod_rows(data)
|
||||
total_size = result[0]
|
||||
total_mods = result[1]
|
||||
|
@ -1214,10 +1244,6 @@ class TreeView(Gtk.TreeView):
|
|||
if mode == "List installed mods":
|
||||
cols = mod_cols
|
||||
self.set_model(mod_store)
|
||||
# attach button panel
|
||||
grid = self.get_parent().get_parent()
|
||||
grid.right_panel.pack_start(grid.sel_panel, False, False, 0)
|
||||
grid.show_all()
|
||||
else:
|
||||
cols = log_cols
|
||||
self.set_model(log_store)
|
||||
|
@ -1988,12 +2014,7 @@ class ModSelectionPanel(Gtk.Box):
|
|||
mods.append(concat)
|
||||
with open(mods_temp_file, "w") as outfile:
|
||||
outfile.writelines(mods)
|
||||
proc = call_out(parent, "delete")
|
||||
if proc.returncode == 0:
|
||||
spawn_dialog(parent, success_msg, Popup.NOTIFY)
|
||||
treeview.update_quad_column("List installed mods")
|
||||
else:
|
||||
spawn_dialog(parent, fail_msg, Popup.NOTIFY)
|
||||
process_tree_option(["Delete selected mods", ""], treeview)
|
||||
|
||||
class FilterPanel(Gtk.Box):
|
||||
def __init__(self):
|
||||
|
|
Loading…
Reference in a new issue