diff --git a/changelog.md b/changelog.md index 6c67f02..7ea1bcb 100644 --- a/changelog.md +++ b/changelog.md @@ -4,8 +4,33 @@ - Clean up logging - Custom query API - Standardize dialogs +- Validate BM API key -## [3.0.7] 2022-11-025 +## [3.1.0] 2022-12-03 +### Added +- Recent connect history +- Simple, OS-agnostic automod installation +- Track local mod versions +- Force update local mods option +- Added python to dependencies +- File-picker driven path discovery on initial setup +### Dropped +- Headless mod installation +- Drop server ID field requirement on initial setup +### Changed +- Clean up main menu options +- Enforce Steam API key on initial setup +- More accurate path discovery on initial setup +- Add thousands separator to player counts in server browser +### Fixed +- Initial setup dialog causing early crash +- Improved error handling on initial setup to avoid malformed config files +- Delete server menu not clearing when returning to main menu +- Handle whitelist deletion when only one entry present +- Include path to drives under /run in path discovery +- Use Steam-safe local zenity version + +## [3.0.7] 2022-11-25 ### Fixed - Hotfix for server reporting multiple versions of same mod diff --git a/dzgui.sh b/dzgui.sh index ff3c358..a097aa5 100755 --- a/dzgui.sh +++ b/dzgui.sh @@ -1,7 +1,7 @@ #!/bin/bash set -o pipefail -version=3.0.7 +version=3.1.0 aid=221100 game="dayz" @@ -10,6 +10,7 @@ api="https://api.battlemetrics.com/servers" sd_res="--width=1280 --height=800" config_path="$HOME/.config/dztui/" config_file="${config_path}dztuirc" +hist_file="${config_path}/history" tmp=/tmp/dzgui.tmp fifo=/tmp/table.tmp separator="%%" @@ -31,9 +32,15 @@ km_helper_url="$releases_url/latlon" db_file="$releases_url/ips.csv.gz" sums_url="$stable_url/helpers/sums.md5" scmd_url="$stable_url/helpers/scmd.sh" +vdf2json_url="$stable_url/helpers/vdf2json.py" notify_url="$stable_url/helpers/d.html" notify_img_url="$stable_url/helpers/d.webp" forum_url="https://github.com/aclist/dztui/discussions" +version_file="$config_path/versions" +steamsafe_zenity="/usr/bin/zenity" + +#TODO: prevent connecting to offline servers +#TODO: abstract zenity title params and dimensions update_last_seen(){ mv $config_file ${config_path}dztuirc.old @@ -51,7 +58,7 @@ check_news(){ } print_news(){ check_news - if [[ $sum == $seen_news || -z $result ]]; then + if [[ $sum == $seen_news || -z $result ]]; then hchar="" news="" else @@ -60,11 +67,9 @@ print_news(){ update_last_seen fi } -#TODO: prevent connecting to offline servers -#TODO: abstract zenity title params and dimensions declare -A deps -deps=([awk]="5.1.1" [curl]="7.80.0" [jq]="1.6" [tr]="9.0" [zenity]="3.42.1" [steam]="1.0.0") +deps=([awk]="5.1.1" [curl]="7.80.0" [jq]="1.6" [tr]="9.0" [$steamsafe_zenity]="3.42.1" [steam]="1.0.0") changelog(){ if [[ $branch == "stable" ]]; then md="https://raw.githubusercontent.com/aclist/dztui/dzgui/changelog.md" @@ -96,8 +101,9 @@ items=( " Server browser" " My servers" " Quick connect to favorite server" - "[Manage servers]" " Connect by IP" + " Recent servers (last 10)" + "[Manage servers]" " Add server by ID" " Add favorite server" " Delete server" @@ -108,19 +114,14 @@ items=( "[Help]" " Help file ⧉" " Report bug ⧉" - " Become a beta tester ⧉" + " Forum ⧉" ) } -warn_and_exit(){ - zenity --info --title="DZGUI" --text="$1" --width=500 --icon-name="dialog-warning" 2>/dev/null - printf "[DZGUI] %s\n" "$check_config_msg" - exit -} warn(){ - zenity --info --title="DZGUI" --text="$1" --width=500 --icon-name="dialog-warning" 2>/dev/null + $steamsafe_zenity --info --title="DZGUI" --text="$1" --width=500 --icon-name="dialog-warning" 2>/dev/null } info(){ - zenity --info --title="DZGUI" --text="$1" --width=500 2>/dev/null + $steamsafe_zenity --info --title="DZGUI" --text="$1" --width=500 2>/dev/null } set_api_params(){ response=$(curl -s "$api" -H "Authorization: Bearer "$api_key"" -G -d "sort=-players" \ @@ -133,11 +134,7 @@ query_api(){ if [[ $one_shot_launch -eq 1 ]]; then list_of_ids="$fav" else - if [[ -n $fav ]]; then - list_of_ids="$whitelist,$fav" - else - list_of_ids="$whitelist" - fi + list_of_ids="$whitelist" fi set_api_params if [[ "$(jq -r 'keys[]' <<< "$response")" == "errors" ]]; then @@ -194,6 +191,9 @@ auto_install="$auto_install" #Automod staging directory staging_dir="$staging_dir" + +#Path to default Steam client +default_steam_path="$default_steam_path" END } write_desktop_file(){ @@ -215,7 +215,7 @@ freedesktop_dirs(){ #TODO: update url curl -s "$version_url" > "$sd_install_path/dzgui.sh" chmod +x "$sd_install_path/dzgui.sh" - img_url="https://raw.githubusercontent.com/aclist/dztui/testing/images" + img_url="$stable_url/images" for i in dzgui grid.png hero.png logo.png; do curl -s "$img_url/$i" > "$sd_install_path/$i" done @@ -224,68 +224,59 @@ freedesktop_dirs(){ write_desktop_file > "$HOME/Desktop/dzgui.desktop" fi } +find_library_folder(){ + steam_path=$(python $helpers_path/vdf2json.py -i $default_steam_path/steamapps/libraryfolders.vdf | jq -r '.libraryfolders[]|select(.apps|has("221100")).path') +} file_picker(){ while true; do - local path=$(zenity --file-selection --directory 2>/dev/null) + local path=$($steamsafe_zenity --file-selection --directory 2>/dev/null) if [[ -z "$path" ]]; then return else - echo "[DZGUI]" Set mod staging path to "$path" - staging_dir="$path" - write_config > $config_file + default_steam_path="$path" + find_library_folder + fi + if [[ -z $steam_path ]]; then + warn "DayZ not found at this path." + else return fi done } -guess_path(){ - echo "# Checking for default DayZ path" - path=$(find $HOME -type d -regex ".*/steamapps/common/DayZ$" -print -quit) - if [[ -n "$path" ]]; then - clean_path=$(echo -e "$path" | awk -F"/steamapps" '{print $1}') - steam_path="$clean_path" - else - echo "# Searching for alternate DayZ path. This may take some time." - path=$(find / -type d \( -path "/proc" -o -path "*/timeshift" -o -path "/tmp" -o -path "/usr" -o -path "/boot" -o -path "/proc" -o -path "/root" -o -path "/sys" -o -path "/etc" -o -path "/var" -o -path "/lost+found" \) -prune -o -regex ".*/steamapps/common/DayZ$" -print -quit 2>/dev/null) - clean_path=$(echo -e "$path" | awk -F"/steamapps" '{print $1}') - steam_path="$clean_path" - fi -} create_config(){ + check_pyver while true; do - player_input="$(zenity --forms --add-entry="Player name (required for some servers)" --add-entry="API key" --add-entry="Server 1 (you can add more later)" --title="DZGUI" --text="DZGUI" --add-entry="Server 2" --add-entry="Server 3" --add-entry="Server 4" $sd_res --separator="│" 2>/dev/null)" - #explicitly setting IFS crashes zenity in loop - #and mapfile does not support high ascii delimiters - #so split fields with newline - readarray -t args < <(echo "$player_input" | sed 's/│/\n/g') - name="${args[0]}" - api_key="${args[1]}" - server_1="${args[2]}" - server_2="${args[3]}" - server_3="${args[4]}" - server_4="${args[5]}" + player_input="$($steamsafe_zenity --forms --add-entry="Player name (required for some servers)" --add-entry="BattleMetrics API key" --add-entry="Steam API key" --title="DZGUI" --text="DZGUI" $sd_res --separator="│" 2>/dev/null)" + #explicitly setting IFS crashes $steamsafe_zenity in loop + #and mapfile does not support high ascii delimiters + #so split fields with newline + readarray -t args < <(echo "$player_input" | sed 's/│/\n/g') + name="${args[0]}" + api_key="${args[1]}" + steam_api="${args[2]}" - [[ -z $player_input ]] && exit - if [[ -z $api_key ]]; then - warn "API key: invalid value" - elif [[ -z $server_1 ]]; then - warn "Server 1: cannot be empty" - elif [[ ! $server_1 =~ ^[0-9]+$ ]]; then - warn "Server 1: only numeric IDs" - elif [[ -n $server_2 ]] && [[ ! $server_2 =~ ^[0-9]+$ ]]; then - warn "Server 2: only numeric IDs" - elif [[ -n $server_3 ]] && [[ ! $server_3 =~ ^[0-9]+$ ]]; then - warn "Server 3: only numeric IDs" - elif [[ -n $server_4 ]] && [[ ! $server_3 =~ ^[0-9]+$ ]]; then - warn "Server 4: only numeric IDs" - else - whitelist=$(echo "$player_input" | awk -F"│" '{OFS=","}{print $3,$4,$5,$6}' | sed 's/,*$//g' | sed 's/^,*//g') - guess_path > >(zenity --width 500 --progress --auto-close --pulsate 2>/dev/null) && - echo "[DZGUI] Set path to $steam_path" - #FIXME: tech debt: gracefully exit if user cancels search process - mkdir -p $config_path; write_config > $config_file - info "Config file created at $config_file." - return - fi + [[ -z $player_input ]] && exit + if [[ -z $api_key ]] || [[ -z $steam_api ]]; then + warn "API key: invalid value" + #TODO: test BM key + elif [[ $(test_steam_api) -eq 1 ]]; then + warn "Invalid Steam API key" + else + while true; do + find_default_path + find_library_folder + if [[ -z $steam_path ]]; then + zenity --question --text="DayZ not found or not installed at the chosen path." --ok-label="Retry" --cancel-label="Exit" + [[ $? -eq 1 ]] && exit + else + mkdir -p $config_path + write_config > $config_file + info "Config file created at $config_file." + source $config_file + return + fi + done + fi done } @@ -293,17 +284,21 @@ err(){ printf "[ERROR] %s\n" "$1" } varcheck(){ - [[ -z $api_key ]] && (err "Error in key: 'api_key'") - [[ -z $whitelist ]] && (err "Error in key: 'whitelist'") - [[ ! -d "$game_dir" ]] && (err "Malformed game path") - [[ $whitelist =~ [[:space:]] ]] && (err "Separate whitelist values with commas") + if [[ -z $api_key ]] || [[ ! -d $steam_path ]] || [[ ! -d $game_dir ]]; then + echo 1 + fi } run_depcheck(){ - if [[ -z $(depcheck) ]]; then - : - else + if [[ -n $(depcheck) ]]; then echo "100" - zenity --warning --ok-label="Exit" --title="DZGUI" --text="$(depcheck)" + $steamsafe_zenity --warning --ok-label="Exit" --title="DZGUI" --text="$(depcheck)" + exit + fi +} +check_pyver(){ + pyver=$(python --version | awk '{print $2}') + if [[ -z $pyver ]] || [[ ${pyver:0:1} -lt 3 ]]; then + warn "Requires python >=3.0" && exit fi } @@ -311,26 +306,21 @@ run_varcheck(){ source $config_file workshop_dir="$steam_path/steamapps/workshop/content/$aid" game_dir="$steam_path/steamapps/common/DayZ" - if [[ -z $(varcheck) ]]; then - : - else - zenity --warning --width 500 --text="$(varcheck)" 2>/dev/null - printf "[DZGUI] %s\n" "$check_config_msg" - zenity --question --cancel-label="Exit" --text="Malformed config file. This is probably user error.\nStart first-time setup process again?" --width=500 2>/dev/null + if [[ $(varcheck) -eq 1 ]]; then + $steamsafe_zenity --question --cancel-label="Exit" --text="Malformed config file. This is probably user error.\nStart first-time setup process again?" --width=500 2>/dev/null code=$? if [[ $code -eq 1 ]]; then exit else - echo "100" create_config fi fi } config(){ if [[ ! -f $config_file ]]; then - zenity --width 500 --info --text="Config file not found. Click OK to proceed to first-time setup." 2>/dev/null + $steamsafe_zenity --width 500 --info --text="Config file not found. Click OK to proceed to first-time setup." 2>/dev/null code=$? - #prevent progress if user hits ESC + #TODO: prevent progress if user hits ESC if [[ $code -eq 1 ]]; then exit else @@ -340,92 +330,28 @@ config(){ source $config_file fi -} -open_mod_links(){ - link_file=$(mktemp) - echo "" > $link_file - echo "DZGUI" >> $link_file - echo "

DZGUI

" >> $link_file - echo "

Open these links and subscribe to them on the Steam Workshop, then continue with the application prompts.
Note: it may take some time for mods to synchronize before DZGUI can see them.
It can help to have Steam in an adjacent window so that you can see the downloads completing.

" >> $link_file - n=1 - for i in $diff; do - echo "$n. ${workshop}$i
" - let n++ - done >> $link_file - echo "" >> $link_file - browser "$link_file" 2>/dev/null & - } steam_deck_mods(){ until [[ -z $diff ]]; do next=$(echo -e "$diff" | head -n1) - zenity --question --ok-label="Open" --cancel-label="Cancel" --title="DZGUI" --text="Missing mods. Click [Open] to open mod $next in Steam Workshop and subscribe to it by clicking the green Subscribe button. After the mod is downloaded, return to this menu to continue validation." --width=500 2>/dev/null + $steamsafe_zenity --question --ok-label="Open" --cancel-label="Cancel" --title="DZGUI" --text="Missing mods. Click [Open] to open mod $next in Steam Workshop and subscribe to it by clicking the green Subscribe button. After the mod is downloaded, return to this menu to continue validation." --width=500 2>/dev/null rc=$? if [[ $rc -eq 0 ]]; then echo "[DZGUI] Opening ${workshop}$next" steam steam://url/CommunityFilePage/$next 2>/dev/null & - zenity --info --title="DZGUI" --ok-label="Next" --text="Click [Next] to continue mod check." --width=500 2>/dev/null + $steamsafe_zenity --info --title="DZGUI" --ok-label="Next" --text="Click [Next] to continue mod check." --width=500 2>/dev/null else return 1 fi compare done } -set_term(){ - local term="$1" - local tterm="term=\"$term\"" - mv $config_file ${config_path}dztuirc.old - nr=$(awk '/term=/ {print NR}' ${config_path}dztuirc.old) - awk -v "var=$tterm" -v "nr=$nr" 'NR==nr {$0=var}{print}' ${config_path}dztuirc.old > $config_file - printf "[DZGUI] Set term to '$term'\n" - source $config_file -} -sel_term(){ - #only terminals known to support -e flag - for i in "$TERMINAL" urxvt alacritty konsole gnome-terminal terminator xfce4-terminal xterm tilix; do - [[ $(command -v $i) ]] && terms+=($i) - done - #FIXME: if no terms, error - local terms=$(printf "%s\n" "${terms[@]}" | sort -u) - term=$(echo "$terms" | zenity --list --column=Terminal --height=800 --width=1200 --text="Select your preferred terminal emulator to run steamcmd (setting will be saved)" --title=DZGUI 2>/dev/null) -} calc_mod_sizes(){ for i in "$diff"; do local mods+=$(grep -w "$i" /tmp/modsizes | awk '{print $1}') done totalmodsize=$(echo -e "${mods[@]}" | awk '{s+=$1}END{print s}') } -term_params(){ - case $term in - konsole) $term --hold -e "bash $helpers_path/scmd.sh $totalmodsize $1";; - urxvt) $term -e bash -c "/$helpers_path/scmd.sh $totalmodsize $1";; - alacritty) $term -e bash -c "/$helpers_path/scmd.sh $totalmodsize $1";; - terminator|xterm|tilix|xfce4-terminal) $term -e "bash $helpers_path/scmd.sh $totalmodsize $1";; - esac -} -auto_mod_install(){ - cmd=$(printf "%q " "$@") - if [[ -z "$term" ]]; then - if [[ $is_steam_deck -eq 1 ]]; then - set_term konsole - return 0 - else - sel_term && set_term "$term" - fi - fi - [[ -z "$term" ]] && return 1 - echo "[DZGUI] Kicking off auto mod script" - calc_mod_sizes - term_params "$cmd" - compare - if [[ -z $diff ]]; then - passed_mod_check > >(zenity --pulsate --progress --auto-close --width=500 2>/dev/null) - launch - else - warn "Auto mod installation failed or some mods missing.\nReverting to manual mode." - return 1 - fi -} test_display_mode(){ pgrep -a gamescope | grep -q "generate-drm-mode" [[ $? -eq 0 ]] && gamemode=1 @@ -474,34 +400,16 @@ manual_mod_install(){ done echo "100" } - watcher > >(zenity --pulsate --progress --auto-close --title="DZG Watcher" --width=500 2>/dev/null; rc=$?; [[ $rc -eq 1 ]] && touch $ex) + watcher > >($steamsafe_zenity --pulsate --progress --auto-close --title="DZG Watcher" --width=500 2>/dev/null; rc=$?; [[ $rc -eq 1 ]] && touch $ex) compare if [[ -z $diff ]]; then - passed_mod_check > >(zenity --pulsate --progress --auto-close --width=500 2>/dev/null) + passed_mod_check > >($steamsafe_zenity --pulsate --progress --auto-close --width=500 2>/dev/null) launch else return 1 fi fi } -# if [[ $is_steam_deck -eq 0 ]]; then -# open_mod_links -# until [[ -z $diff ]]; do -# zenity --question --title="DZGUI" --ok-label="Next" --cancel-label="Cancel" --text="Opened mod links in browser.\nClick [Next] when all mods have been subscribed to.\nThis dialog may reappear if clicking [Next] too soon\nbefore mods are synchronized in the background." --width=500 2>/dev/null -# rc=$? -# if [[ $rc -eq 0 ]]; then -# compare -# open_mod_links -# else -# return -# fi -# done -# else -# steam_deck_mods -# rc=$? -# [[ $rc -eq 1 ]] && return 1 -# fi -# passed_mod_check > >(zenity --pulsate --progress --auto-close --width=500 2>/dev/null) encode(){ echo "$1" | md5sum | cut -c -8 } @@ -541,12 +449,112 @@ symlinks(){ passed_mod_check(){ echo "[DZGUI] Passed mod check" echo "# Preparing symlinks" - stale_symlinks legacy_symlinks symlinks echo "100" } +auto_mod_install(){ + popup 300 + rc=$? + if [[ $rc -eq 0 ]]; then + calc_mod_sizes + local total_size=$(numfmt --to=iec $totalmodsize) + log="$default_steam_path/logs/content_log.txt" + [[ -f "/tmp/dz.status" ]] && rm "/tmp/dz.status" + touch "/tmp/dz.status" + console_dl "$diff" && + steam steam://open/downloads && 2>/dev/null 1>&2 + until [[ -z $(comm -23 <(printf "%s\n" "${modids[@]}" | sort) <(ls -1 $workshop_dir | sort)) ]]; do + win=$(xdotool search --name "DZG Watcher") + [[ ! $(xdotool getwindowfocus) -eq $win ]] && xdotool windowraise $win + local missing=$(comm -23 <(printf "%s\n" "${modids[@]}" | sort) <(ls -1 $workshop_dir | sort) | wc -l) + echo "# Downloaded $((${#modids[@]}-missing)) of ${#modids[@]} mods" + done | $steamsafe_zenity --pulsate --progress --title="DZG Watcher" --auto-close --no-cancel --width=500 2>/dev/null + compare + [[ $force_update -eq 1 ]] && { unset force_update; return; } + if [[ -z $diff ]]; then + check_timestamps + passed_mod_check > >($steamsafe_zenity --pulsate --progress --title=DZGUI --auto-close --width=500 2>/dev/null) + launch + else + manual_mod_install + fi + else + manual_mod_install + fi +} +get_local_stamps(){ + concat(){ + for ((i=0;i<$max;i++)); do + echo "publishedfileids[$i]=${local_modlist[$i]}&" + done | awk '{print}' ORS='' + } + payload(){ + echo -e "itemcount=${max}&$(concat)" + } + post(){ + curl -s -X POST -H "Content-Type:application/x-www-form-urlencoded" \ + -d "$(payload)" 'https://api.steampowered.com/ISteamRemoteStorage/GetPublishedFileDetails/v1/?format=json' + } + post +} +update_stamps(){ + for((i=0;i<${#local_modlist[@]};i++)); do + mod=${local_modlist[$i]} + stamp=${stamps[$i]} + printf "%s\t%s\n" "$mod" "$stamp" >> $version_file + done +} +check_timestamps(){ + readarray -t local_modlist < <(ls -1 $workshop_dir) + max=${#local_modlist[@]} + readarray -t stamps < <(get_local_stamps | jq -r '.response.publishedfiledetails[].time_updated') + if [[ ! -f $version_file ]]; then + update_stamps + return + else + needs_update=() + for((i=0;i<${#local_modlist[@]};i++)); do + mod=${local_modlist[$i]} + stamp=${stamps[$i]} + if [[ ! $(awk -v var=$mod '$1 == var' $version_file) ]]; then + echo -e "$mod\t$stamp" >> $version_file + elif [[ $(awk -v var=$mod -v var2=$stamp '$1 == var && $2 == var2' $version_file) ]]; then + : + else + awk -v var=$mod -v var2=$stamp '$1 == var {$2=var2;print $1"\t"$2; next;};{print}' $version_file > $version_file.new + mv $version_file.new $version_file + needs_update+=($mod) + fi + done + fi +} +merge_modlists(){ + [[ $force_update -eq 1 ]] && echo "# Checking mod versions" + check_timestamps + if [[ -z "$diff" ]] && [[ ${#needs_update[@]} -gt 0 ]]; then + diff=$(printf "%s\n" "${needs_update[@]}") + elif [[ -z "$diff" ]] && [[ ${#needs_update[@]} -eq 0 ]]; then + diff= + elif [[ -n "$diff" ]] && [[ ${#needs_update[@]} -eq 0 ]]; then + : + else + diff="$(echo -e "$diff\n${needs_update[@]}")" + fi + [[ $force_update -eq 1 ]] && echo "100" +} +update_history(){ + [[ -n $(grep "$ip" $hist_file) ]] && return + if [[ -f $hist_file ]]; then + old=$(tail -n9 "$hist_file") + old="$old\n" + fi + echo -e "${old}${ip}" > "$hist_file" +} +is_steam_running(){ + xdotool search --desktop "$(xdotool get_desktop)" --name "Steam" +} connect(){ #TODO: sanitize/validate input readarray -t qport_arr <<< "$qport_list" @@ -557,7 +565,7 @@ connect(){ ip=$(echo "$1" | awk -F"$separator" '{print $1}') bid=$(echo "$1" | awk -F"$separator" '{print $2}') if [[ $2 == "ip" ]]; then - fetch_mods_sa "$ip" > >(zenity --pulsate --progress --auto-close --no-cancel --width=500 2>/dev/null) + fetch_mods_sa "$ip" > >($steamsafe_zenity --pulsate --progress --auto-close --no-cancel --width=500 2>/dev/null) else fetch_mods "$bid" fi @@ -569,16 +577,16 @@ connect(){ rc=$? [[ $rc -eq 1 ]] && return compare + [[ $auto_install -eq 2 ]] && merge_modlists if [[ -n $diff ]]; then - if [[ $auto_install -eq 1 ]]; then - auto_mod_install "$diff" - rc=$? - [[ $rc -eq 1 ]] && manual_mod_install - else - manual_mod_install - fi + [[ -z $(is_steam_running) ]] && { $steamsafe_zenity --info --text "Steam must be running on the current desktop to use this feature."; return; } + case $auto_install in + 1|2) auto_mod_install ;; + *) manual_mod_install ;; + esac else - passed_mod_check > >(zenity --pulsate --progress --auto-close --width=500 2>/dev/null) + passed_mod_check > >($steamsafe_zenity --pulsate --progress --auto-close --width=500 2>/dev/null) + update_history launch fi } @@ -600,7 +608,7 @@ fetch_mods_sa(){ if [[ $status -eq 1 ]]; then echo "100" err "97: Failed to fetch modlist" - zenity --error --title="DZGUI" --width=500 --text="[ERROR] 97: Failed to fetch modlist" 2>/dev/null && + $steamsafe_zenity --error --title="DZGUI" --width=500 --text="[ERROR] 97: Failed to fetch modlist" 2>/dev/null && ret=96 return fi @@ -624,10 +632,46 @@ prepare_ip_list(){ echo "$time" done } +history_table(){ + [[ -f /tmp/dz.hist ]] && rm /tmp/dz.hist + for i in $(cat $hist_file); do + echo "# Getting metadata for $i" + local meta_file=$(mktemp) + source $config_file + local url="https://api.steampowered.com/IGameServersService/GetServerList/v1/?filter=\appid\221100\gameaddr\\$i&key=$steam_api" + curl -Ls "$url" > $meta_file + json=$(mktemp) + < $meta_file jq '.response' > $json + res=$(< $meta_file jq -er '.response.servers[]' 2>/dev/null) + prepare_ip_list "$meta_file" >> /tmp/dz.hist + sleep 0.5s + done | $steamsafe_zenity --pulsate --progress --auto-close --title=DZGUI --width=500 --no-cancel 2>/dev/null + [[ $? -eq 1 ]] && return + while true; do + sel=$(cat /tmp/dz.hist | $steamsafe_zenity --width 1200 --height 800 --title=DZGUI --text="Recent servers" --list --column=Name --column=IP --column=Players --column=Gametime --print-column=2 --separator=%% 2>/dev/null) + if [[ $? -eq 1 ]]; then + return_from_table=1 + rm /tmp/dz.hist + return + fi + if [[ -z $sel ]]; then + echo "No selection" + else + local gameport="$(echo "$sel" | awk -F: '{print $2}')" + local ip="$(echo "$sel" | awk -F: '{print $1}')" + local addr=$(< $json jq -r --arg gameport $gameport '.servers[]|select(.gameport == ($gameport|tonumber)).addr') + local qport=$(echo "$addr" | awk -F: '{print $2}') + local sa_ip=$(echo "$ip:$gameport%%$qport") + qport_list="$sa_ip" + connect "$sel" "ip" + fi + done + rm /tmp/dz.hist +} ip_table(){ while true; do - sel=$(prepare_ip_list "$meta_file" | zenity --width 1200 --height 800 --list --column=Name --column=IP --column=Players --column=Gametime --print-column=2 --separator=%% 2>/dev/null) + sel=$(prepare_ip_list "$meta_file" | $steamsafe_zenity --width 1200 --height 800 --list --column=Name --column=IP --column=Players --column=Gametime --print-column=2 --separator=%% 2>/dev/null) if [[ $? -eq 1 ]]; then return_from_table=1 return @@ -679,16 +723,16 @@ add_steam_api(){ steam_api="steam_api=\"$steam_api\"" awk -v "var=$steam_api" -v "nr=$nr" 'NR==nr {$0=var}{print}' ${config_path}dztuirc.old > ${config_path}dztuirc echo "[DZGUI] Added Steam API key" - zenity --info --title="DZGUI" --text="Added Steam API key to:\n\n${config_path}dztuirc\nIf errors occur, you can restore the file:\n${config_path}dztuirc.old" --width=500 2>/dev/null + $steamsafe_zenity --info --title="DZGUI" --text="Added Steam API key to:\n\n${config_path}dztuirc\nIf errors occur, you can restore the file:\n${config_path}dztuirc.old" --width=500 2>/dev/null source $config_file } check_steam_api(){ if [[ -z $steam_api ]]; then - steam_api=$(zenity --entry --text="Key 'steam_api' not present in config file. Enter Steam API key:" --title="DZGUI" 2>/dev/null) + steam_api=$($steamsafe_zenity --entry --text="Key 'steam_api' not present in config file. Enter Steam API key:" --title="DZGUI" 2>/dev/null) if [[ $? -eq 1 ]] ; then return elif [[ ${#steam_api} -lt 32 ]] || [[ $(test_steam_api) -eq 1 ]]; then - zenity --warning --title="DZGUI" --text="Check API key and try again." 2>/dev/null + $steamsafe_zenity --warning --title="DZGUI" --text="Check API key and try again." 2>/dev/null return 1 else add_steam_api @@ -707,7 +751,7 @@ connect_by_ip(){ return_from_table=0 return fi - ip=$(zenity --entry --text="Enter server IP (omit port)" --title="DZGUI" 2>/dev/null) + ip=$($steamsafe_zenity --entry --text="Enter server IP (omit port)" --title="DZGUI" 2>/dev/null) [[ $? -eq 1 ]] && return if validate_ip "$ip"; then fetch_ip_metadata @@ -773,19 +817,19 @@ launch(){ if [[ $debug -eq 1 ]]; then launch_options="steam -applaunch $aid -connect=$ip -nolauncher -nosplash -name=$name -skipintro \"-mod=$mods\"" print_launch_options="$(printf "This is a dry run.\nThese options would have been used to launch the game:\n\n$launch_options\n" | fold -w 60)" - zenity --question --title="DZGUI" --ok-label="Write to file" --cancel-label="Back"\ + $steamsafe_zenity --question --title="DZGUI" --ok-label="Write to file" --cancel-label="Back"\ --text="$print_launch_options" 2>/dev/null if [[ $? -eq 0 ]]; then source_script=$(realpath "$0") source_dir=$(dirname "$source_script") echo "$launch_options" > "$source_dir"/options.log echo "[DZGUI] Wrote launch options to $source_dir/options.log" - zenity --info --width 500 --title="DZGUI" --text="Wrote launch options to \n$source_dir/options.log" 2>/dev/null + $steamsafe_zenity --info --width 500 --title="DZGUI" --text="Wrote launch options to \n$source_dir/options.log" 2>/dev/null fi else echo "[DZGUI] All OK. Launching DayZ" - zenity --width 500 --title="DZGUI" --info --text="Launch conditions satisfied.\nDayZ will now launch after clicking [OK]." 2>/dev/null + $steamsafe_zenity --width 500 --title="DZGUI" --info --text="Launch conditions satisfied.\nDayZ will now launch after clicking [OK]." 2>/dev/null steam -applaunch $aid -connect=$ip -nolauncher -nosplash -skipintro -name=$name \"-mod=$mods\" exit fi @@ -830,31 +874,31 @@ set_mode(){ fi } delete_by_id(){ - new_whitelist="whitelist=\"$(echo "$whitelist" | sed "s/,$server_id$//;s/^$server_id,//;s/,$server_id,/,/")\"" + new_whitelist="whitelist=\"$(echo "$whitelist" | sed "s/,$server_id$//;s/^$server_id,//;s/,$server_id,/,/;s/^$server_id$//")\"" mv $config_file ${config_path}dztuirc.old nr=$(awk '/whitelist=/ {print NR}' ${config_path}dztuirc.old) awk -v "var=$new_whitelist" -v "nr=$nr" 'NR==nr {$0=var}{print}' ${config_path}dztuirc.old > ${config_path}dztuirc echo "[DZGUI] Removed $server_id from key 'whitelist'" - zenity --info --title="DZGUI" --text="Removed "$server_id" from:\n${config_path}dztuirc\nIf errors occur, you can restore the file:\n${config_path}dztuirc.old" --width=500 2>/dev/null + $steamsafe_zenity --info --title="DZGUI" --text="Removed "$server_id" from:\n${config_path}dztuirc\nIf errors occur, you can restore the file:\n${config_path}dztuirc.old" --width=500 2>/dev/null source $config_file } delete_or_connect(){ if [[ $delete -eq 1 ]]; then server_name=$(echo "$sel" | awk -F"%%" '{print $1}') server_id=$(echo "$sel" | awk -F"%%" '{print $2}') - zenity --question --text="Delete this server? \n$server_name" + $steamsafe_zenity --question --text="Delete this server? \n$server_name" --title=DZGUI --width=500 2>/dev/null if [[ $? -eq 0 ]]; then delete_by_id $server_id fi + source $config_file + unset delete else #hotfix for bug #36 local lookup_ip=$(echo "$sel" | awk -F%% '{print $1}') local lookup_port=$(echo "$lookup_ip" | awk -F: '{print $2}') source $config_file - file=$(mktemp) url="https://api.steampowered.com/IGameServersService/GetServerList/v1/?filter=\appid\221100\gameaddr\\$lookup_ip&key=$steam_api" - curl -Ls "$url" > $file - local qport_res=$(< $file jq -r --arg port $lookup_port '.response.servers[]|select(.gameport==($port|tonumber)).addr') + local qport_res=$(curl -Ls "$url" | jq -r --arg port $lookup_port '.response.servers[]|select(.gameport==($port|tonumber)).addr') local qport=$(echo "$qport_res" | awk -F: '{print $2}') qport_list="$lookup_ip%%$qport" connect "$qport_list" "ip" @@ -886,7 +930,7 @@ populate(){ } list_mods(){ if [[ -z $(installed_mods) ]] || [[ -z $(find $workshop_dir -maxdepth 2 -name "*.cpp" | grep .cpp) ]]; then - zenity --info --text="94: No mods currently installed or incorrect path given" $sd_res 2>/dev/null + $steamsafe_zenity --info --text="94: No mods currently installed or incorrect path given" $sd_res 2>/dev/null else for d in $(find $game_dir/* -maxdepth 1 -type l); do dir=$(basename $d) @@ -911,16 +955,17 @@ connect_to_fav(){ } set_header(){ - [[ $auto_install -eq 1 ]] && install_mode=auto + [[ $auto_install -eq 2 ]] && install_mode="auto" + [[ $auto_install -eq 1 ]] && install_mode="headless" [[ $auto_install -eq 0 ]] && install_mode=manual if [[ $1 == "delete" ]]; then - sel=$(cat $tmp | zenity $sd_res --list $cols --title="DZGUI" --text="DZGUI $version | Mode: $mode | Branch: $branch | Mods: $install_mode | Fav: $fav_label" \ + sel=$(cat $tmp | $steamsafe_zenity $sd_res --list $cols --title="DZGUI" --text="DZGUI $version | Mode: $mode | Branch: $branch | Mods: $install_mode | Fav: $fav_label" \ --separator="$separator" --print-column=1,2 --ok-label="Delete" 2>/dev/null) elif [[ $1 == "populate" ]]; then - sel=$(cat $tmp | zenity $sd_res --list $cols --title="DZGUI" --text="DZGUI $version | Mode: $mode | Branch: $branch | Mods: $install_mode | Fav: $fav_label" \ + sel=$(cat $tmp | $steamsafe_zenity $sd_res --list $cols --title="DZGUI" --text="DZGUI $version | Mode: $mode | Branch: $branch | Mods: $install_mode | Fav: $fav_label" \ --separator="$separator" --print-column=2,6 2>/dev/null) elif [[ $1 == "main_menu" ]]; then - sel=$(zenity $sd_res --list --title="DZGUI" --text="${news}DZGUI $version | Mode: $mode | Branch: $branch | Mods: $install_mode | Fav: $fav_label" \ + sel=$($steamsafe_zenity $sd_res --list --title="DZGUI" --text="${news}DZGUI $version | Mode: $mode | Branch: $branch | Mods: $install_mode | Fav: $fav_label" \ --cancel-label="Exit" --ok-label="Select" --column="Select launch option" --hide-header "${items[@]}" 2>/dev/null) fi } @@ -943,7 +988,6 @@ generate_log(){ Version: $version Branch: $branch Whitelist: $whitelist - Path: $steam_path Steam path: $steam_path Workshop path: $workshop_dir Game path: $game_dir @@ -952,50 +996,100 @@ generate_log(){ $(list_mods) DOC } -automods_prompt(){ -cat <<- HERE - -Auto-mod installation set to ON. This method is NOT supported in Game Mode (Steam Deck). - -READ THIS FIRST: -With this setting on, DZGUI will attempt to download and prepare mods using Valve's steamcmd tool. - -The first time this process is run, DZGUI will ask you to select a terminal emulator of your preference to spawn the installation routine. If you don't have a preference or don't know, you can pick any. - -Installation will kick off in a separate window and may ask you for input such as your sudo password in order to install system packages and create the steamcmd user. - -steamcmd itself will ask for your Steam credentials. This information is used directly by Valve's steamcmd tool to authenticate your account and let you download mods headlessly. steamcmd is an official program created by Valve and communicates only with their servers. - -NOTE: it can take some time for large mods to download, and steamcmd will not inform you of activity until each one is finished downloading. - -If your distribution is unsupported, you don't have enough disk space to stage all of the mods, or there are other problems, DZGUI will warn you and write a report to $HOME/.local/share/dzgui/helpers/SCMD.log. You can attach this file to a bug report. -HERE +console_dl(){ + readarray -t modids <<< "$@" + steam steam://open/console 2>/dev/null 1>&2 && + sleep 1s + #https://github.com/jordansissel/xdotool/issues/67 + local wid=$(xdotool search --desktop "$(xdotool get_desktop)" --name Steam) + xdotool windowactivate $wid + for i in "${modids[@]}"; do + xdotool type --delay 15 "workshop_download_item $aid $i" + sleep 0.2s + xdotool key Return + sleep 0.2s + done } -toggle_automods(){ +find_default_path(){ + discover(){ + echo "# Searching for Steam" + default_steam_path=$(find / -type d \( -path "/proc" -o -path "*/timeshift" -o -path \ + "/tmp" -o -path "/usr" -o -path "/boot" -o -path "/proc" -o -path "/root" \ + -o -path "/sys" -o -path "/etc" -o -path "/var" -o -path "/lost+found" \) -prune \ + -o -regex ".*/Steam/ubuntu12_32$" -print -quit 2>/dev/null | sed 's@/ubuntu12_32@@') + } + if [[ $is_steam_deck -eq 1 ]]; then + default_steam_path="$HOME/.local/share/Steam" + else + #default + if [[ -d "$HOME/.local/share/Steam" ]]; then + default_steam_path="$HOME/.local/share/Steam" + #ubuntu + elif [[ -d "$HOME/.steam/steam" ]]; then + default_steam_path="$HOME/.steam/steam" + else + local res=$(echo -e "Let DZGUI auto-discover Steam path (accurate, slower)\nSelect the Steam path manually (less accurate, faster)" | $steamsafe_zenity --list --column="Choice" --title=DZGUI --hide-header --text="Steam is not installed in a standard location." $sd_res) + case "$res" in + *auto*) discover ;; + *manual*) + zenity --info --text="\nSelect the top-level path to the Steam library folder containing \"steamapps\".\n\nE.g., if DayZ is installed at:\n\"/media/mydrive/steamapps/common/DayZ\"\n\nYou should select:\n\"/media/mydrive\"" --width=500 && + file_picker ;; + esac + fi + fi +} +popup(){ + pop(){ + $steamsafe_zenity --info --text="$1" --title=DZGUI --width=500 2>/dev/null + } + case "$1" in + 100) pop "This feature requires xdotool.";; + 200) pop "This feature is not supported on Gaming Mode.";; + 300) pop "\nThe Steam console will now open and briefly issue commands to\ndownload the workshop files, then return to the download progress page.\n\nEnsure that the Steam console has keyboard and mouse focus\n(keep hands off keyboard) while the commands are being issued.\n\nDepending on the number if mods, it may take some time to queue the downloads,\nbut if a popup or notification window steals focus, it could obstruct\nthe process." ;; + 400) pop "Automod install enabled. Auto-downloaded mods will not appear\nin your Steam Workshop subscriptions, but DZGUI will\ntrack the version number of downloaded mods internally\nand trigger an update if necessary." ;; + 500) pop "Automod install disabled.\nSwitched to manual mode." ;; + 600) pop "No preferred servers set." ;; + esac +} +toggle_console_dl(){ + [[ $is_steam_deck -eq 1 ]] && test_display_mode + [[ $gamemode -eq 1 ]] && { popup 200; return; } + [[ ! $(command -v xdotool) ]] && { popup 100; return; } mv $config_file ${config_path}dztuirc.old local nr=$(awk '/auto_install=/ {print NR}' ${config_path}dztuirc.old) - if [[ $auto_install == "1" ]]; then + if [[ $auto_install == "2" ]]; then auto_install="0" + popup 500 else - auto_install="1" + auto_install="2" + popup 400 fi local flip_state="auto_install=\"$auto_install\"" awk -v "var=$flip_state" -v "nr=$nr" 'NR==nr {$0=var}{print}' ${config_path}dztuirc.old > $config_file - printf "[DZGUI] Toggled auto-mod install to '$auto_install'\n" + printf "[DZGUI] Set mod install to '$auto_install'\n" source $config_file - local big_prompt - [[ $is_steam_deck -eq 1 ]] && big_prompt="--width=800" - [[ $auto_install == "1" ]] && zenity --info --text="$(automods_prompt)" $big_prompt 2>/dev/null +} +force_update_mods(){ + if [[ -f $version_file ]]; then + awk '{OFS="\t"}{$2="000"}1' $version_file > /tmp/versions + mv /tmp/versions $version_file + fi } options_menu(){ + case "$auto_install" in + 0|1|"") auto_hr="OFF"; ;; + 2) auto_hr="ON"; ;; + esac debug_list=( "Toggle branch" "Toggle debug mode" "Generate debug log" - "Toggle auto-mod install (experimental)" - "Set auto-mod staging directory [$staging_dir]" + "Toggle auto mod install [$auto_hr]" ) - debug_sel=$(zenity --list --width=1280 --height=800 --column="Options" --title="DZGUI" --hide-header "${debug_list[@]}" 2>/dev/null) + #TODO: tech debt: drop old flags + [[ $auto_install -eq 2 ]] || [[ $auto_install -eq 1 ]] && debug_list+=("Force update local mods") + debug_sel=$($steamsafe_zenity --list --width=1280 --height=800 --column="Options" --title="DZGUI" --hide-header "${debug_list[@]}" 2>/dev/null) + [[ -z $debug_sel ]] && return if [[ $debug_sel == "${debug_list[0]}" ]]; then enforce_dl=1 toggle_branch && @@ -1005,22 +1099,27 @@ options_menu(){ elif [[ $debug_sel == "${debug_list[2]}" ]]; then source_script=$(realpath "$0") source_dir=$(dirname "$source_script") - generate_log > "$source_dir/log" + generate_log > "$source_dir/DZGUI.log" printf "[DZGUI] Wrote log file to %s/log\n" "$source_dir" - zenity --info --width 500 --title="DZGUI" --text="Wrote log file to \n$source_dir/log" 2>/dev/null + $steamsafe_zenity --info --width 500 --title="DZGUI" --text="Wrote log file to \n$source_dir/log" 2>/dev/null elif [[ $debug_sel == "${debug_list[3]}" ]]; then - toggle_automods + toggle_console_dl elif [[ $debug_sel == "${debug_list[4]}" ]]; then - file_picker + force_update=1 + force_update_mods + merge_modlists > >($steamsafe_zenity --pulsate --progress --no-cancel --auto-close --title=DZGUI --width=500 2>/dev/null) + [[ -z $(is_steam_running) ]] && { $steamsafe_zenity --info --text "Steam must be running on the current desktop to use this feature."; return; } + auto_mod_install fi } query_and_connect(){ + [[ -z $whitelist ]] && { popup 600; return; } query_api parse_json #TODO: create logger function if [[ ! $delete -eq 1 ]]; then echo "[DZGUI] Checking response time of servers" - create_array | zenity --width 500 --progress --pulsate --title="DZGUI" --auto-close 2>/dev/null + create_array | $steamsafe_zenity --width 500 --progress --pulsate --title="DZGUI" --auto-close 2>/dev/null else create_array fi @@ -1042,7 +1141,7 @@ filter_maps(){ [[ $ret -eq 98 ]] && return local maps=$(echo "$response" | jq -r '.[].map//empty|ascii_downcase' | sort -u) local map_ct=$(echo "$maps" | wc -l) - local map_sel=$(echo "$maps" | zenity --list --column="Check" --width=1200 --height=800 2>/dev/null --title="DZGUI" --text="Found $map_ct map types") + local map_sel=$(echo "$maps" | $steamsafe_zenity --list --column="Check" --width=1200 --height=800 2>/dev/null --title="DZGUI" --text="Found $map_ct map types") echo "[DZGUI] Selected '$map_sel'" if [[ -z $map_sel ]]; then ret=97 @@ -1131,16 +1230,16 @@ check_geo_file(){ chmod +x $km_helper echo "100" } - run > >(zenity --pulsate --progress --auto-close --width=500 2>/dev/null) + run > >($steamsafe_zenity --pulsate --progress --auto-close --width=500 2>/dev/null) fi } choose_filters(){ if [[ $is_steam_deck -eq 0 ]]; then sd_res="--width=1920 --height=1080" fi - sels=$(zenity --title="DZGUI" --text="Server search" --list --checklist --column "Check" --column "Option" --hide-header TRUE "All maps (untick to select from map list)" TRUE "Daytime" TRUE "Nighttime" False "Empty" False "Full" False "Low population" FALSE "Non-ASCII titles" FALSE "Keyword search" $sd_res 2>/dev/null) + sels=$($steamsafe_zenity --title="DZGUI" --text="Server search" --list --checklist --column "Check" --column "Option" --hide-header TRUE "All maps (untick to select from map list)" TRUE "Daytime" TRUE "Nighttime" False "Empty" False "Full" False "Low population" FALSE "Non-ASCII titles" FALSE "Keyword search" $sd_res 2>/dev/null) if [[ $sels =~ Keyword ]]; then - search=$(zenity --entry --text="Search (case insensitive)" --width=500 --title="DZGUI" 2>/dev/null | awk '{print tolower($0)}') + search=$($steamsafe_zenity --entry --text="Search (case insensitive)" --width=500 --title="DZGUI" 2>/dev/null | awk '{print tolower($0)}') [[ -z $search ]] && { ret=97; return; } fi [[ -z $sels ]] && return @@ -1186,13 +1285,13 @@ write_fifo(){ } munge_servers(){ if [[ ! "$sels" =~ "All maps" ]]; then - filter_maps > >(zenity --pulsate --progress --auto-close --width=500 2>/dev/null) + filter_maps > >($steamsafe_zenity --pulsate --progress --auto-close --width=500 2>/dev/null) disabled+=("All maps") fi [[ $ret -eq 97 ]] && return - prepare_filters > >(zenity --pulsate --progress --auto-close --width=500 2>/dev/null) + prepare_filters > >($steamsafe_zenity --pulsate --progress --auto-close --width=500 2>/dev/null) if [[ $(echo "$response" | jq 'length') -eq 0 ]]; then - zenity --error --text="No matching servers" 2>/dev/null + $steamsafe_zenity --error --text="No matching servers" 2>/dev/null return fi local addr=$(echo "$response" | jq -r '.[].addr' | awk -F: '{print $1}') @@ -1218,7 +1317,7 @@ munge_servers(){ write_fifo & pid=$! - local sel=$(zenity --text="$(pagination)" --title="DZGUI" --list --column=Map --column=Name --column=Gametime --column=Players --column=Max --column=Distance --column=IP --column=Qport $sd_res --print-column=7,8 --separator=%% 2>/dev/null < <(while true; do cat $fifo; done)) + local sel=$($steamsafe_zenity --text="$(pagination)" --title="DZGUI" --list --column=Map --column=Name --column=Gametime --column=Players --column=Max --column=Distance --column=IP --column=Qport $sd_res --print-column=7,8 --separator=%% 2>/dev/null < <(while true; do cat $fifo; done)) if [[ -z $sel ]]; then rm $fifo kill -9 $pid @@ -1249,7 +1348,7 @@ debug_servers(){ Key length: $key_len ======Short query====== Expected: 10 - Found: $debug_len + Found: $debug_len Response follows----> $debug_res ======END DEBUG======= @@ -1263,7 +1362,7 @@ server_browser(){ file=$(mktemp) local limit=20000 local url="https://api.steampowered.com/IGameServersService/GetServerList/v1/?filter=\appid\221100&limit=$limit&key=$steam_api" - check_geo_file + check_geo_file local_latlon choose_filters [[ -z $sels ]] && return @@ -1271,12 +1370,11 @@ server_browser(){ #TODO: some error handling here fetch(){ echo "# Getting server list" - curl -Ls "$url" > $file + response=$(curl -Ls "$url" | jq -r '.response.servers') } - fetch > >(zenity --pulsate --progress --auto-close --width=500 2>/dev/null) - response=$(< $file jq -r '.response.servers') - total_servers=$(echo "$response" | jq 'length') - players_online=$(echo "$response" | jq '.[].players' | awk '{s+=$1}END{print s}') + fetch > >($steamsafe_zenity --pulsate --progress --auto-close --width=500 2>/dev/null) + total_servers=$(echo "$response" | jq 'length' | numfmt --grouping) + players_online=$(echo "$response" | jq '.[].players' | awk '{s+=$1}END{print s}' | numfmt --grouping) debug_log="$HOME/.local/share/dzgui/DEBUG.log" debug_servers local sel=$(munge_servers) @@ -1301,13 +1399,12 @@ mods_disk_size(){ printf "%s mods | " $(ls -1 "$game_dir" | wc -l) printf "Location: %s/steamapps/workshop/content/221100" "$steam_path" } - main_menu(){ print_news set_mode - if [[ -n $fav ]]; then - items[7]=" Change favorite server" - fi +# if [[ -n $fav ]]; then +# items[8]=" Change favorite server" +# fi while true; do set_header ${FUNCNAME[0]} rc=$? @@ -1323,35 +1420,37 @@ main_menu(){ elif [[ $sel == "${items[3]}" ]]; then connect_to_fav elif [[ $sel == "${items[4]}" ]]; then - : - elif [[ $sel == "${items[5]}" ]]; then connect_by_ip + elif [[ $sel == "${items[5]}" ]]; then + history_table elif [[ $sel == "${items[6]}" ]]; then - add_by_id + : elif [[ $sel == "${items[7]}" ]]; then - add_by_fav + add_by_id elif [[ $sel == "${items[8]}" ]]; then + add_by_fav + elif [[ $sel == "${items[9]}" ]]; then delete=1 query_and_connect - elif [[ $sel == "${items[9]}" ]]; then - : elif [[ $sel == "${items[10]}" ]]; then - list_mods | sed 's/\t/\n/g' | zenity --list --column="Mod" --column="Symlink" \ + : + elif [[ $sel == "${items[11]}" ]]; then + list_mods | sed 's/\t/\n/g' | $steamsafe_zenity --list --column="Mod" --column="Symlink" \ --title="DZGUI" $sd_res --text="$(mods_disk_size)" \ --print-column="" 2>/dev/null - elif [[ $sel == "${items[11]}" ]]; then - changelog | zenity --text-info $sd_res --title="DZGUI" 2>/dev/null elif [[ $sel == "${items[12]}" ]]; then + changelog | $steamsafe_zenity --text-info $sd_res --title="DZGUI" 2>/dev/null + elif [[ $sel == "${items[13]}" ]]; then options_menu main_menu return - elif [[ $sel == "${items[13]}" ]]; then - : elif [[ $sel == "${items[14]}" ]]; then - help_file + : elif [[ $sel == "${items[15]}" ]]; then - report_bug + help_file elif [[ $sel == "${items[16]}" ]]; then + report_bug + elif [[ $sel == "${items[17]}" ]]; then forum else warn "This feature is not yet implemented." @@ -1395,7 +1494,6 @@ check_ping(){ } create_array(){ rows=() - list=$(cat $tmp) #TODO: improve error handling for null values lc=1 while read line; do @@ -1411,9 +1509,6 @@ create_array(){ time=$(echo "$line" | awk -F'\t' '{print $4}') stat=$(echo "$line" | awk -F'\t' '{print $5}') - #yad only - #[[ $stat == "online" ]] && stat="online" || : - #TODO: probe offline return codes id=$(echo "$line" | awk -F'\t' '{print $6}') tc=$(awk 'END{print NR}' $tmp) @@ -1425,12 +1520,11 @@ create_array(){ declare -g -a rows=("${rows[@]}" "$name" "$ip" "$players" "$time" "$stat" "$id" "$ping") fi let lc++ - done <<< "$list" + done < "$tmp" for i in "${rows[@]}"; do echo -e "$i"; done > $tmp } set_fav(){ - #TODO: test API key here and return errors echo "[DZGUI] Querying favorite server" query_api fav_label=$(curl -s "$api" -H "Authorization: Bearer "$api_key"" -G -d "filter[game]=$game" -d "filter[ids][whitelist]=$fav" \ @@ -1453,7 +1547,7 @@ merge_config(){ [[ -z $staging_dir ]] && staging_dir="/tmp" write_config > $config_file printf "[DZGUI] Wrote new config file to %sdztuirc\n" $config_path - zenity --info --width 500 --title="DZGUI" --text="Wrote new config format to \n${config_path}dztuirc\nIf errors occur, you can restore the file:\n${config_path}dztuirc.old" 2>/dev/null + $steamsafe_zenity --info --width 500 --title="DZGUI" --text="Wrote new config format to \n${config_path}dztuirc\nIf errors occur, you can restore the file:\n${config_path}dztuirc.old" 2>/dev/null } download_new_version(){ @@ -1471,10 +1565,10 @@ download_new_version(){ chmod +x $source_script touch ${config_path}.unmerged echo "100" - zenity --question --width 500 --title="DZGUI" --text "DZGUI $upstream successfully downloaded.\nTo view the changelog, select Changelog.\nTo use the new version, select Exit and restart." --ok-label="Changelog" --cancel-label="Exit" 2>/dev/null + $steamsafe_zenity --question --width 500 --title="DZGUI" --text "DZGUI $upstream successfully downloaded.\nTo view the changelog, select Changelog.\nTo use the new version, select Exit and restart." --ok-label="Changelog" --cancel-label="Exit" 2>/dev/null code=$? if [[ $code -eq 0 ]]; then - changelog | zenity --text-info $sd_res --title="DZGUI" 2>/dev/null + changelog | $steamsafe_zenity --text-info $sd_res --title="DZGUI" 2>/dev/null exit elif [[ $code -eq 1 ]]; then exit @@ -1482,7 +1576,7 @@ download_new_version(){ else echo "100" mv $source_script.old $source_script - zenity --info --title="DZGUI" --text "[ERROR] 99: Failed to download new version." 2>/dev/null + $steamsafe_zenity --info --title="DZGUI" --text "[ERROR] 99: Failed to download new version." 2>/dev/null return fi @@ -1496,16 +1590,16 @@ check_branch(){ upstream=$(curl -Ls "$version_url" | awk -F= '/^version=/ {print $2}') } enforce_dl(){ - download_new_version > >(zenity --progress --pulsate --auto-close --no-cancel --width=500) + download_new_version > >($steamsafe_zenity --progress --pulsate --auto-close --no-cancel --width=500) } prompt_dl(){ - zenity --question --title="DZGUI" --text "Version conflict.\n\nYour branch:\t\t\t$branch\nYour version\t\t\t$version\nUpstream version:\t\t$upstream\n\nVersion updates introduce important bug fixes and are encouraged.\n\nAttempt to download latest version?" --width=500 --ok-label="Yes" --cancel-label="No" 2>/dev/null + $steamsafe_zenity --question --title="DZGUI" --text "Version conflict.\n\nYour branch:\t\t\t$branch\nYour version\t\t\t$version\nUpstream version:\t\t$upstream\n\nVersion updates introduce important bug fixes and are encouraged.\n\nAttempt to download latest version?" --width=500 --ok-label="Yes" --cancel-label="No" 2>/dev/null rc=$? if [[ $rc -eq 1 ]]; then return else echo "100" - download_new_version > >(zenity --progress --pulsate --auto-close --no-cancel --width=500) + download_new_version > >($steamsafe_zenity --progress --pulsate --auto-close --no-cancel --width=500) fi } check_version(){ @@ -1538,20 +1632,21 @@ check_architecture(){ add_by_id(){ #FIXME: prevent redundant creation of existent IDs (for neatness) while true; do - id=$(zenity --entry --text="Enter server ID" --title="DZGUI" 2>/dev/null) + id=$($steamsafe_zenity --entry --text="Enter server ID" --title="DZGUI" 2>/dev/null) rc=$? if [[ $rc -eq 1 ]]; then return else if [[ ! $id =~ ^[0-9]+$ ]]; then - zenity --warning --title="DZGUI" --text="Invalid ID" 2>/dev/null + $steamsafe_zenity --warning --title="DZGUI" --text="Invalid ID" 2>/dev/null else - new_whitelist="whitelist=\"$whitelist,$id\"" + [[ -z $whitelist ]] && new_whitelist="whitelist=\"$id\"" + [[ -n $whitelist ]] && new_whitelist="whitelist=\"$whitelist,$id\"" mv $config_file ${config_path}dztuirc.old nr=$(awk '/whitelist=/ {print NR}' ${config_path}dztuirc.old) awk -v "var=$new_whitelist" -v "nr=$nr" 'NR==nr {$0=var}{print}' ${config_path}dztuirc.old > ${config_path}dztuirc echo "[DZGUI] Added $id to key 'whitelist'" - zenity --info --title="DZGUI" --text="Added "$id" to:\n${config_path}dztuirc\nIf errors occur, you can restore the file:\n${config_path}dztuirc.old" --width=500 2>/dev/null + $steamsafe_zenity --info --title="DZGUI" --text="Added "$id" to:\n${config_path}dztuirc\nIf errors occur, you can restore the file:\n${config_path}dztuirc.old" --width=500 2>/dev/null source $config_file return fi @@ -1575,7 +1670,7 @@ toggle_debug(){ setup(){ if [[ -n $fav ]]; then set_fav - items[7]=" Change favorite server" + items[8]=" Change favorite server" fi } check_map_count(){ @@ -1583,9 +1678,9 @@ check_map_count(){ echo "[DZGUI] Checking system map count" if [[ $(sysctl -q vm.max_map_count | awk -F"= " '{print $2}') -lt $count ]]; then echo "100" - map_warning=$(zenity --question --width 500 --title="DZGUI" --text "System map count must be $count or higher to run DayZ with Wine. Increase map count and make this change permanent? (will prompt for sudo password)" 2>/dev/null) + map_warning=$($steamsafe_zenity --question --width 500 --title="DZGUI" --text "System map count must be $count or higher to run DayZ with Wine. Increase map count and make this change permanent? (will prompt for sudo password)" 2>/dev/null) if [[ $? -eq 0 ]]; then - pass=$(zenity --password) + pass=$($steamsafe_zenity --password) sudo -S <<< "$pass" sh -c "echo 'vm.max_map_count=1048576' > /etc/sysctl.d/dayz.conf" echo "" @@ -1594,23 +1689,23 @@ check_map_count(){ } add_by_fav(){ while true; do - fav_id=$(zenity --entry --text="Enter server ID" --title="DZGUI" 2>/dev/null) + fav_id=$($steamsafe_zenity --entry --text="Enter server ID" --title="DZGUI" 2>/dev/null) rc=$? if [[ $rc -eq 1 ]]; then return else if [[ ! $fav_id =~ ^[0-9]+$ ]]; then - zenity --warning --title="DZGUI" --text="Invalid ID" + $steamsafe_zenity --warning --title="DZGUI" --text="Invalid ID" else new_fav="fav=\"$fav_id\"" mv $config_file ${config_path}dztuirc.old nr=$(awk '/fav=/ {print NR}' ${config_path}dztuirc.old) awk -v "var=$new_fav" -v "nr=$nr" 'NR==nr {$0=var}{print}' ${config_path}dztuirc.old > ${config_path}dztuirc echo "[DZGUI] Added $fav_id to key 'fav'" - zenity --info --title="DZGUI" --text="Added "$fav_id" to:\n${config_path}dztuirc\nIf errors occurred, you can restore the file:\n${config_path}dztuirc.old" 2>/dev/null + $steamsafe_zenity --info --title="DZGUI" --text="Added "$fav_id" to:\n${config_path}dztuirc\nIf errors occurred, you can restore the file:\n${config_path}dztuirc.old" 2>/dev/null source $config_file set_fav - items[7]=" Change favorite server" + items[8]=" Change favorite server" return fi fi @@ -1625,7 +1720,7 @@ lock(){ res=$? if [[ $res -eq 0 ]]; then echo "[DZGUI] Already running ($pid)" - zenity --info --text="DZGUI already running (pid $pid)" --width=500 --title="DZGUI" 2>/dev/null + $steamsafe_zenity --info --text="DZGUI already running (pid $pid)" --width=500 --title="DZGUI" 2>/dev/null exit elif [[ $pid == $$ ]]; then : @@ -1633,48 +1728,9 @@ lock(){ echo $$ > $config_path/.lockfile fi } -fetch_scmd_helper(){ +fetch_helpers(){ mkdir -p "$helpers_path" - curl -Ls "$scmd_url" > "$helpers_path/scmd.sh" - chmod +x "$helpers_path/scmd.sh" - [[ ! -f "$helpers_path/d.html" ]] && curl -Ls "$notify_url" > "$helpers_path/d.html" - [[ ! -f "$helpers_path/d.webp" ]] && curl -Ls "$notify_img_url" > "$helpers_path/d.webp" -} -deprecation_warning(){ - warn(){ - cat <<- HERE - IMPORTANT ANNOUNCEMENT - (Steam API key not found) - - A Steam API key is now mandatory to run the app. - The BM API returns incorrect mod data on some servers - and cannot be relied upon for up to date information. - - Going forward, we will only use the BM API as a convenience - function to manage server names and your favorite servers list, - and migrate to indexing servers on an IP basis. - - This is a backend change. You can continue adding servers by ID, - but we will retrieve information from Valve instead, as we do for the - server browser and connect-by-ip methods. - - Click [OK] to open the help page describing how to set up your key. - After you input a valid key, the app will resume. - HERE - } - if [[ -z $steam_api ]]; then - echo "100" - local big_prompt - [[ $is_steam_deck -eq 1 ]] && big_prompt="--width=800" - zenity --info --text="$(warn)" $big_prompt - key_setup_url="https://aclist.github.io/dzgui/dzgui.html#_api_key_server_ids" - browser "$key_setup_url" 2>/dev/null & - while true; do - if [[ $(check_steam_api) ]]; then - break - fi - done - fi + [[ ! -f "$helpers_path/vdf2json.py" ]] && curl -Ls "$vdf2json_url" > "$helpers_path/vdf2json.py" } initial_setup(){ echo "# Initial setup" @@ -1683,21 +1739,19 @@ initial_setup(){ check_architecture check_version check_map_count + fetch_helpers config - fetch_scmd_helper run_varcheck + stale_symlinks init_items setup - deprecation_warning echo "100" } main(){ lock - initial_setup > >(zenity --pulsate --progress --auto-close --title="DZGUI" --width=500 2>/dev/null) + initial_setup > >($steamsafe_zenity --pulsate --progress --auto-close --title="DZGUI" --no-cancel --width=500 2>/dev/null) main_menu - #cruddy handling for steam forking + #TODO: tech debt: cruddy handling for steam forking [[ $? -eq 1 ]] && pkill -f dzgui.sh } - main -#trap cleanup EXIT diff --git a/helpers/d.html b/helpers/d.html deleted file mode 100644 index e5bbbda..0000000 --- a/helpers/d.html +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/helpers/d.webp b/helpers/d.webp deleted file mode 100644 index 37129b7..0000000 Binary files a/helpers/d.webp and /dev/null differ diff --git a/helpers/scmd.sh b/helpers/scmd.sh deleted file mode 100644 index 7a30202..0000000 --- a/helpers/scmd.sh +++ /dev/null @@ -1,361 +0,0 @@ -#!/bin/bash - -conf=$HOME/.config/dztui/dztuirc -source $conf -[[ -z $staging_dir ]] && staging_dir="/tmp" -aid=221100 -steamcmd_user=steam -workshop_dir="$steam_path/steamapps/workshop/content/$aid" -helpers_path="$HOME/.local/share/dzgui/helpers" - -log(){ - printf "$(tput setaf 3)[INFO]$(tput sgr0) %s\n" "$1" -} -pass(){ - printf "$(tput setaf 2)[PASS]$(tput sgr0) %s\n" "$1" -} -fail(){ - printf "$(tput setaf 1)[FAIL]$(tput sgr0) %s\n" "$1" -} -steamcmd_modlist(){ - printf "force_install_dir %s\n" "$staging_dir" - printf "login %s\n" "$steam_username" - for i in "${ids[@]}"; do - printf "workshop_download_item %s %s validate\n" $aid $i - done - printf "quit" -} -move_files(){ - printf "\n" - log "Moving mods from $staging_dir to $workshop_dir" - if [[ $staging_dir == "/tmp" ]]; then - sudo chown -R $USER:$gid "$staging_dir"/steamapps - fi - cp -R "$staging_dir"/steamapps/workshop/content/$aid/* "$workshop_dir" - if [[ $dist == "steamos" ]]; then - rm -rf "$staging_dir"/steamapps - else - sudo rm -rf "$staging_dir"/steamapps - fi -} -#tutorial(){ -#cat <<- HERE -# -#INSTRUCTIONS -# -#Keep this window adjacent to your terminal as a guide. -# -#1. In the steamcmd prompt, enter "login [id] [pass] [2FA]" (if applicable) -#and type Enter. E.g., if the user is Billy, pass is Banana, and 2FA token is 777: -# -#login Billy Banana 777 [Enter] -# -#2. Then enter: runscript /tmp/mods.txt and type Enter -# -#3. The auto-mod process will begin to headlessly download the mods. -# -#Valve uses a long-lived token to cache credentials, -#so you may be able to simply type [id] and "quit" -#on subsequent invocations, but it expires after some time. -#HERE -#} -#ctdw(){ -# for((i=3;i>0;i--)); do -# printf "[INFO] Downloading mods in %i\r" "$i" -# sleep 1s -# done -#} -test_dir(){ - if [[ $dist == "steamos" ]]; then - return 0 - fi - sudo -u steam test -w "$staging_dir" - rc=$? - if [[ $rc -eq 1 ]]; then - fail "User '$steamcmd_user' does not have write access to $staging_dir. Reverting to /tmp" - staging_dir="/tmp" - return 0 - fi -} -auto_mod_download(){ - while true; do - read -p 'Enter Steam login name: ' steam_username - [[ -z $steam_username ]] && { fail "Username can't be empty"; continue; } - [[ -n $steam_username ]] && break - done - test_dir - if [[ -d "$staging_dir/steamapps" ]]; then - log "Sanitizing $staging_dir" - if [[ $staging_dir == "/tmp" ]]; then - sudo chown -R $USER:$gid "$staging_dir"/steamapps - fi - if [[ $dist == "steamos" ]]; then - rm -rf "$staging_dir"/steamapps - else - sudo rm -rf "$staging_dir"/steamapps - fi - fi - tput civis - [[ ${#ids[@]} -gt 1 ]] && s=s - tput cnorm - log "Staging dir is $staging_dir" - steamcmd_modlist > "/tmp/mods.txt" - log "Preparing to download ${#ids[@]} mod$s. This may take some time. Abort with Ctrl+c." - if [[ $dist == "steamos" ]]; then - $steamcmd_path +runscript /tmp/mods.txt - else - sudo -iu $steamcmd_user bash -c "$steamcmd_path +runscript /tmp/mods.txt" - fi - rc=$? - rm "/tmp/mods.txt" - if [[ $rc -eq 0 ]]; then - move_files - else - return 1 - fi -} -find_steam_cmd(){ - for i in "/home/steam" "/usr/bin" "/usr/local/bin" "/usr/games"; do - if [[ -f "$i/steamcmd" ]]; then - steamcmd_path="$i/steamcmd" - pass "Found steamcmd: $steamcmd_path" - return 0 - fi - done - fail "Failed to find steamcmd" - return 1 -} -create_user(){ - log "Creating steamcmd user" - sudo useradd -m steam - rc=$? - if [[ $rc -eq 0 ]]; then - log "Set a password for the headless steamcmd user" - sudo passwd steam - else - return 1 - fi -} -check_user(){ - id $steamcmd_user &>/dev/null - rc=$? - if [[ $rc -eq 1 ]]; then - fail "steamcmd user missing" - create_user - rc=$? - [[ $rc -eq 1 ]] && return 1 - else - pass "Found user: $steamcmd_user" - fi - while true; do - local stat=$(sudo passwd $steamcmd_user --status | awk '{print $2}') - if - [[ $stat == "L" ]] || [[ $stat == "NP" ]]; then - fail "steamcmd user has a locked or empty password" - sudo passwd $steamcmd_user - else - return 0 - fi - done -} -generic_install(){ - fail "Unrecognized distro: $dist." - log "Please report this upstream for whitelisting and attach your SCMD.log" - log "Location: $helpers_path/SCMD.log" - return 1 -} -fedora_install(){ - #TODO - : -} -#ubuntu related -# dep: debconf -# Debian configuration management system -# -# dep: debconf (>= 0.5) -# Debian configuration management system -# or debconf-2.0 -# virtual package provided by cdebconf, cdebconf-udeb, debconf -# -# dep: libc6 (>= 2.12) -# GNU C Library: Shared libraries -# also a virtual package provided by libc6-udeb -# -# dep: libstdc++6 -# GNU Standard C++ Library v3 -# -# sug: steam -# Valve's Steam digital software delivery system -# -deb_install(){ - check_user - rc=$? - [[ $rc -eq 1 ]] && return 1 - find_steam_cmd - rc=$? - if [[ $rc -eq 1 ]]; then - log "Installing distribution steamcmd packages" - sudo add-apt-repository -y multiverse - sudo apt install -y software-properties-common - sudo dpkg --add-architecture i386 - sudo apt update - sudo apt install -y steamcmd - find_steam_cmd - fi - dpkg -s lib32gcc-s1 1>/dev/null - rc=$? - if [[ $rc -eq 1 ]]; then - fail "Missing deps: lib32-gcc-libs" - sudo apt install -y lib32gcc-s1 - else - pass "Found deps: lib32-gcc-libs" - fi - -} -deck_install(){ - pacman -Qi lib32-gcc-libs 2>/dev/null 1>&2 - rc=$? - [[ ! $rc -eq 0 ]] && return 1 - if [[ ! -f $HOME/.local/share/dzgui/helpers/steamcmd/steamcmd.sh ]]; then - local tarball="steamcmd_linux.tar.gz" - mkdir -p $HOME/.local/share/dzgui/helpers/steamcmd - curl -Ls "https://steamcdn-a.akamaihd.net/client/installer/$tarball" > $HOME/.local/share/dzgui/helpers/steamcmd/$tarball - $(cd $HOME/.local/share/dzgui/helpers/steamcmd; tar xvf $tarball) - fi - steamcmd_path="$HOME/.local/share/dzgui/helpers/steamcmd/steamcmd.sh" -} -arch_install(){ - check_user - rc=$? - [[ $rc -eq 1 ]] && return 1 - find_steam_cmd - rc=$? - if [[ $rc -eq 1 ]]; then - log "Checking prerequisites" - for i in makepkg git; do - if [[ ! $(command -v $i) ]]; then - fail "Missing package: $i" - info "Script will fetch build tools now. Partial upgrades on Arch Linux are discouraged, so triggering a full update.\n - Type any key to proceed." - read -n1 key - case $key in - *) sudo pacman -Syu base-devel git lib32-gcc-libs --noconfirm - esac - break - else - pass "Found deps: $i" - fi - done - log "Installing steamcmd from distribution" - [[ -d /tmp/steamcmd ]] && rm -rf /tmp/steamcmd - git clone https://aur.archlinux.org/steamcmd.git /tmp/steamcmd - cd /tmp/steamcmd && makepkg -si --noconfirm && cd $OLDPWD - #TODO: check symlink - log "Symlinking steamcmd" - sudo ln -s /usr/bin/steamcmd /home/steam/steamcmd - rm -rf /tmp/steamcmd - find_steam_cmd - fi - sudo pacman -Qi lib32-gcc-libs 2>/dev/null 1>&2 - rc=$? - if [[ $rc -eq 1 ]]; then - fail "Missing deps: lib32-gcc-libs" - info "Script will fetch build tools now. Partial upgrades on Arch Linux are discouraged, so triggering a full update.\n - Type any key to proceed." - read -n1 key - case $key in - *) sudo pacman -Syu lib32-gcc-libs --noconfirm - esac - else - pass "Found deps: lib32-gcc-libs" - fi -} -check_dist(){ - os=/etc/os-release - dist=$(awk -F= '/^ID=/ {print $2}' $os) - pass "Found OS: $dist" - case $dist in - ubuntu|linuxmint|pop|debian) deb_install ;; - arch|antergos|manjaro) arch_install ;; - steamos) deck_install ;; - fedora) generic_install ;; - *) generic_install ;; - esac -} -return_to_dzg(){ - if [[ $ret -eq 1 ]]; then - fail "Errors occurred. Type any key to return to DZGUI and kick off manual install." - read -n1 key - case $key in - *) cleanup ;; - esac - elif [[ $dist == "steamos" ]]; then - pass "All OK. Returning to DZGUI." - for((i=3;i>0;i--)); do - printf "Returning in %i\r" "$i" - sleep 1s - done - cleanup - else - $(cd $HOME/.local/share/dzgui/helpers; zenity --text-info --title=DZGUI --html --width=390 --height=452 --filename="d.html" 2>/dev/null) - cleanup - fi -} -cleanup(){ - tput cnorm - sed -i "s/Logging in user '.*'/Logging in user XXX/" $helpers_path/SCMD.log - exit -} -abort(){ - tput cnorm - printf "\n" - log "Keyboard interrupt" - exit -} -check_disks(){ - if [[ $dist == "steamos" ]]; then - staging_dir="$HOME/.local/share/dzgui/mods" - mkdir -p $staging_dir - fi - disksize=$(df $staging_dir --output=avail | tail -n1) - disk_bytewise=$((disksize * 1024)) - hr=$(echo $(numfmt --to=iec --format "%.2f" $totalmodsize $disk_bytewise) | sed 's/ /\//') - [[ ${#ids[@]} -gt 1 ]] && s=s - if [[ $disk_bytewise -lt $totalmodsize ]]; then - fail "Required/actual: $hr. Installation will quit after /tmp reaches capacity." - else - pass "Required/actual: $hr" - fi -} -[[ -f $PWD/SCMD.log ]] && rm SCMD.log -if [[ -z $1 ]] || [[ -z $2 ]]; then - fail "Missing mod arguments" - ret=1 - return_to_dzg -fi -totalmodsize="$1" -shift -for i in $@; do - ids+=("$i") -done -main(){ - echo "" - echo "────────DZGUI automod helper────────" - log "Preparing environment" - check_disks - check_dist - if [[ $? -eq 1 ]]; then - ret=1 - return_to_dzg - else - pass "All OK. Starting mod auto install process" - auto_mod_download - rc=$? - [[ $rc -eq 1 ]] && ret=1 - return_to_dzg - fi -} -trap cleanup EXIT -trap abort SIGINT -main | tee -a $helpers_path/SCMD.log -cleanup diff --git a/helpers/vdf2json.py b/helpers/vdf2json.py new file mode 100644 index 0000000..279b513 --- /dev/null +++ b/helpers/vdf2json.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +from shlex import shlex + +def vdf2json(stream): + + """ + Read a Steam vdf file and return a string in json format + """ + + def _istr(ident, string): + return (ident * ' ') + string + + jbuf = '{\n' + lex = shlex(stream) + indent = 1 + + while True: + tok = lex.get_token() + if not tok: + return jbuf + '}\n' + if tok == '}': + indent -= 1 + jbuf += _istr(indent, '}') + ntok = lex.get_token() + lex.push_token(ntok) + if ntok and ntok != '}': + jbuf += ',' + jbuf += '\n' + else: + ntok = lex.get_token() + if ntok == '{': + jbuf += _istr(indent, tok + ': {\n') + indent += 1 + else: + jbuf += _istr(indent, tok + ': ' + ntok) + ntok = lex.get_token() + lex.push_token(ntok) + if ntok != '}': + jbuf += ',' + jbuf += '\n' +def main(): + """ + Read Steam vdf and write json compatible conversion + """ + import sys + import argparse + + parser = argparse.ArgumentParser(prog='vdf2json', description=main.__doc__) + parser.add_argument('-i', '--input', + default=sys.stdin, + type=argparse.FileType('r'), + help='input vdf file (stdin if not specified)') + parser.add_argument('-o', '--output', + default=sys.stdout, + type=argparse.FileType('w'), + help='output json file (stdout if not specified)') + + args = parser.parse_args() + args.output.write(vdf2json(args.input)) + +if __name__ == '__main__': + main() diff --git a/news b/news index c62f490..efb3b43 100644 --- a/news +++ b/news @@ -1 +1 @@ -NEWS: Streamlined manual mod subscription. Automatic mod installation enters testing. +NEWS: Simple auto mod installation under Advanced Options.