name: Update Community Skins README on: schedule: - cron: '*/5 * * * *' workflow_dispatch: env: IMAGE_NAME: osc/skins-image GITEA_API: https://${{ vars.CONTAINER_REGISTRY }}/api/v1 README_PATH: "README.md" jobs: fetch_and_process_data: name: Fetch and Process Skin Data runs-on: ubuntu-latest container: image: ${{ vars.CONTAINER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest outputs: user_rows_file: ${{ steps.generate_data.outputs.user_rows_file }} avatar_rows_file: ${{ steps.generate_data.outputs.avatar_rows_file }} total_valid_entries: ${{ steps.generate_data.outputs.total_valid_entries }} steps: - name: Checkout Repository uses: actions/checkout@v4 with: token: ${{ secrets.TOKEN }} - name: Pull latest changes run: git pull --rebase origin main || echo "Nothing to rebase" - name: Generate Skin Data Files id: generate_data shell: bash run: | set -euo pipefail total_valid_entries=0 user_rows_file=$(mktemp) avatar_rows_file=$(mktemp) page=1 users_data_found=true while "$users_data_found"; do echo "Fetching users page $page..." >&2 users_json=$(curl --fail --retry 3 --retry-delay 5 -sSL \ -H "Authorization: token ${{ secrets.TOKEN }}" \ "$GITEA_API/admin/users?limit=50&page=$page&_ts=$(date +%s)") if [ "$(echo "$users_json" | jq 'length')" -eq 0 ]; then users_data_found=false break fi mapfile -t user_logins < <(echo "$users_json" | jq -r '.[].login') for user_login in "${user_logins[@]}"; do echo "Processing user: $user_login" >&2 repos_json=$(curl --fail --retry 3 --retry-delay 5 -sSL \ -H "Authorization: token ${{ secrets.TOKEN }}" \ "$GITEA_API/users/$user_login/repos?limit=50&page=1&_ts=$(date +%s)") if ! echo "$repos_json" | jq -e '.[0]' >/dev/null; then continue fi mapfile -t repo_details < <(echo "$repos_json" | jq -r '.[] | .owner.login, .name, .html_url') for ((i=0; i<${#repo_details[@]}; i+=3)); do owner="${repo_details[i]}" repo="${repo_details[i+1]}" html_url="${repo_details[i+2]}" echo " Checking repo: $repo" >&2 curl -sSL -w "%{http_code}" -o readme_content.json \ -H "Authorization: token ${{ secrets.TOKEN }}" \ "$GITEA_API/repos/$owner/$repo/contents/README.md?_ts=$(date +%s)" > http_code.txt http_code=$(cat http_code.txt) rm -f http_code.txt if [ "$http_code" != "200" ]; then echo "README not found for $owner/$repo (HTTP $http_code)" >&2 continue fi readme_content=$(jq -r '.content' readme_content.json | base64 -d || echo "") rm -f readme_content.json if echo "$readme_content" | grep -qE "^---$" && \ echo "$readme_content" | grep -qE "^gitea: none" && \ echo "$readme_content" | grep -qE "^include_toc: true" && \ echo "$readme_content" | grep -qE "^# Skins"; then osu_id=$(echo "$readme_content" | awk '/osuid:[ ]*[0-9]+/ { match($0, /[0-9]+/); print substr($0, RSTART, RLENGTH); exit }') if [ -n "$osu_id" ]; then user_data=$(curl --fail --retry 3 --retry-delay 5 -s \ "https://osu.ppy.sh/api/get_user?k=${{ secrets.OSUAPIV1 }}&u=$osu_id&type=id&_ts=$(date +%s)") if ! echo "$user_data" | jq -e '.[0]' >/dev/null; then echo "No osu! data found for ID: $osu_id" >&2 continue fi pp_rank=$(echo "$user_data" | jq -r '.[0].pp_rank // "9999999"') pp_country_rank=$(echo "$user_data" | jq -r '.[0].pp_country_rank // "-"') username=$(echo "$user_data" | jq -r --arg owner "$owner" '.[0].username // $owner') padded_rank=$(printf "%07d" "$pp_rank") printf "%s|%s%s%sProfileSkins\n" \ "$padded_rank" "$username" "$pp_rank" "$pp_country_rank" "$osu_id" "$html_url" >> "$user_rows_file" timestamp=$(( $(date +%s) / 86400 * 86400 )) printf "%s|\n" \ "$padded_rank" "$html_url" "$osu_id" "$timestamp" >> "$avatar_rows_file" total_valid_entries=$((total_valid_entries + 1)) else echo "osu! ID not found in README for $owner/$repo" >&2 fi else echo "README for $owner/$repo does not match required format" >&2 fi done done page=$((page + 1)) done { echo "user_rows_file=$user_rows_file" echo "avatar_rows_file=$avatar_rows_file" echo "total_valid_entries=$total_valid_entries" } >> "$GITHUB_OUTPUT" update_and_push_readme: name: Update README and Push Changes runs-on: ubuntu-latest needs: fetch_and_process_data container: image: ${{ vars.CONTAINER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest steps: - name: Checkout Repository uses: actions/checkout@v4 with: token: ${{ secrets.TOKEN }} - name: Update README with user skins run: | user_rows_file="${{ needs.fetch_and_process_data.outputs.user_rows_file }}" avatar_rows_file="${{ needs.fetch_and_process_data.outputs.avatar_rows_file }}" 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
list instead of icons
EOF sort -t '|' -k1,1n "$user_rows_file" | cut -d'|' -f2- | sed 's/^/ /' >> "$README_PATH" cat >> "$README_PATH" <<-EOF
Name Global Rank Country Rank Profile Skins

EOF sort -t '|' -k1,1n "$avatar_rows_file" | cut -d'|' -f2- | sed 's/^/ /' >> "$README_PATH" cat >> "$README_PATH" <<-EOF

EOF rm -f "$user_rows_file" "$avatar_rows_file" - 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 - name: Add and Commit changes run: | git config advice.addIgnoredFile false git add "$README_PATH" git commit -m "[ci skip] push back from pipeline" -q || echo "No changes to commit" - name: Push changes and create tag run: | 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