Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .github/workflows/Create-NewReleases.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,17 @@ jobs:
- name: Push Changes
run: git push origin main

- name: Build and Validate Counted Release Assets
run: |
cp MerlinAU.sh MerlinAU-install.sh
cp MerlinAU.sh MerlinAU-update.sh

sed -i 's/^readonly RELEASE_ASSET_KIND=.*/readonly RELEASE_ASSET_KIND="install"/' MerlinAU-install.sh
sed -i 's/^readonly RELEASE_ASSET_KIND=.*/readonly RELEASE_ASSET_KIND="update"/' MerlinAU-update.sh

grep -Fxq 'readonly RELEASE_ASSET_KIND="install"' MerlinAU-install.sh
grep -Fxq 'readonly RELEASE_ASSET_KIND="update"' MerlinAU-update.sh

- name: Create and Push Tag
run: |
git tag ${{ steps.nextver.outputs.tag }}
Expand All @@ -92,3 +103,6 @@ jobs:
name: "Release ${{ steps.nextver.outputs.tag }}"
prerelease: false
generate_release_notes: true
files: |
MerlinAU-install.sh
MerlinAU-update.sh
64 changes: 64 additions & 0 deletions .github/workflows/Track_Metrics_MerlinAU.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Track Release Downloads

on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:

jobs:
snapshot-metrics:
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- name: Checkout repository
uses: actions/checkout@v7.0.1
with:
fetch-depth: 0

- name: Restore metrics history
shell: bash
run: |
mkdir -p metrics

if git ls-remote --exit-code --heads origin metrics >/dev/null 2>&1; then
git fetch origin metrics:refs/remotes/origin/metrics
git show origin/metrics:metrics/release_downloads.csv \
> metrics/release_downloads.csv 2>/dev/null || true
fi

- name: Snapshot release download counts
env:
GITHUB_REPOSITORY: ${{ github.repository }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: python3 track_downloads.py

- name: Publish metrics history
shell: bash
run: |
cp metrics/release_downloads.csv /tmp/release_downloads.csv
rm -rf metrics

git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

if git show-ref --verify --quiet refs/remotes/origin/metrics; then
git switch --force-create metrics origin/metrics
else
git switch --orphan metrics
git rm -rf . >/dev/null 2>&1 || true
fi

mkdir -p metrics
cp /tmp/release_downloads.csv metrics/release_downloads.csv

git add metrics/release_downloads.csv

if git diff --cached --quiet; then
echo "No metrics changes to commit."
exit 0
fi

git commit -m "Update release download metrics"
git push origin metrics
119 changes: 111 additions & 8 deletions MerlinAU.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
set -u

## Set version for each Production Release ##
readonly SCRIPT_VERSION=1.6.9
readonly SCRIPT_VERSTAG="26092509"
readonly SCRIPT_VERSION=1.7.0
readonly SCRIPT_VERSTAG="26092816"
readonly SCRIPT_NAME="MerlinAU"
## Set to "master" for Production Releases ##
SCRIPT_BRANCH="master"
SCRIPT_BRANCH="dev"

##----------------------------------------##
## Modified by Martinski W. [2024-Jul-03] ##
Expand All @@ -32,6 +32,15 @@ SCRIPT_BRANCH="master"
readonly SCRIPT_URL_BASE="https://raw.githubusercontent.com/ExtremeFiretop/MerlinAutoUpdate-Router"
SCRIPT_URL_REPO="${SCRIPT_URL_BASE}/$SCRIPT_BRANCH"

# Production release assets are used for install/update downloads so GitHub's
# native per-asset download counters can provide aggregate usage statistics.
# Development builds continue to use raw.githubusercontent.com.
readonly RELEASE_URL_BASE="https://github.com/ExtremeFiretop/MerlinAutoUpdate-Router/releases/download"
readonly RELEASE_INSTALL_ASSET="${SCRIPT_NAME}-install.sh"
readonly RELEASE_UPDATE_ASSET="${SCRIPT_NAME}-update.sh"
# Rewritten to "install" or "update" in generated GitHub Release assets.
readonly RELEASE_ASSET_KIND="source"

# Firmware URL Info #
readonly FW_SFURL_BASE="https://sourceforge.net/projects/asuswrt-merlin/files"
readonly FW_SFURL_RELEASE_SUFFIX="Release"
Expand Down Expand Up @@ -2947,9 +2956,14 @@ _CurlFileDownload_()
then return 1
fi
local tempFilePathDL="${2}.DL.$$.TMP"
local srceFilePathURL="${SCRIPT_URL_REPO}/$1"
local srceFilePathURL
local curlRetCode returnCODE statusSTRx httpStatusSTR

if [ $# -gt 2 ] && [ -n "$3" ]
then srceFilePathURL="$3"
else srceFilePathURL="${SCRIPT_URL_REPO}/$1"
fi

rm -f "$tempFilePathDL"
printf '' > "$curlErrLogFPath"
printf '' > "$curlTmpLogFPath"
Expand Down Expand Up @@ -2995,9 +3009,60 @@ _CurlFileDownload_()
return "$returnCODE"
}

##----------------------------------------##
## Modified by maghuro [2026-Sep-24] ##
##----------------------------------------##
##------------------------------------------##
## Added by ExtremeFiretop [2026-Sep-28] ##
##------------------------------------------##
# Download a production script from a version-pinned GitHub Release asset.
# Validate the downloaded script's asset type before replacing the installed script.
# This provides aggregate GitHub# download counts without adding a third-party redirect service
# or a persistent client identifier.
_DownloadReleaseScriptAsset_()
{
if [ $# -lt 3 ] || [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]
then return 1
fi

local assetKind="$1" releaseVersion="$2" destFilePath="$3"
local assetName releaseBaseURL tempScriptPath
local downloadedKind

case "$assetKind" in
install) assetName="$RELEASE_INSTALL_ASSET" ;;
update) assetName="$RELEASE_UPDATE_ASSET" ;;
*) return 1 ;;
esac

releaseBaseURL="${RELEASE_URL_BASE}/${releaseVersion}"
tempScriptPath="${destFilePath}.REL.$$.TMP"
rm -f "$tempScriptPath"

if ! _CurlFileDownload_ "$assetName" "$tempScriptPath" \
"${releaseBaseURL}/${assetName}"
then
rm -f "$tempScriptPath"
return 1
fi

downloadedKind="$(grep -m1 '^readonly RELEASE_ASSET_KIND=' "$tempScriptPath" | cut -d'"' -f2)"

if [ "$downloadedKind" != "$assetKind" ]
then
Say "${REDct}**ERROR**${NOct}: Release asset type validation failed for [$assetName]."
rm -f "$tempScriptPath"
return 1
fi

if ! mv -f "$tempScriptPath" "$destFilePath"
then
rm -f "$tempScriptPath"
return 1
fi
return 0
}

##------------------------------------------##
## Modified by ExtremeFiretop [2026-Sep-28] ##
##------------------------------------------##
_DownloadScriptFiles_()
{
local retCode=0 isUpdateAction updatedWebUIPage theWebPage
Expand Down Expand Up @@ -3038,7 +3103,45 @@ _DownloadScriptFiles_()
Say "${REDct}**ERROR**${NOct}: Unable to download latest WebUI ASP file for $SCRIPT_NAME."
fi

if _CurlFileDownload_ "${SCRIPT_NAME}.sh" "$ScriptFilePath"
local scriptDownloadOK=false releaseVersion

# Stable production installs/updates use GitHub Release assets so GitHub
# can count aggregate install/update downloads. Development stays on raw
# GitHub and is intentionally excluded from production download counts.
if [ "$SCRIPT_BRANCH" = "master" ]
then
if "$isUpdateAction"
then
releaseVersion="$DLRepoVersion"
[ -z "$releaseVersion" ] && releaseVersion="$(head -n1 "$SCRIPT_VERPATH")"
if _DownloadReleaseScriptAsset_ update "$releaseVersion" "$ScriptFilePath"
then scriptDownloadOK=true
fi
elif [ "$RELEASE_ASSET_KIND" = "install" ]
then
# The bootstrap itself was the counted install asset. Do not fetch
# the same asset a second time and inflate the install counter.
scriptDownloadOK=true
else
releaseVersion="$(head -n1 "$SCRIPT_VERPATH")"
if _DownloadReleaseScriptAsset_ install "$releaseVersion" "$ScriptFilePath"
then
scriptDownloadOK=true
else
# Preserve compatibility with a short release-publication race
# or an older AMTM bootstrap by falling back to the raw script.
Say "${YLWct}*WARNING*${NOct}: Counted install asset unavailable; falling back to repository source."
if _CurlFileDownload_ "${SCRIPT_NAME}.sh" "$ScriptFilePath"
then scriptDownloadOK=true
fi
fi
fi
elif _CurlFileDownload_ "${SCRIPT_NAME}.sh" "$ScriptFilePath"
then
scriptDownloadOK=true
fi

if "$scriptDownloadOK"
then
dos2unix "$ScriptFilePath"
chmod 755 "$ScriptFilePath"
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,13 @@ Use your preferred SSH client to connect to the router.
*Manual Installation*
1. To Download the script to your router, Copy and paste:
```bash
curl --retry 3 "https://raw.githubusercontent.com/ExtremeFiretop/MerlinAutoUpdate-Router/master/MerlinAU.sh" -o "/jffs/scripts/MerlinAU.sh" && chmod +x "/jffs/scripts/MerlinAU.sh" && sh /jffs/scripts/MerlinAU.sh install
curl -fL --retry 3 "https://github.com/ExtremeFiretop/MerlinAutoUpdate-Router/releases/latest/download/MerlinAU-install.sh" -o "/jffs/scripts/MerlinAU.sh" && chmod +x "/jffs/scripts/MerlinAU.sh" && sh /jffs/scripts/MerlinAU.sh install
```
- The script is now ready for use!

### Aggregate Download Counts and Privacy
Stable MerlinAU releases use separate GitHub Release assets for fresh installs and script updates. This way, GitHub's native download counter can provide aggregate install/update activity without adding a third-party gateway, cookies, installation ID, or telemetry.
The counters represent **download events, not unique users or routers**. Reinstalls, forced updates, retries, or manual downloads can increment them more than once.

## Usage

Expand Down
Loading
Loading