diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 3e3e7aa..eea7014 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -637,13 +637,12 @@ jobs: echo "" >> "$README_PATH" get_desc() { - grep -- "^$1=" "$DESC_FILE" 2>/dev/null | cut -d '=' -f2- + grep -F -m1 -- "$1=" "$DESC_FILE" 2>/dev/null | cut -d '=' -f2- } ORDER_FILE=$(mktemp) - echo "Step 3: Extracting order from skins.json..." - jq -r '.order[]' "$SKINS_JSON_FILE" > "$ORDER_FILE" + jq -r '.order[]?' "$SKINS_JSON_FILE" > "$ORDER_FILE" echo "Step 4: Processing ordered skins..." while IFS= read -r skin; do @@ -654,82 +653,83 @@ jobs: ini_file=$(find "$dir" -maxdepth 1 -iname "skin.ini" | head -n1) skin_header="$skin" if [ -f "$ini_file" ]; then - name_line=$(grep -i '^[[:space:]]*Name:' "$ini_file" | head -n1) - if [ -n "$name_line" ]; then - new_name=$(echo "${name_line#*:}" | sed 's/^[[:space:]]*//') - new_name=$(sanitize_filename "$new_name") - [ -n "$new_name" ] && skin_header="$new_name" - fi + line=$(grep -i '^[[:space:]]*Name:' "$ini_file" | head -n1 2>/dev/null || true) + [ -n "$line" ] && { + val="${line#*:}" + skin_header=$(sanitize_filename "$val") + } fi - skin_header=$(printf '%s' "$skin_header" | tr -d '\r\n') base_path=$(printf "%s/%s" "$skin" "$skin_header" | sed 's/ /%20/g') - escaped_img="${base_path}.gif" - escaped_panel="${base_path}.png" - escaped_osk="${base_path}.osk" - escaped_mod="${base_path}-mod-icons.png" - - echo " Writing skin: $skin_header" - echo "## [$skin_header]($REGISTRY_URL/$USER_REPOSITORY/media/tag/$new_tag/export/$escaped_osk)" >> "$README_PATH" + echo "## [$skin_header]($REGISTRY_URL/$USER_REPOSITORY/media/tag/$new_tag/export/${base_path}.osk)" >> "$README_PATH" echo "" >> "$README_PATH" desc=$(get_desc "$skin") [ -n "$desc" ] && { echo "$desc" >> "$README_PATH"; echo "" >> "$README_PATH"; } - author_line=$(grep -i '^[[:space:]]*Author:' "$ini_file" | head -n1 2>/dev/null) - if [ -n "$author_line" ]; then - author=$(echo "${author_line#*:}" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') - [ -n "$author" ] && { echo "**Author:** $author" >> "$README_PATH"; echo "" >> "$README_PATH"; } + if [ -f "$ini_file" ]; then + author_line=$(grep -i '^[[:space:]]*Author:' "$ini_file" | head -n1 2>/dev/null || true) + if [ -n "$author_line" ]; then + author="${author_line#*:}" + author="$(echo "$author" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')" + [ -n "$author" ] && { echo "**Author:** $author" >> "$README_PATH"; echo "" >> "$README_PATH"; } + fi fi - echo "![$skin_header Gameplay](media/gameplay/$escaped_img)" >> "$README_PATH" + echo "![$skin_header Gameplay](media/gameplay/${base_path}.gif)" >> "$README_PATH" echo "" >> "$README_PATH" - echo "![$skin_header Ranking Panel](media/panel/$escaped_panel)" >> "$README_PATH" + echo "![$skin_header Ranking Panel](media/panel/${base_path}.png)" >> "$README_PATH" echo "" >> "$README_PATH" - echo "![$skin_header Mods](media/icons/$escaped_mod)" >> "$README_PATH" + echo "![$skin_header Mods](media/icons/${base_path}-mod-icons.png)" >> "$README_PATH" echo "" >> "$README_PATH" done < "$ORDER_FILE" + declare -A ordered + while IFS= read -r skin; do + ordered["$skin"]=1 + done < "$ORDER_FILE" + echo "Step 5: Processing extra skins..." - find "$DANSER_SKINS_DIR" -mindepth 1 -maxdepth 1 -type d | while IFS= read -r dir; do - skin=$(basename "$dir") - grep -F -x -q -- "$skin" "$ORDER_FILE" && continue + if [ ! -s "$ORDER_FILE" ]; then + echo "→ No \`order\` defined in skins.json; skipping extra-skins loop." + else + for dir in "$DANSER_SKINS_DIR"/*; do + [ -d "$dir" ] || continue + skin=$(basename "$dir") + [[ -n "${ordered[$skin]}" ]] && continue - ini_file=$(find "$dir" -maxdepth 1 -iname "skin.ini" | head -n1) - skin_header="$skin" - if [ -f "$ini_file" ]; then - name_line=$(grep -i '^[[:space:]]*Name:' "$ini_file" | head -n1) - if [ -n "$name_line" ]; then - new_name=$(echo "${name_line#*:}" | sed 's/^[[:space:]]*//') - new_name=$(sanitize_filename "$new_name") - [ -n "$new_name" ] && skin_header="$new_name" + echo " Writing extra skin: $skin" + ini_file=$(find "$dir" -maxdepth 1 -iname "skin.ini" | head -n1) + skin_header="$skin" + if [ -f "$ini_file" ]; then + line=$(grep -i '^[[:space:]]*Name:' "$ini_file" | head -n1 2>/dev/null || true) + [ -n "$line" ] && { + val="${line#*:}" + skin_header=$(sanitize_filename "$val") + } fi - fi - skin_header=$(printf '%s' "$skin_header" | tr -d '\r\n') - base_path=$(printf "%s/%s" "$skin" "$skin_header" | sed 's/ /%20/g') - escaped_img="${base_path}.gif" - escaped_panel="${base_path}.png" - escaped_osk="${base_path}.osk" - escaped_mod="${base_path}-mod-icons.png" + base_path=$(printf "%s/%s" "$skin" "$skin_header" | sed 's/ /%20/g') + echo "## [$skin_header]($REGISTRY_URL/$USER_REPOSITORY/media/tag/$new_tag/export/${base_path}.osk)" >> "$README_PATH" + echo "" >> "$README_PATH" - echo " Writing extra skin: $skin_header" - echo "## [$skin_header]($REGISTRY_URL/$USER_REPOSITORY/media/tag/$new_tag/export/$escaped_osk)" >> "$README_PATH" - echo "" >> "$README_PATH" + if [ -f "$ini_file" ]; then + author_line=$(grep -i '^[[:space:]]*Author:' "$ini_file" | head -n1 2>/dev/null || true) + if [ -n "$author_line" ]; then + author="${author_line#*:}" + author="$(echo "$author" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')" + [ -n "$author" ] && { echo "**Author:** $author" >> "$README_PATH"; echo "" >> "$README_PATH"; } + fi + fi - author_line=$(grep -i '^[[:space:]]*Author:' "$ini_file" | head -n1 2>/dev/null) - if [ -n "$author_line" ]; then - author=$(echo "${author_line#*:}" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') - [ -n "$author" ] && { echo "**Author:** $author" >> "$README_PATH"; echo "" >> "$README_PATH"; } - fi - - echo "![$skin_header Gameplay](media/gameplay/$escaped_img)" >> "$README_PATH" - echo "" >> "$README_PATH" - echo "![$skin_header Ranking Panel](media/panel/$escaped_panel)" >> "$README_PATH" - echo "" >> "$README_PATH" - echo "![$skin_header Mods](media/icons/$escaped_mod)" >> "$README_PATH" - echo "" >> "$README_PATH" - done + echo "![$skin_header Gameplay](media/gameplay/${base_path}.gif)" >> "$README_PATH" + echo "" >> "$README_PATH" + echo "![$skin_header Ranking Panel](media/panel/${base_path}.png)" >> "$README_PATH" + echo "" >> "$README_PATH" + echo "![$skin_header Mods](media/icons/${base_path}-mod-icons.png)" >> "$README_PATH" + echo "" >> "$README_PATH" + done + fi echo "Step 7: Writing Build History section..." echo "# Build History" >> "$README_PATH" @@ -757,50 +757,62 @@ jobs: set -euo pipefail echo "[Migration of flat assets started]" - # helper to sanitize header sanitize() { - echo "$1" \ - | tr -d '\r\n' \ - | sed -e 's#[\\/:\*\?"<>|]#-#g' -e 's#%#_#g' \ - | tr -s ' ' \ - | sed 's/^ *//;s/ *$//' + echo "$1" | tr -d $'\r\n\t' | \ + sed -e 's#[\\/:\*\?"<>|]#-#g' -e 's#%#_#g' | \ + tr -s ' ' | \ + sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' } readarray -t skins <<< "$ALL_SKINS_DIR" - declare -A hdr2fld for skin in "${skins[@]}"; do - header=$(sanitize "$skin") - ini=$(find "$DANSER_SKINS_DIR/$skin" -maxdepth 1 -type f -iname "skin.ini" | head -n1 || true) - if [ -n "$ini" ]; then - raw=$(grep -i '^[[:space:]]*Name:' "$ini" | head -n1 || true) + [[ -z "${skin// }" ]] && continue + dir_key=$(sanitize "$skin") + hdr2fld["$dir_key"]="$skin" + ini=$(find "$DANSER_SKINS_DIR/$skin" -maxdepth 1 -iname skin.ini -print -quit || true) + if [[ -f "$ini" ]]; then + raw=$(grep -i '^\s*Name:' "$ini" | head -n1 || true) raw="${raw#*:}" - raw="${raw#"${raw%%[![:space:]]*}"}" - header=$(sanitize "$raw") + ini_key=$(sanitize "$raw") + [[ -n "$ini_key" ]] && hdr2fld["$ini_key"]="$skin" fi - hdr2fld["$header"]="$skin" + done + + echo "DEBUG: header→folder map" + for key in "${!hdr2fld[@]}"; do + echo " '$key' → '${hdr2fld[$key]}'" done migrate() { - root=$1; ext=$2 - echo " → Migrating *.$ext files in $root" - shopt -s nullglob - for f in "$root"/*."$ext"; do - base="$(basename "$f" ."$ext")" - if [[ "$root" == *icons ]]; then - base="${base%-mod-icons}" - fi - target="${hdr2fld[$base]:-}" - if [ -n "$target" ]; then + local root=$1 ext=$2 + echo " → Migrating *.$ext in $root" + set +e + find "$root" -maxdepth 2 -type f -name "*.$ext" | while read -r f; do + filename=$(basename "$f") + base="${filename%.*}" + [[ "$root" == *icons ]] && base="${base%-mod-icons}" + key=$(sanitize "$base") + target="${hdr2fld[$key]:-}" + if [[ -n "$target" ]]; then dst="$root/$target" mkdir -p "$dst" - echo " • Moving $f → $dst/" - mv "$f" "$dst/" + srcdir=$(dirname "$f") + if [[ "$srcdir" == "$dst" ]]; then + echo " → $filename already in $target/, skipping" + else + echo " • Moving $filename → $target/" + mv "$f" "$dst/$filename" + fi else - echo " ✖ No matching skin for '$base'; leaving $f" + echo " ✖ No mapping for '$base' → leaving $f" fi done - shopt -u nullglob + set -euo pipefail + + find "$root" -mindepth 1 -maxdepth 1 -type d | while read -r d; do + [ -z "$(ls -A "$d")" ] && { echo " • Removing empty dir $d"; rmdir "$d"; } + done } migrate "$REPO_SCREENSHOT_DIR" gif @@ -820,24 +832,35 @@ jobs: [ -d src/docs ] && rm -rf src/docs [ -f how-to-use.md ] && rm -f how-to-use.md + # Read the current list of skins + readarray -t skins <<< "$ALL_SKINS_DIR" + + # Helper to sanitize header (for pruning inside) sanitize() { echo "$1" \ | tr -d '\r\n' \ | sed -e 's#[\\/:\*\?"<>|]#-#g' -e 's#%#_#g' \ | tr -s ' ' \ - | sed 's/^ *//;s/ *$//' + | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' } - readarray -t skins <<< "$ALL_SKINS_DIR" + for root in "$REPO_SCREENSHOT_DIR" "$REPO_RANKING_PANEL_DIR" "$REPO_MOD_ICONS_DIR" "$OSK_PATH"; do + for dir in "$root"/*; do + [ -d "$dir" ] || continue + name="$(basename "$dir")" + if ! printf '%s\n' "${skins[@]}" | grep -Fxq -- "$name"; then + echo " → Skin '$name' deleted—removing directory $dir" + rm -rf "$dir" + fi + done + done for skin in "${skins[@]}"; do header=$(sanitize "$skin") - - ini=$(find "$DANSER_SKINS_DIR/$skin" -maxdepth 1 -type f -iname "skin.ini" | head -n1 || true) - if [ -n "$ini" ]; then - raw_line=$(grep -i '^[[:space:]]*Name:' "$ini" | head -n1 || true) - raw="${raw_line#*:}" - raw="${raw#"${raw%%[![:space:]]*}"}" + ini=$(find "$DANSER_SKINS_DIR/$skin" -maxdepth 1 -type f -iname "skin.ini" -print -quit || true) + if [[ -f "$ini" ]]; then + raw=$(grep -i '^[[:space:]]*Name:' "$ini" | head -n1 || true) + raw="${raw#*:}" header=$(sanitize "$raw") fi @@ -846,23 +869,23 @@ jobs: expect_icon="$header-mod-icons.png" expect_osk="$header.osk" - prune() { + prune_dir() { root=$1; expected=$2 dir="$root/$skin" - [ -d "$dir" ] || return + [ ! -d "$dir" ] && return for f in "$dir"/*; do [ -e "$f" ] || continue - if [ "$(basename "$f")" != "$expected" ]; then + if [[ "$(basename "$f")" != "$expected" ]]; then echo " → Removing unexpected file: $f" rm -f "$f" fi done } - prune "$REPO_SCREENSHOT_DIR" "$expect_gif" - prune "$REPO_RANKING_PANEL_DIR" "$expect_png" - prune "$REPO_MOD_ICONS_DIR" "$expect_icon" - prune "$OSK_PATH" "$expect_osk" + prune_dir "$REPO_SCREENSHOT_DIR" "$expect_gif" + prune_dir "$REPO_RANKING_PANEL_DIR" "$expect_png" + prune_dir "$REPO_MOD_ICONS_DIR" "$expect_icon" + prune_dir "$OSK_PATH" "$expect_osk" done echo "[Cleanup Extra Files Complete]"