Files
skins/.gitea/workflows/ci.yml
2025-11-22 23:46:46 +01:00

354 lines
12 KiB
YAML

name: Update Community Skins README
on:
schedule:
- cron: '*/5 * * * *'
workflow_dispatch:
env:
README_PATH: "${{ github.workspace }}/README.md"
IMAGE_NAME: osc/skins-image
GITEA_API: https://${{ vars.CONTAINER_REGISTRY }}/api/v1
ARTIFACT_PATH: "/data"
USER_ROWS_FILE: "/data/user_rows.txt"
AVATAR_ROWS_FILE: "/data/avatar_rows.txt"
jobs:
gather-skins:
runs-on: ubuntu-latest
container:
image: ${{ vars.CONTAINER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
steps:
- id: mask-secrets
name: Mask Sensitive Tokens
run: |
echo "::add-mask::${{ secrets.TOKEN }}"
echo "::add-mask::${{ secrets.OSUAPIV1 }}"
- id: checkout-code
name: Checkout Repository
uses: actions/checkout@v4
with:
token: ${{ secrets.TOKEN }}
- id: fetch-skins-data
name: Find Skin Repositories and Generate Tables
run: |
set -eo pipefail
mkdir -p "$ARTIFACT_PATH"
total_valid_entries=0
json_valid() {
jq -e . >/dev/null 2>&1
}
fetch_json() {
url="$1"
body_file=$(mktemp)
code=$(curl --retry 3 --retry-delay 5 -s -o "$body_file" -w "%{http_code}" "$url")
echo "$code" "$body_file"
}
page=1
while :; do
# --- Fetch user list ---
set -- $(fetch_json "$GITEA_API/admin/users?limit=50&page=$page&_ts=$(date +%s)")
users_code="$1"
users_body="$2"
users_json=$(cat "$users_body")
if [ "$users_code" != "200" ] || ! printf "%s" "$users_json" | json_valid; then
echo "❌ Invalid users JSON on page $page (HTTP $users_code)"
echo "$users_json" > "$ARTIFACT_PATH/invalid_users_page_${page}.json"
break
fi
count=$(printf "%s" "$users_json" | jq 'length')
[ "$count" -eq 0 ] && break
echo "📄 Found $count users on page $page"
# --- Loop through users ---
for i in $(seq 0 $((count - 1))); do
user_login=$(printf "%s" "$users_json" | jq -r ".[$i].login")
echo "🔍 User: $user_login"
# --- Fetch repos list ---
set -- $(fetch_json "$GITEA_API/users/$user_login/repos?_ts=$(date +%s)")
repos_code="$1"
repos_body="$2"
repos_json=$(cat "$repos_body")
if [ "$repos_code" != "200" ] || ! printf "%s" "$repos_json" | json_valid; then
echo " ❌ Invalid repo list for $user_login (HTTP $repos_code)"
echo "$repos_json" > "$ARTIFACT_PATH/invalid_repos_${user_login}.json"
continue
fi
repos_count=$(printf "%s" "$repos_json" | jq 'length')
echo " 📦 $repos_count repos found"
[ "$repos_count" -eq 0 ] && continue
# --- Loop through repos ---
for j in $(seq 0 $((repos_count - 1))); do
owner=$(printf "%s" "$repos_json" | jq -r ".[$j].owner.login")
repo=$(printf "%s" "$repos_json" | jq -r ".[$j].name")
html_url=$(printf "%s" "$repos_json" | jq -r ".[$j].html_url")
echo " → Repo: $owner/$repo"
# --- Check Skins directory ---
set -- $(fetch_json "$GITEA_API/repos/$owner/$repo/contents/Skins?_ts=$(date +%s)")
dir_code="$1"
if [ "$dir_code" != "200" ]; then
echo " ❌ Skipped: No Skins/ directory (HTTP $dir_code)"
continue
fi
# --- Fetch README.md ---
set -- $(fetch_json "$GITEA_API/repos/$owner/$repo/contents/README.md?_ts=$(date +%s)")
readme_code="$1"
readme_body="$2"
readme_json=$(cat "$readme_body")
if [ "$readme_code" != "200" ] || ! printf "%s" "$readme_json" | json_valid; then
echo " ❌ Skipped: No README.md or invalid JSON (HTTP $readme_code)"
continue
fi
# Decode README
content=$(printf "%s" "$readme_json" | jq -r .content | base64 -d 2>/dev/null || echo "")
osu_id=$(printf "%s" "$content" | grep -oE "osuid:[ ]*[0-9]+" | grep -oE "[0-9]+" | head -1)
if [ -z "$osu_id" ]; then
echo " ❌ Skipped: No osuid in README"
continue
fi
# --- Fetch osu API ---
set -- $(fetch_json "https://osu.ppy.sh/api/get_user?k=${{ secrets.OSUAPIV1 }}&u=$osu_id&type=id&_ts=$(date +%s)")
api_code="$1"
api_body="$2"
osu_json=$(cat "$api_body")
if ! printf "%s" "$osu_json" | json_valid; then
echo " ❌ Invalid osu! API JSON for $osu_id"
printf "%s" "$osu_json" > "$ARTIFACT_PATH/invalid_osu_user_${osu_id}.json"
continue
fi
if [ "$(printf "%s" "$osu_json" | jq 'length')" -eq 0 ]; then
echo " 🚫 Restricted or banned user"
username="$owner"
pp_rank="RESTRICTED"
pp_country_rank="RESTRICTED"
padded_rank="9999999"
profile_url="https://osu.ppy.sh/users/$osu_id"
timestamp=$(( $(date +%s)/86400*86400 ))
avatar_url="https://a.ppy.sh/$osu_id?$timestamp"
printf "%s|<tr><td>%s</td><td>%s</td><td>%s</td><td><a href=\"%s\">Profile</a></td><td><a href=\"%s\">Skins</a></td></tr>\n" \
"$padded_rank" "$username" "$pp_rank" "$pp_country_rank" "$profile_url" "$html_url" >> "$USER_ROWS_FILE"
printf "%s|<a href=\"%s\"><img src=\"%s\" width=\"175\" height=\"175\"></a>\n" \
"$padded_rank" "$html_url" "$avatar_url" >> "$AVATAR_ROWS_FILE"
total_valid_entries=$((total_valid_entries + 1))
continue
fi
# Normal osu user
pp_rank=$(printf "%s" "$osu_json" | jq -r '.[0].pp_rank // "9999999"')
pp_country_rank=$(printf "%s" "$osu_json" | jq -r '.[0].pp_country_rank // "-"')
country=$(printf "%s" "$osu_json" | jq -r '.[0].country // "-"')
username=$(printf "%s" "$osu_json" | jq -r '.[0].username')
padded_rank=$(printf "%07d" "$pp_rank")
if [ "$pp_country_rank" != "-" ] && [ "$country" != "-" ]; then
cc_rank="${country}${pp_country_rank}"
else
cc_rank="-"
fi
timestamp=$(( $(date +%s)/86400*86400 ))
printf "%s|<tr><td>%s</td><td>%s</td><td>%s</td><td><a href=\"https://osu.ppy.sh/users/%s\">Profile</a></td><td><a href=\"%s\">Skins</a></td></tr>\n" \
"$padded_rank" "$username" "$pp_rank" "$cc_rank" "$osu_id" "$html_url" >> "$USER_ROWS_FILE"
printf "%s|<a href=\"%s\"><img src=\"https://a.ppy.sh/%s?%s\" width=\"175\" height=\"175\"></a>\n" \
"$padded_rank" "$html_url" "$osu_id" "$timestamp" >> "$AVATAR_ROWS_FILE"
echo " ✅ Added: $username (#$pp_rank, $cc_rank)"
total_valid_entries=$((total_valid_entries + 1))
done
done
page=$((page + 1))
done
echo "✅ Total valid entries found: $total_valid_entries"
- id: upload-tables
name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: skin-tables
path: ${{ env.ARTIFACT_PATH }}
retention-days: 1
generate-readme:
needs: gather-skins
runs-on: ubuntu-latest
container:
image: ${{ vars.CONTAINER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
outputs:
readme_changed: ${{ steps.check-readme.outputs.changed }}
steps:
- id: download-skin-data
name: Download skin data
uses: actions/download-artifact@v3
with:
name: skin-tables
path: ${{ env.ARTIFACT_PATH }}
- id: checkout-code
name: Checkout Repository
uses: actions/checkout@v4
with:
token: ${{ secrets.TOKEN }}
- id: generate-readme
name: Generate README
run: |
set -eo pipefail
cat > "$README_PATH" <<-EOF
# osu! Swiss Community Skin collection
Welcome to the osu! Swiss Community Skin collection, this repository archives and showcases Skins osc members use.
Enjoy looking around, click file names to download the skins and click on the images to see more about the skins.
## How do I add my skins here?
If you're interested in adding your skins here please follow this tutorial [how-to-use](/how-to-use.md)
## Skins
<details>
<summary>list instead of icons</summary>
<br />
<table border="1" cellpadding="5" cellspacing="0">
<thead>
<tr>
<th>Name</th>
<th>Global Rank</th>
<th>Country Rank</th>
<th>Profile</th>
<th>Skins</th>
</tr>
</thead>
<tbody>
EOF
sort -t '|' -k1,1n "$USER_ROWS_FILE" | cut -d'|' -f2- | sed 's/^/ /' >> "$README_PATH"
cat >> "$README_PATH" <<-EOF
</tbody>
</table>
</details>
<p align="center">
EOF
sort -t '|' -k1,1n "$AVATAR_ROWS_FILE" | cut -d'|' -f2- | sed 's/^/ /' >> "$README_PATH"
cat >> "$README_PATH" <<-EOF
</p>
EOF
- id: check-readme
name: Check for README changes
run: |
set -euo pipefail
# Make sure the workspace is considered safe by git inside containers
git config --global --add safe.directory "$GITHUB_WORKSPACE"
# Ensure diff works even if file were new (intent-to-add)
git add -N "$README_PATH" || true
if git diff --quiet -- "$README_PATH"; then
echo "✅ README unchanged"
echo "changed=false" >> "$GITHUB_OUTPUT"
else
echo "⚠️ README was modified"
echo "changed=true" >> "$GITHUB_OUTPUT"
git --no-pager diff --stat -- "$README_PATH" || true
fi
- id: upload-updated-readme
name: Upload updated README
if: steps.check-readme.outputs.changed == 'true'
uses: actions/upload-artifact@v3
with:
name: updated-readme
path: ${{ env.README_PATH }}
retention-days: 1
commit-readme:
needs: generate-readme
if: needs.generate-readme.outputs.readme_changed == 'true'
runs-on: ubuntu-latest
container:
image: ${{ vars.CONTAINER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
steps:
- id: checkout-code
name: Checkout Repository
uses: actions/checkout@v4
with:
token: ${{ secrets.TOKEN }}
- id: configure-git
name: Configure Git
run: |
git config user.email "arlind@sulej.ch"
git config user.name "ci-bot"
git config lfs.https://${{ vars.CONTAINER_REGISTRY }}/arlind/skins.git/info/lfs.locksverify true
- id: rebase-repository
name: Rebase Repository
run: |
git fetch origin main
git rebase origin/main || {
echo "⚠️ Git rebase failed, likely due to conflicts."
git rebase --abort || true
exit 1
}
- id: download-updated-readme
name: Download README
uses: actions/download-artifact@v3
with:
name: updated-readme
path: .
- id: commit-and-push
name: Commit and Push README
run: |
git config advice.addIgnoredFile false
git add README.md
git commit -m "[ci skip] push back from pipeline" -q || echo "No changes to commit"
if [ "${GITHUB_REF}" = "refs/heads/main" ]; then
git push origin HEAD:main || echo "No changes to push"
else
git push origin HEAD:"${GITHUB_REF_NAME}" || echo "No changes to push"
fi