forked from refined-github/refined-github
-
Notifications
You must be signed in to change notification settings - Fork 1
/
release-download-count.tsx
94 lines (83 loc) · 2.44 KB
/
release-download-count.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import './release-download-count.css';
import React from 'dom-chef';
import select from 'select-dom';
import DownloadIcon from 'octicon/download.svg';
import * as pageDetect from 'github-url-detection';
import features from '.';
import * as api from '../github-helpers/api';
import {getRepoGQL} from '../github-helpers';
interface Asset {
name: string;
downloadCount: number;
}
type Tag = Record<string, Asset[]>;
async function getAssetsForTag(tags: string[]): Promise<Tag> {
const {repository} = await api.v4(`
repository(${getRepoGQL()}) {
${tags.map(tag => `
${api.escapeKey(tag)}: release(tagName:"${tag}") {
releaseAssets(first: 100) {
nodes {
name
downloadCount
}
}
}
`).join()}
}
`);
const assets: Tag = {};
for (const [tag, release] of Object.entries(repository)) {
assets[tag] = (release as AnyObject).releaseAssets.nodes;
}
return assets;
}
function prettyNumber(value: number): string {
let newValue = value;
const suffixes = ['', 'K', 'M', 'B', 'T'];
let suffixNumber = 0;
while (newValue >= 1000) {
newValue /= 1000;
suffixNumber++;
}
return `${Number(newValue.toPrecision(3))} ${suffixes[suffixNumber]}`;
}
async function init(): Promise<void | false> {
const releases = new Map();
for (const release of select.all('.release')) {
if (select.exists('.octicon-package', release)) {
const name = select('svg.octicon-tag ~ span', release)!.textContent!;
releases.set(name, release);
}
}
if (releases.size === 0) {
return false;
}
const assets = await getAssetsForTag([...releases.keys()]);
for (const [name, release] of releases) {
const sortedDownloads = assets[api.escapeKey(name)].sort((a, b) => b.downloadCount - a.downloadCount);
for (const assetName of select.all('.octicon-package ~ span', release)) {
// Match the asset in the DOM to the asset in the API response
for (const [index, {name, downloadCount}] of sortedDownloads.entries()) {
if (name === assetName.textContent && downloadCount > 0) {
const classes = 'rgh-release-download-count mr-2 text-gray' + (index === 0 ? ' text-bold' : '');
// Place next to asset size
assetName
.closest('.Box-body')!
.querySelector('small')!
.before(
<small className={classes} title="Downloads">
{prettyNumber(downloadCount)} <DownloadIcon/>
</small>
);
}
}
}
}
}
void features.add(__filebasename, {
include: [
pageDetect.isReleasesOrTags
],
init
});