mirror of
https://github.com/Xaymar/obs-StreamFX
synced 2024-11-11 06:15:05 +00:00
e3302fa163
Also includes a tool to convert Patreon Membership .csv files into a support patch set.
329 lines
7.8 KiB
JavaScript
329 lines
7.8 KiB
JavaScript
const HTTPS = require("https");
|
|
const PATH = require("path");
|
|
const FS = require("fs/promises");
|
|
const CHILD_PROCESS = require("child_process");
|
|
|
|
function query_git() {
|
|
// git shortlog -sn --all | sed -E "s/^\W+[0-9]+\W+//"
|
|
return (async () => {
|
|
let users = new Map();
|
|
|
|
let git = new Promise((resolve, reject) => {
|
|
try {
|
|
const child = CHILD_PROCESS.spawn('git', ['shortlog', '-sn', '--all']);
|
|
|
|
let sout = "";
|
|
child.stdout.setEncoding('utf8');
|
|
child.stdout.on('data', (data) => {
|
|
sout += data;
|
|
});
|
|
|
|
let serr = "";
|
|
child.stderr.setEncoding('utf8');
|
|
child.stderr.on('data', (data) => {
|
|
serr += data;
|
|
});
|
|
|
|
child.on('close', (code) => {
|
|
if (code != 0) {
|
|
reject([code, serr]);
|
|
} else {
|
|
resolve(sout);
|
|
}
|
|
});
|
|
} catch (e) {
|
|
reject(e);
|
|
}
|
|
});
|
|
|
|
let result = await git;
|
|
let lines = result.matchAll(/^[\s]+([0-9]+)[\s]+(.+)$/gim);
|
|
for (let line of lines) {
|
|
let name = line[2];
|
|
if (!users.has(name)) {
|
|
users.set(name, `https://github.com/${process.env.GITHUB_REPOSITORY}/graphs/contributors`)
|
|
}
|
|
}
|
|
|
|
return users;
|
|
})();
|
|
}
|
|
|
|
function query_crowdin(project_id, project_auth_key) {
|
|
const limit = 100;
|
|
function _query_page(page) {
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
let query = {
|
|
protocol: "https:",
|
|
host: "crowdin.com",
|
|
path: `/api/v2/projects/${project_id}/members?limit=${limit}&offset=${page * limit}`,
|
|
method: "GET",
|
|
headers: {
|
|
"accept": "application/json",
|
|
"authorization": `Bearer ${project_auth_key}`
|
|
}
|
|
};
|
|
let req = HTTPS.request(query, (res) => {
|
|
let data = "";
|
|
res.setEncoding('utf8');
|
|
res.on('data', (chunk) => {
|
|
data += chunk;
|
|
});
|
|
res.on('end', () => {
|
|
res.data = data;
|
|
resolve(res);
|
|
});
|
|
});
|
|
req.end();
|
|
} catch (e) {
|
|
reject(e);
|
|
}
|
|
});
|
|
}
|
|
|
|
return (async () => {
|
|
let page_is_last = false;
|
|
let page = 0;
|
|
|
|
let users = new Map();
|
|
|
|
while (!page_is_last) {
|
|
let res = await _query_page(page++);
|
|
if (res.statusCode == 200) {
|
|
let json = JSON.parse(res.data);
|
|
let count = json.data.length;
|
|
for (let user of json.data) {
|
|
// Don't credit blocked users for work not done.
|
|
if (user.data.role == 'blocked') {
|
|
continue;
|
|
}
|
|
|
|
let key = (user.data.fullName !== null) && (user.data.fullName !== undefined) && (user.data.fullName.length > 0) ? user.data.fullName : user.data.username;
|
|
|
|
users.set(key, `https://crowdin.com/profile/${user.data.username}`);
|
|
}
|
|
|
|
page_is_last = (count < limit);
|
|
} else {
|
|
throw new Error(JSON.parse(res.data));
|
|
}
|
|
}
|
|
|
|
return users;
|
|
})();
|
|
}
|
|
|
|
function query_github_sponsors(auth_token) {
|
|
const HTTPS = require("https");
|
|
|
|
let build_query = function (cursor) {
|
|
if (cursor === undefined) {
|
|
return `query {
|
|
viewer {
|
|
sponsors(after: null, first: 0) {
|
|
totalCount
|
|
}
|
|
}
|
|
}`;
|
|
} else {
|
|
return `query {
|
|
viewer {
|
|
sponsors(after: ${typeof (cursor) == "string" ? `"${cursor}"` : "null"}, first: 100) {
|
|
nodes {
|
|
__typename
|
|
... on User {
|
|
resourcePath
|
|
login
|
|
name
|
|
}
|
|
... on Organization {
|
|
resourcePath
|
|
login
|
|
name
|
|
}
|
|
}
|
|
pageInfo {
|
|
endCursor
|
|
startCursor
|
|
}
|
|
}
|
|
}
|
|
}`;
|
|
}
|
|
}
|
|
|
|
let do_query = function (schema) {
|
|
return new Promise((resolve, reject) => {
|
|
let text_query = JSON.stringify({ query: schema });
|
|
|
|
let request = HTTPS.request(
|
|
"https://api.github.com/graphql",
|
|
{
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json',
|
|
'Authorization': `bearer ${auth_token}`,
|
|
'User-Agent': 'Node.JS'
|
|
},
|
|
}, (res) => {
|
|
let data = "";
|
|
res.setEncoding('utf8');
|
|
res.on('data', (chunk) => {
|
|
data += chunk;
|
|
});
|
|
res.on('error', () => {
|
|
reject();
|
|
});
|
|
res.on('end', () => {
|
|
res.data = JSON.parse(data);
|
|
resolve(res);
|
|
});
|
|
});
|
|
request.write(text_query);
|
|
request.end();
|
|
})
|
|
}
|
|
|
|
return (async () => {
|
|
let users = new Map();
|
|
let total = 0;
|
|
|
|
// Find the total amount.
|
|
{
|
|
let query = build_query();
|
|
let response = await do_query(query);
|
|
let data = response.data.data;
|
|
total = data.viewer.sponsors.totalCount;
|
|
}
|
|
|
|
// Index by page, in 100 user increments.
|
|
let cursor = null;
|
|
for (let idx = 0, edx = total; idx < edx; idx += 100) {
|
|
let query = build_query(cursor);
|
|
let response = await do_query(query);
|
|
let data = response.data.data;
|
|
|
|
// Insert data info Map.
|
|
for (let entry of data.viewer.sponsors.nodes) {
|
|
let name = entry.login;
|
|
if (typeof (entry.name) === "string") {
|
|
name = entry.name;
|
|
}
|
|
|
|
users.set(name, `https://github.com${entry.resourcePath}`);
|
|
}
|
|
|
|
// Update cursor for further queries.
|
|
cursor = data.viewer.sponsors.pageInfo.endCursor;
|
|
}
|
|
|
|
return users;
|
|
})();
|
|
}
|
|
|
|
(async () => {
|
|
let json = {};
|
|
let markdown = `# StreamFX Contributors & Supporters
|
|
|
|
## Contributors
|
|
|
|
`;
|
|
|
|
// Contributors
|
|
{// - Git
|
|
markdown += `### Code, Media
|
|
Thanks go to the following people, who have either wrangled with code or wrangled with image editors while saving often in the hopes of not losing any changes:
|
|
|
|
`;
|
|
json.contributor = {};
|
|
let info = await query_git();
|
|
let extra = JSON.parse(await FS.readFile(PATH.join(__dirname, "patch-contributors-git.json")));
|
|
for (let key in extra) {
|
|
info.set(key, extra[key]);
|
|
}
|
|
for (let key of Array.from(info.keys()).sort()) {
|
|
let value = info.get(key);
|
|
json.contributor[key] = value;
|
|
markdown += `* [${key}](${value})\n`;
|
|
}
|
|
markdown += "\n";
|
|
}
|
|
|
|
{// - Crowdin
|
|
markdown += `### Translators
|
|
[StreamFX relies on crowd-sourced translations to be available in your language.](https://github.com/Xaymar/obs-StreamFX/issues/36) Much thanks go out to all volunteer translators who have taken some time to submit translations on Crowdin.
|
|
|
|
`;
|
|
json.translator = {};
|
|
let info = await query_crowdin(process.env.CROWDIN_PROJECTID, process.env.CROWDIN_TOKEN);
|
|
let extra = JSON.parse(await FS.readFile(PATH.join(__dirname, "patch-contributors-git.json")));
|
|
for (let key in extra) {
|
|
info.set(key, extra[key]);
|
|
}
|
|
for (let key of Array.from(info.keys()).sort()) {
|
|
let value = info.get(key);
|
|
json.translator[key] = value;
|
|
markdown += `* [${key}](${value})\n`;
|
|
}
|
|
markdown += "\n";
|
|
}
|
|
|
|
// Supporters
|
|
markdown += `## Supporters
|
|
The StreamFX project relies on generous donations from you through [Patreon](https://patreon.com/xaymar), [GitHub](https://github.com/sponsors/xaymar) or [PayPal](https://paypal.me/xaymar). Huge thanks go out to the following people for supporting StreamFX:
|
|
|
|
`;
|
|
json.supporter = {}
|
|
{// - GitHub
|
|
markdown += `### GitHub Sponsors
|
|
`;
|
|
json.supporter.github = {};
|
|
let info = await query_github_sponsors(process.env.GITHUB_TOKEN);
|
|
let extra = JSON.parse(await FS.readFile(PATH.join(__dirname, "patch-supporters-github.json")));
|
|
for (let key in extra) {
|
|
info.set(key, extra[key]);
|
|
}
|
|
for (let key of Array.from(info.keys()).sort()) {
|
|
let value = info.get(key);
|
|
json.supporter.github[key] = value;
|
|
markdown += `* [${key}](${value})\n`;
|
|
}
|
|
markdown += "\n";
|
|
}
|
|
|
|
{// - Patreon
|
|
// TODO: How do we OAuth without OAuth?!
|
|
markdown += `### Patreon Patrons
|
|
`;
|
|
json.supporter.patreon = {};
|
|
let info = new Map();
|
|
let extra = JSON.parse(await FS.readFile(PATH.join(__dirname, "patch-supporters-patreon.json")));
|
|
for (let key in extra) {
|
|
info.set(key, extra[key]);
|
|
}
|
|
for (let key of Array.from(info.keys()).sort()) {
|
|
let value = info.get(key);
|
|
json.supporter.patreon[key] = value;
|
|
markdown += `* [${key}](${value})\n`;
|
|
}
|
|
markdown += "\n";
|
|
}
|
|
|
|
// Write Markdown file
|
|
FS.writeFile(process.argv[2],
|
|
markdown,
|
|
{
|
|
encoding: 'utf8'
|
|
}
|
|
)
|
|
|
|
// Write JSON file
|
|
FS.writeFile(process.argv[3],
|
|
JSON.stringify(json, undefined, '\t'),
|
|
{
|
|
encoding: 'utf8'
|
|
}
|
|
)
|
|
})();
|