-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgithub-stars.js
139 lines (119 loc) · 4.12 KB
/
github-stars.js
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
const EXPIRE_AFTER = 1000 * 60 * 60 * 24; // 1 day
const GITHUB_STAR_MARK = `<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-label='star' height='16' class='octicon octicon-star v-align-text-bottom' viewBox='0 0 14 16' version='1.1' width='14' role='img'%3E%3Cpath fill-rule='evenodd' d='M14 6l-4.9-.64L7 1 4.9 5.36 0 6l3.6 3.26L2.67 14 7 11.67 11.33 14l-.93-4.74L14 6z'%3E%3C/path%3E%3C/svg%3E" width="14px" height="14px" style="display: inline; margin: 0px; padding: 1px; width: 14px;" />`;
const extractRepoFromUrl = function (url) {
const match = url.match(
/^https?:\/\/github.com\/([a-zA-Z0-9_\-\.]+)?\/([a-zA-Z0-9_\-\.]+)\/?$/
);
if (!match) {
return [false, null];
}
return [true, { user: match[1], repo: match[2] }];
};
const saveToCache = function (url, stargazersCount) {
const value = { stargazersCount, timestamp: new Date().getTime() };
chrome.storage.local.set({ [url]: value }, () => {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError);
return;
}
console.debug(
"Stored stargazersCount to local storage for url",
url,
stargazersCount
);
});
};
const requestQueue = [];
let isProcessing = false;
const BATCH_SIZE = 50; // Number of requests to process at a time
const processQueue = () => {
if (requestQueue.length === 0) {
isProcessing = false; // Reset processing flag when the queue is empty
return; // Exit if there's nothing to process
}
isProcessing = true; // Set processing flag
const batch = requestQueue.splice(0, BATCH_SIZE); // Get the next batch of requests
// Process each request in the batch
const promises = batch.map(({ url, token, onStargazersCount }) =>
fetchGithubStars(url, token, onStargazersCount)
);
// Wait for all promises in the batch to resolve
Promise.all(promises)
.then(() => {
setTimeout(processQueue, 500); // Delay before processing the next batch
})
.catch(() => {
setTimeout(processQueue, 500); // Delay even on error
});
};
const queueFetchGithubStars = function (url, token, onStargazersCount) {
requestQueue.push({ url, token, onStargazersCount });
checkQueue(); // Check the queue to start processing if needed
};
const checkQueue = () => {
if (requestQueue.length > 0 && !isProcessing) {
processQueue(); // Start processing if there are items in the queue
}
};
const fetchGithubStars = function (url, token, onStargazersCount) {
const [_, { user, repo }] = extractRepoFromUrl(url);
const apiUrl = `https://api.github.com/repos/${user}/${repo}`;
const headers = {};
if (token) {
headers["Authorization"] = `token ${token}`;
}
return fetch(apiUrl, { headers })
.then((response) => {
return response.json().then((data) => {
if (
data.message &&
data.message.match(/API rate limit exceeded/)
) {
throw new Error(
"Github API Rate limit exceeded. Please set an auth token in the options page."
);
}
let count;
if (data.message === "Not Found") {
count = "NOT_A_REPO";
} else {
count = data.stargazers_count;
}
saveToCache(url, count);
return count;
});
})
.then(onStargazersCount)
.catch((err) => {
console.error(`Failed to fetch stars for ${apiUrl}`, err);
onStargazersCount("NOT_A_REPO");
});
};
const displayCachedOrRemoteGithubStars = function (
url,
token,
onStargazersCount
) {
const [ok, _] = extractRepoFromUrl(url);
if (!ok) {
onStargazersCount("NOT_A_REPO");
return;
}
chrome.storage.local.get(url, (result) => {
const cached = result[url];
if (!cached) {
queueFetchGithubStars(url, token, onStargazersCount);
return;
}
const isExpired = cached.timestamp + EXPIRE_AFTER < Date.now();
if (cached.stargazersCount === "NOT_A_REPO") {
onStargazersCount("NOT_A_REPO");
return;
}
if (isExpired || cached.stargazersCount === undefined) {
queueFetchGithubStars(url, token, onStargazersCount);
} else {
onStargazersCount(cached.stargazersCount);
}
});
};