Download milestone check #574
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Download milestone check | |
| # Checks the CF download total every 4 hours and posts a celebratory message | |
| # to Discord (and Facebook if token is valid) when a milestone is first crossed. | |
| # Milestones already hit are recorded in data/milestones-hit.json so they never | |
| # fire twice. | |
| on: | |
| schedule: | |
| - cron: '47 */4 * * *' | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| env: | |
| DISCORD_CHANNEL_ID: '1502850493658042391' | |
| FB_PAGE_ID: '1183968144796759' | |
| CF_SUITE_URL: 'https://www.curseforge.com/members/wick/projects' | |
| jobs: | |
| check: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Fetch current download total | |
| id: total | |
| env: | |
| CF_CORE_API_KEY: ${{ secrets.CF_CORE_API_KEY }} | |
| run: | | |
| set -euo pipefail | |
| TOTAL=0 | |
| for ID in 1502804 1519243 1502890 1521208 1525232 1532082 1533199 1535194 1537836 1538543 1540943 1542398 1557237; do | |
| BODY=$(curl -sf \ | |
| -H "x-api-key: $CF_CORE_API_KEY" \ | |
| -A "Wicksmods milestone checker (https://github.com/Wicksmods/Wicksmods.github.io)" \ | |
| "https://api.curseforge.com/v1/mods/$ID" \ | |
| || echo '{"data":{}}') | |
| P=$(echo "$BODY" | jq '.data.downloadCount // 0') | |
| TOTAL=$((TOTAL + P)) | |
| done | |
| echo "total=$TOTAL" >> "$GITHUB_OUTPUT" | |
| echo "Current total: $TOTAL" | |
| - name: Check milestones and post | |
| env: | |
| TOTAL: ${{ steps.total.outputs.total }} | |
| DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_BOT_TOKEN }} | |
| FB_PAGE_TOKEN: ${{ secrets.FB_PAGE_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| mkdir -p data | |
| if [ -f data/milestones-hit.json ]; then | |
| HIT=$(cat data/milestones-hit.json) | |
| else | |
| HIT='[]' | |
| fi | |
| CHANGED=false | |
| for M in 2500 5000 10000 25000 50000 100000; do | |
| if echo "$HIT" | jq -e --argjson m "$M" 'contains([$m])' > /dev/null; then | |
| echo " $M already hit, skipping" | |
| continue | |
| fi | |
| if [ "$TOTAL" -ge "$M" ]; then | |
| echo " *** NEW MILESTONE: $M ***" | |
| # Format numbers with commas (locale-safe awk) | |
| fmt_num() { echo "$1" | awk '{ | |
| n = $1; s = "" | |
| while (n >= 1000) { m = n % 1000; n = int(n/1000) | |
| s = (m < 10 ? ",00" : m < 100 ? ",0" : ",") m s } | |
| print n s }'; } | |
| FORMATTED=$(fmt_num "$M") | |
| TOTAL_FMT=$(fmt_num "$TOTAL") | |
| if [ "$M" -eq 2500 ]; then HEADLINE="2,500 downloads. To every raider, alt-aholic, and addon hoarder who installed something from the suite -- thank you. This is just the start." | |
| elif [ "$M" -eq 5000 ]; then HEADLINE="5,000 downloads. That's a lot of cooldowns tracked, macros built, and bags sorted. Genuinely grateful for every install." | |
| elif [ "$M" -eq 10000 ]; then HEADLINE="10,000 downloads. From one solo dev to ten thousand TBC players -- this means everything. See you in Outland." | |
| elif [ "$M" -eq 25000 ]; then HEADLINE="25,000 downloads. The suite has come a long way since the first BIS list. Thank you for making it part of your UI." | |
| elif [ "$M" -eq 50000 ]; then HEADLINE="50,000 downloads. Half way to a hundred thousand TBC players trusting Wick's addons in their UI. Blown away." | |
| elif [ "$M" -eq 100000 ]; then HEADLINE="100,000 downloads. Started as a BIS tracker for my own raid group. Thank you for making it something so much bigger." | |
| else HEADLINE="${FORMATTED} downloads. Thank you for every install." | |
| fi | |
| BODY="${TOTAL_FMT} total downloads across the suite on CurseForge." | |
| FOOTER="Wick's Mods" | |
| # Discord | |
| DISCORD_PAYLOAD=$(jq -n \ | |
| --arg title "$HEADLINE" \ | |
| --arg desc "$BODY" \ | |
| --arg url "$CF_SUITE_URL" \ | |
| --arg footer "$FOOTER" \ | |
| --argjson color 5228408 \ | |
| '{embeds:[{title:$title,description:$desc,color:$color,fields:[{name:"Browse the suite",value:("[CurseForge]("+$url+")"),inline:true}],footer:{text:$footer}}]}') | |
| DISCORD_RESP=$(curl -s -X POST \ | |
| -H "Authorization: Bot $DISCORD_BOT_TOKEN" \ | |
| -H "Content-Type: application/json" \ | |
| -d "$DISCORD_PAYLOAD" \ | |
| "https://discord.com/api/v10/channels/$DISCORD_CHANNEL_ID/messages") | |
| echo " Discord: $DISCORD_RESP" | |
| # Facebook (best-effort) | |
| FB_RESP=$(curl -s -X POST \ | |
| "https://graph.facebook.com/v21.0/$FB_PAGE_ID/feed" \ | |
| --data-urlencode "access_token=$FB_PAGE_TOKEN" \ | |
| --data-urlencode "message=$HEADLINE $BODY $CF_SUITE_URL" \ | |
| || echo '{"skipped":true}') | |
| echo " Facebook: $(echo "$FB_RESP" | head -c 120)" | |
| HIT=$(echo "$HIT" | jq --argjson m "$M" '. + [$m]') | |
| CHANGED=true | |
| fi | |
| done | |
| if [ "$CHANGED" = "true" ]; then | |
| echo "$HIT" | jq '.' > data/milestones-hit.json | |
| echo "Wrote milestones-hit.json: $HIT" | |
| else | |
| echo "No new milestones crossed." | |
| fi | |
| - name: Commit if milestones updated | |
| run: | | |
| git config user.name "Wick" | |
| git config user.email "wicksmods@gmail.com" | |
| git add data/milestones-hit.json | |
| if git diff --staged --quiet; then | |
| echo "No change." | |
| else | |
| git commit -m "Record milestone hit" | |
| git push | |
| fi |