Skip to content

Instantly share code, notes, and snippets.

@TotallyInformation
Created October 1, 2020 16:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TotallyInformation/7d12342915ec522056f0d250be9bfcb6 to your computer and use it in GitHub Desktop.
Save TotallyInformation/7d12342915ec522056f0d250be9bfcb6 to your computer and use it in GitHub Desktop.
Track your Node package downloads

Use Node-RED v1.1+ to keep track of how many downloads your NPM packages get per day.

Uses the newer Inject node features to avoid needing an extra Change node. Also uses the $moment feature of JSONata to select and format the appropriate date range.

This is fed into a request node and from there to a function node that accumulates the daily data into an object:

global-var -> by package-name -> downloads-by-day

A summary of the date ranges and total downloads is also kept.

You can only download a maximum of 12 months when selecting multiple packages but the data goes back to 2015-01-10. I manually downloaded all of the previous years but you can just change the date range in the inject node as it uses MomentJS's very easy to follow format, subtracting days from today.

It doesn't hurt to rerun the query over dates you've already included, the duplicates are ignored.

Make sure you change the date range and package names in the inject node before running.

You may also want to change the global variable settings at the top of the function node.

The flow example given here runs once a week on a Sunday at 00:01 and captures the last 8 days.

[
{
"id": "e514269e.74fb58",
"type": "debug",
"z": "a851b997.a01c18",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 715,
"y": 1220,
"wires": [],
"l": false
},
{
"id": "893de9f.e508e18",
"type": "function",
"z": "a851b997.a01c18",
"name": "",
"func": "const myNpmStats = 'myNpmStats'\nconst fileStore = 'file'\n\nconst out = global.get(myNpmStats, fileStore) || {}\n\nObject.keys(msg.payload).forEach( package => {\n\n if ( !out[package] ) {\n out[package] = {\n 'downloads': {},\n 'package': package,\n 'start': '',\n 'end': '',\n 'days': 0,\n 'totalDownloads': 0,\n }\n }\n\n msg.payload[package].downloads.forEach( entry => {\n \n // Loose any zeros until the first download\n if ( out[package].totalDownloads === 0 ) {\n if ( entry.downloads === 0 ) return\n }\n \n // If this day has already been recorded, skip\n if ( entry.day in out[package].downloads ) return\n \n out[package].downloads[entry.day] = {\n 'date': entry.day,\n 'downloads': entry.downloads,\n }\n \n out[package].totalDownloads += entry.downloads\n \n if ( entry.day < out[package].start || out[package].start === '' ) out[package].start = entry.day\n if ( entry.day > out[package].end ) out[package].end = entry.day\n \n out[package].days++\n \n })\n \n})\n\nglobal.set(myNpmStats, out, fileStore)\nmsg.payload = out\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 655,
"y": 1220,
"wires": [
[
"e514269e.74fb58"
]
],
"l": false
},
{
"id": "9a41f93d.2035f8",
"type": "inject",
"z": "a851b997.a01c18",
"name": "URL/Date-Range/package-set",
"props": [
{
"p": "url",
"v": "\"https://api.npmjs.org/downloads/range/\" & \t\t$moment().subtract(8, 'days').format(\"YYYY-MM-DD\")\t\t& \":\" &\t\t$moment().subtract(1, 'days').format(\"YYYY-MM-DD\")\t\t& \"/\" &\t\t$join([\t \"node-red-contrib-uibuilder\",\t \"node-red-contrib-moment\",\t \"node-red-contrib-globalgetset\",\t \"node-red-contrib-fs\",\t \"node-red-contrib-jktesting\",\t \"node-red-contrib-static-markdown\",\t \"alternate-node-red-installer\"\t ], \",\")\t",
"vt": "jsonata"
}
],
"repeat": "",
"crontab": "01 00 * * 0",
"once": false,
"onceDelay": 0.1,
"topic": "",
"x": 360,
"y": 1220,
"wires": [
[
"d2b0e949.dc6a38"
]
]
},
{
"id": "d2b0e949.dc6a38",
"type": "http request",
"z": "a851b997.a01c18",
"name": "",
"method": "GET",
"ret": "obj",
"paytoqs": "ignore",
"url": "",
"tls": "",
"persist": false,
"proxy": "",
"authType": "",
"x": 535,
"y": 1220,
"wires": [
[
"893de9f.e508e18"
]
],
"l": false
}
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment