obs-StreamFX/tools/generate-contributors.js
Michael Fabian 'Xaymar' Dirks 5a3954ae0e project: Fix License, License headers and Copyright information
Fixes several files incorrectly stated a different license from the actual project, as well as the copyright headers included in all files. This change has no effect on the licensing terms, it should clear up a bit of confusion by contributors. Plus the files get a bit smaller, and we have less duplicated information across the entire project.

Overall the project is GPLv2 if not built with Qt, and GPLv3 if it is built with Qt. There are no parts licensed under a different license, all have been adapted from other compatible licenses into GPLv2 or GPLv3.
2023-04-05 18:59:08 +02:00

333 lines
8.2 KiB
JavaScript

// AUTOGENERATED COPYRIGHT HEADER START
// Copyright (C) 2021-2023 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
// AUTOGENERATED COPYRIGHT HEADER END
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((a, b) => a.localeCompare(b, undefined, {numeric: true, sensitivity: 'base'}))) {
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((a, b) => a.localeCompare(b, undefined, {numeric: true, sensitivity: 'base'}))) {
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((a, b) => a.localeCompare(b, undefined, {numeric: true, sensitivity: 'base'}))) {
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((a, b) => a.localeCompare(b, undefined, {numeric: true, sensitivity: 'base'}))) {
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'
}
)
})();