add and run prettier

This commit is contained in:
Lee
2023-10-17 23:38:18 +01:00
parent 47a23f0484
commit f6f56aa09c
136 changed files with 8231 additions and 4493 deletions

View File

@ -1,25 +1,75 @@
import {default as createQueue, PRIORITY} from '../http-queue';
import {substituteVars} from "../../../utils/format";
import { default as createQueue, PRIORITY } from "../http-queue";
import { substituteVars } from "../../../utils/format";
const ACCSABER_API_URL = 'https://api.accsaber.com';
const CATEGORIES_URL = ACCSABER_API_URL + '/categories';
const RANKING_URL = ACCSABER_API_URL + '/categories/${category}/standings';
const PLAYER_SCORES_URL = ACCSABER_API_URL + '/players/${playerId}/scores';
const PLAYER_RANK_HISTORY = ACCSABER_API_URL + '/players/${playerId}/recent-rank-history'
const LEADERBOARD_URL = ACCSABER_API_URL + '/map-leaderboards/${leaderboardId}';
const LEADERBOARD_INFO_URL = ACCSABER_API_URL + '/ranked-maps/${leaderboardId}';
const ACCSABER_API_URL = "https://api.accsaber.com";
const CATEGORIES_URL = ACCSABER_API_URL + "/categories";
const RANKING_URL = ACCSABER_API_URL + "/categories/${category}/standings";
const PLAYER_SCORES_URL = ACCSABER_API_URL + "/players/${playerId}/scores";
const PLAYER_RANK_HISTORY =
ACCSABER_API_URL + "/players/${playerId}/recent-rank-history";
const LEADERBOARD_URL = ACCSABER_API_URL + "/map-leaderboards/${leaderboardId}";
const LEADERBOARD_INFO_URL = ACCSABER_API_URL + "/ranked-maps/${leaderboardId}";
export default (options = {}) => {
const queue = createQueue(options);
const {fetchJson, fetchHtml, ...queueToReturn} = queue;
const { fetchJson, fetchHtml, ...queueToReturn } = queue;
const categories = async (priority = PRIORITY.FG_LOW, options = {}) => fetchJson(CATEGORIES_URL, options, priority)
const ranking = async (category = 'overall', page = 1, priority = PRIORITY.FG_LOW, options = {}) => fetchJson(substituteVars(RANKING_URL, {category, page}), options, priority)
const scores = async (playerId, page = 1, priority = PRIORITY.FG_LOW, options = {}) => fetchJson(substituteVars(PLAYER_SCORES_URL, {playerId, page}), options, priority)
const playerRankHistory = async (playerId, priority = PRIORITY.FG_LOW, options = {}) => fetchJson(substituteVars(PLAYER_RANK_HISTORY, {playerId}), options, priority)
const leaderboard = async (leaderboardId, page = 1, priority = PRIORITY.FG_LOW, options = {}) => fetchJson(substituteVars(LEADERBOARD_URL, {leaderboardId, page}), options, priority)
const leaderboardInfo = async (leaderboardId, priority = PRIORITY.FG_LOW, options = {}) => fetchJson(substituteVars(LEADERBOARD_INFO_URL, {leaderboardId}), options, priority)
const categories = async (priority = PRIORITY.FG_LOW, options = {}) =>
fetchJson(CATEGORIES_URL, options, priority);
const ranking = async (
category = "overall",
page = 1,
priority = PRIORITY.FG_LOW,
options = {},
) =>
fetchJson(
substituteVars(RANKING_URL, { category, page }),
options,
priority,
);
const scores = async (
playerId,
page = 1,
priority = PRIORITY.FG_LOW,
options = {},
) =>
fetchJson(
substituteVars(PLAYER_SCORES_URL, { playerId, page }),
options,
priority,
);
const playerRankHistory = async (
playerId,
priority = PRIORITY.FG_LOW,
options = {},
) =>
fetchJson(
substituteVars(PLAYER_RANK_HISTORY, { playerId }),
options,
priority,
);
const leaderboard = async (
leaderboardId,
page = 1,
priority = PRIORITY.FG_LOW,
options = {},
) =>
fetchJson(
substituteVars(LEADERBOARD_URL, { leaderboardId, page }),
options,
priority,
);
const leaderboardInfo = async (
leaderboardId,
priority = PRIORITY.FG_LOW,
options = {},
) =>
fetchJson(
substituteVars(LEADERBOARD_INFO_URL, { leaderboardId }),
options,
priority,
);
return {
categories,
@ -29,5 +79,5 @@ export default (options = {}) => {
leaderboard,
leaderboardInfo,
...queueToReturn,
}
}
};
};

View File

@ -1,21 +1,23 @@
import {default as createQueue, PRIORITY} from '../http-queue';
import {substituteVars} from "../../../utils/format";
import { default as createQueue, PRIORITY } from "../http-queue";
import { substituteVars } from "../../../utils/format";
const BEATMAPS_API_URL = 'https://api.beatsaver.com/';
const SONG_BY_HASH_URL = BEATMAPS_API_URL + '/maps/hash/${hash}';
const SONG_BY_KEY_URL = BEATMAPS_API_URL + '/maps/id/${key}'
const BEATMAPS_API_URL = "https://api.beatsaver.com/";
const SONG_BY_HASH_URL = BEATMAPS_API_URL + "/maps/hash/${hash}";
const SONG_BY_KEY_URL = BEATMAPS_API_URL + "/maps/id/${key}";
export default (options = {}) => {
const queue = createQueue(options);
const {fetchJson, fetchHtml, ...queueToReturn} = queue;
const { fetchJson, fetchHtml, ...queueToReturn } = queue;
const byHash = async (hash, priority = PRIORITY.FG_LOW, options = {}) => fetchJson(substituteVars(SONG_BY_HASH_URL, {hash}), options, priority)
const byKey = async (key, priority = PRIORITY.FG_LOW, options = {}) => fetchJson(substituteVars(SONG_BY_KEY_URL, {key}), options, priority)
const byHash = async (hash, priority = PRIORITY.FG_LOW, options = {}) =>
fetchJson(substituteVars(SONG_BY_HASH_URL, { hash }), options, priority);
const byKey = async (key, priority = PRIORITY.FG_LOW, options = {}) =>
fetchJson(substituteVars(SONG_BY_KEY_URL, { key }), options, priority);
return {
byHash,
byKey,
...queueToReturn,
}
}
};
};

View File

@ -1,9 +1,17 @@
import {default as createQueue, PRIORITY as QUEUE_PRIORITY} from '../../utils/queue';
import {SsrError, SsrTimeoutError} from '../../others/errors'
import {SsrHttpRateLimitError, SsrHttpResponseError, SsrNetworkError, SsrNetworkTimeoutError} from '../errors'
import {fetchHtml, fetchJson} from '../fetch';
import makePendingPromisePool from '../../utils/pending-promises'
import {AbortError} from '../../utils/promise'
import {
default as createQueue,
PRIORITY as QUEUE_PRIORITY,
} from "../../utils/queue";
import { SsrError, SsrTimeoutError } from "../../others/errors";
import {
SsrHttpRateLimitError,
SsrHttpResponseError,
SsrNetworkError,
SsrNetworkTimeoutError,
} from "../errors";
import { fetchHtml, fetchJson } from "../fetch";
import makePendingPromisePool from "../../utils/pending-promises";
import { AbortError } from "../../utils/promise";
const DEFAULT_RETRIES = 2;
@ -13,65 +21,91 @@ export const PRIORITY = {
BG_HIGH: QUEUE_PRIORITY.NORMAL,
BG_NORMAL: QUEUE_PRIORITY.LOW,
BG_LOW: QUEUE_PRIORITY.LOWEST,
}
};
const resolvePromiseOrWaitForPending = makePendingPromisePool();
export default (options = {}) => {
const {retries, rateLimitTick, ...queueOptions} = {retries: DEFAULT_RETRIES, rateLimitTick: 500, ...options};
const { retries, rateLimitTick, ...queueOptions } = {
retries: DEFAULT_RETRIES,
rateLimitTick: 500,
...options,
};
const queue = createQueue(queueOptions);
const {add, emitter, ...queueToReturn} = queue;
const { add, emitter, ...queueToReturn } = queue;
let lastRateLimitError = null;
let rateLimitTimerId = null;
let currentRateLimit = {waiting: 0, remaining: null, limit: null, resetAt: null};
let currentRateLimit = {
waiting: 0,
remaining: null,
limit: null,
resetAt: null,
};
const rateLimitTicker = () => {
const expiresInMs = lastRateLimitError && lastRateLimitError.resetAt ? lastRateLimitError.resetAt - new Date() + 1000 : 0;
const expiresInMs =
lastRateLimitError && lastRateLimitError.resetAt
? lastRateLimitError.resetAt - new Date() + 1000
: 0;
if (expiresInMs <= 0) {
emitter.emit('waiting', {waiting: 0, remaining: null, limit: null, resetAt: null});
emitter.emit("waiting", {
waiting: 0,
remaining: null,
limit: null,
resetAt: null,
});
if (rateLimitTimerId) clearTimeout(rateLimitTimerId);
return;
}
const {remaining, limit, resetAt} = lastRateLimitError;
emitter.emit('waiting', {waiting: expiresInMs, remaining, limit, resetAt});
const { remaining, limit, resetAt } = lastRateLimitError;
emitter.emit("waiting", {
waiting: expiresInMs,
remaining,
limit,
resetAt,
});
if (rateLimitTimerId) clearTimeout(rateLimitTimerId);
rateLimitTimerId = setTimeout(rateLimitTicker, rateLimitTick);
}
};
const retriedFetch = async (fetchFunc, url, options, priority = PRIORITY.FG_LOW) => {
const retriedFetch = async (
fetchFunc,
url,
options,
priority = PRIORITY.FG_LOW,
) => {
for (let i = 0; i <= retries; i++) {
try {
return await add(async () => {
if (lastRateLimitError) {
await lastRateLimitError.waitBeforeRetry();
if (lastRateLimitError) {
await lastRateLimitError.waitBeforeRetry();
lastRateLimitError = null;
}
lastRateLimitError = null;
}
return fetchFunc(url, options)
.then(response => {
currentRateLimit = {...response.rateLimit, waiting: 0};
return fetchFunc(url, options)
.then((response) => {
currentRateLimit = { ...response.rateLimit, waiting: 0 };
return response;
})
.catch(err => {
if (err instanceof SsrTimeoutError) throw new SsrNetworkTimeoutError(err.timeout);
return response;
})
.catch((err) => {
if (err instanceof SsrTimeoutError)
throw new SsrNetworkTimeoutError(err.timeout);
throw err;
})
},
priority,
)
throw err;
});
}, priority);
} catch (err) {
if (err instanceof SsrHttpResponseError) {
const {remaining, limit, resetAt} = err;
currentRateLimit = {waiting: 0, remaining, limit, resetAt};
const { remaining, limit, resetAt } = err;
currentRateLimit = { waiting: 0, remaining, limit, resetAt };
}
if (err instanceof SsrNetworkError) {
@ -79,7 +113,13 @@ export default (options = {}) => {
if (!shouldRetry || i === retries) throw err;
if (err instanceof SsrHttpRateLimitError) {
if (err.remaining <= 0 && err.resetAt && (!lastRateLimitError || !lastRateLimitError.resetAt || lastRateLimitError.resetAt < err.resetAt)) {
if (
err.remaining <= 0 &&
err.resetAt &&
(!lastRateLimitError ||
!lastRateLimitError.resetAt ||
lastRateLimitError.resetAt < err.resetAt)
) {
lastRateLimitError = err;
rateLimitTicker();
@ -95,11 +135,17 @@ export default (options = {}) => {
}
}
throw new SsrError('Unknown error');
}
throw new SsrError("Unknown error");
};
const queuedFetchJson = async (url, options, priority = PRIORITY.FG_LOW) => resolvePromiseOrWaitForPending(url, () => retriedFetch(fetchJson, url, options, priority));
const queuedFetchHtml = async (url, options, priority = PRIORITY.FG_LOW) => resolvePromiseOrWaitForPending(url, () => retriedFetch(fetchHtml, url, options, priority));
const queuedFetchJson = async (url, options, priority = PRIORITY.FG_LOW) =>
resolvePromiseOrWaitForPending(url, () =>
retriedFetch(fetchJson, url, options, priority),
);
const queuedFetchHtml = async (url, options, priority = PRIORITY.FG_LOW) =>
resolvePromiseOrWaitForPending(url, () =>
retriedFetch(fetchHtml, url, options, priority),
);
const getRateLimit = () => currentRateLimit;
@ -108,5 +154,5 @@ export default (options = {}) => {
fetchHtml: queuedFetchHtml,
getRateLimit,
...queueToReturn,
}
}
};
};

View File

@ -1,55 +1,99 @@
import {writable} from 'svelte/store'
import {PRIORITY} from './http-queue'
import createScoreSaberApiQueue from './scoresaber/api-queue'
import createScoreSaberPageQueue from './scoresaber/page-queue'
import createBeatMapsApiQueue from './beatmaps/api-queue'
import createBeatSaviorApiQueue from './beatsavior/api-queue'
import createTwitchApiQueue from './twitch/api-queue'
import createAccSaberApiQueue from './accsaber/api-queue'
import { writable } from "svelte/store";
import { PRIORITY } from "./http-queue";
import createScoreSaberApiQueue from "./scoresaber/api-queue";
import createScoreSaberPageQueue from "./scoresaber/page-queue";
import createBeatMapsApiQueue from "./beatmaps/api-queue";
import createBeatSaviorApiQueue from "./beatsavior/api-queue";
import createTwitchApiQueue from "./twitch/api-queue";
import createAccSaberApiQueue from "./accsaber/api-queue";
export const getResponseBody = response => response ? response.body : null;
export const isResponseCached = response => !!(response && response.cached)
export const updateResponseBody = (response, body) => response ? {...response, body} : null;
export const getResponseBody = (response) => (response ? response.body : null);
export const isResponseCached = (response) => !!(response && response.cached);
export const updateResponseBody = (response, body) =>
response ? { ...response, body } : null;
const initQueue = queue => {
const initQueue = (queue) => {
let queueState = {
size: 0,
pending: 0,
rateLimit: {waiting: 0, remaining: null, limit: null, resetAt: null},
progress: {num: 0, count: 0, progress: 1},
rateLimit: { waiting: 0, remaining: null, limit: null, resetAt: null },
progress: { num: 0, count: 0, progress: 1 },
};
const {subscribe, set} = writable(queueState);
const { subscribe, set } = writable(queueState);
queue.on('change', ({size, pending}) => {
const {rateLimit: {waiting}} = queueState;
const {remaining, limit, resetAt} = queue.getRateLimit();
queueState = {...queueState, size, pending, rateLimit: {waiting, remaining, limit, resetAt}};
queue.on("change", ({ size, pending }) => {
const {
rateLimit: { waiting },
} = queueState;
const { remaining, limit, resetAt } = queue.getRateLimit();
queueState = {
...queueState,
size,
pending,
rateLimit: { waiting, remaining, limit, resetAt },
};
set(queueState);
});
queue.on('progress', ({progress, num, count}) => {
const {rateLimit: {waiting}} = queueState;
const {remaining, limit, resetAt} = queue.getRateLimit();
queueState = {...queueState, progress: {num, count, progress}, rateLimit: {waiting, remaining, limit, resetAt}}
queue.on("progress", ({ progress, num, count }) => {
const {
rateLimit: { waiting },
} = queueState;
const { remaining, limit, resetAt } = queue.getRateLimit();
queueState = {
...queueState,
progress: { num, count, progress },
rateLimit: { waiting, remaining, limit, resetAt },
};
set(queueState);
});
queue.on('waiting', ({waiting, remaining, limit, resetAt}) => {
queueState = {...queueState, rateLimit: {waiting, remaining, limit, resetAt}}
queue.on("waiting", ({ waiting, remaining, limit, resetAt }) => {
queueState = {
...queueState,
rateLimit: { waiting, remaining, limit, resetAt },
};
set(queueState);
})
});
return {
subscribe,
...queue,
}
}
};
};
export default {
SCORESABER_API: initQueue(createScoreSaberApiQueue({concurrency: 3, timeout: 95000})),
SCORESABER_PAGE: initQueue(createScoreSaberPageQueue({concurrency: 3, timeout: 30000})),
BEATMAPS: initQueue(createBeatMapsApiQueue({concurrency: 1, timeout: 10000, intervalCap: 10, interval: 1000})),
BEATSAVIOR: initQueue(createBeatSaviorApiQueue({concurrency: 1, timeout: 10000, intervalCap: 60, interval: 60000})),
TWITCH: initQueue(createTwitchApiQueue({concurrency: 8, timeout: 8000, intervalCap: 800, interval: 60000})),
ACCSABER: initQueue(createAccSaberApiQueue({concurrency: 2, timeout: 10000})),
SCORESABER_API: initQueue(
createScoreSaberApiQueue({ concurrency: 3, timeout: 95000 }),
),
SCORESABER_PAGE: initQueue(
createScoreSaberPageQueue({ concurrency: 3, timeout: 30000 }),
),
BEATMAPS: initQueue(
createBeatMapsApiQueue({
concurrency: 1,
timeout: 10000,
intervalCap: 10,
interval: 1000,
}),
),
BEATSAVIOR: initQueue(
createBeatSaviorApiQueue({
concurrency: 1,
timeout: 10000,
intervalCap: 60,
interval: 60000,
}),
),
TWITCH: initQueue(
createTwitchApiQueue({
concurrency: 8,
timeout: 8000,
intervalCap: 800,
interval: 60000,
}),
),
ACCSABER: initQueue(
createAccSaberApiQueue({ concurrency: 2, timeout: 10000 }),
),
PRIORITY,
}
};

View File

@ -1,35 +1,79 @@
import {default as createQueue, PRIORITY} from '../http-queue';
import {substituteVars} from '../../../utils/format'
import {PLAYER_SCORES_PER_PAGE, PLAYERS_PER_PAGE} from '../../../utils/scoresaber/consts'
import { default as createQueue, PRIORITY } from "../http-queue";
import { substituteVars } from "../../../utils/format";
import {
PLAYER_SCORES_PER_PAGE,
PLAYERS_PER_PAGE,
} from "../../../utils/scoresaber/consts";
export const SS_API_HOST = 'https://new.scoresaber.com';
export const SS_API_HOST = "https://new.scoresaber.com";
export const SS_API_URL = `${SS_API_HOST}/api`;
export const SS_API_PLAYER_INFO_URL = SS_API_URL + '/player/${playerId}/full';
export const SS_API_RECENT_SCORES_URL = SS_API_URL + '/player/${playerId}/scores/recent/${page}';
export const SS_API_TOP_SCORES_URL = SS_API_URL + '/player/${playerId}/scores/top/${page}';
export const SS_API_FIND_PLAYER_URL = SS_API_URL + '/players/by-name/${query}'
export const SS_API_RANKING_GLOBAL_URL = SS_API_URL + '/players/${page}'
export const SS_API_RANKING_GLOBAL_PAGES_URL = SS_API_URL + '/players/pages'
export const SS_API_PLAYER_INFO_URL = SS_API_URL + "/player/${playerId}/full";
export const SS_API_RECENT_SCORES_URL =
SS_API_URL + "/player/${playerId}/scores/recent/${page}";
export const SS_API_TOP_SCORES_URL =
SS_API_URL + "/player/${playerId}/scores/top/${page}";
export const SS_API_FIND_PLAYER_URL = SS_API_URL + "/players/by-name/${query}";
export const SS_API_RANKING_GLOBAL_URL = SS_API_URL + "/players/${page}";
export const SS_API_RANKING_GLOBAL_PAGES_URL = SS_API_URL + "/players/pages";
export default (options = {}) => {
const queue = createQueue(options);
const {fetchJson, fetchHtml, ...queueToReturn} = queue;
const { fetchJson, fetchHtml, ...queueToReturn } = queue;
const fetchScores = async (baseUrl, playerId, page = 1, priority = PRIORITY.FG_LOW, options = {}) => fetchJson(substituteVars(baseUrl, {playerId, page}), options, priority);
const fetchScores = async (
baseUrl,
playerId,
page = 1,
priority = PRIORITY.FG_LOW,
options = {},
) =>
fetchJson(substituteVars(baseUrl, { playerId, page }), options, priority);
const player = async (playerId, priority = PRIORITY.FG_LOW, options = {}) => fetchJson(substituteVars(SS_API_PLAYER_INFO_URL, {playerId}), options, priority);
const player = async (playerId, priority = PRIORITY.FG_LOW, options = {}) =>
fetchJson(
substituteVars(SS_API_PLAYER_INFO_URL, { playerId }),
options,
priority,
);
const recentScores = async (playerId, page = 1, priority = PRIORITY.FG_LOW, options = {}) => fetchScores(SS_API_RECENT_SCORES_URL, playerId, page, priority, options);
const recentScores = async (
playerId,
page = 1,
priority = PRIORITY.FG_LOW,
options = {},
) => fetchScores(SS_API_RECENT_SCORES_URL, playerId, page, priority, options);
const topScores = async (playerId, page = 1, priority = PRIORITY.FG_LOW, options = {}) => fetchScores(SS_API_TOP_SCORES_URL, playerId, page, priority, options);
const topScores = async (
playerId,
page = 1,
priority = PRIORITY.FG_LOW,
options = {},
) => fetchScores(SS_API_TOP_SCORES_URL, playerId, page, priority, options);
const findPlayer = async (query, priority = PRIORITY.FG_LOW, options = {}) => fetchJson(substituteVars(SS_API_FIND_PLAYER_URL, {query: encodeURIComponent(query)}), options, priority);
const findPlayer = async (query, priority = PRIORITY.FG_LOW, options = {}) =>
fetchJson(
substituteVars(SS_API_FIND_PLAYER_URL, {
query: encodeURIComponent(query),
}),
options,
priority,
);
const rankingGlobal = async (page = 1, priority = PRIORITY.FG_LOW, options = {}) => fetchJson(substituteVars(SS_API_RANKING_GLOBAL_URL, {page}), options, priority);
const rankingGlobal = async (
page = 1,
priority = PRIORITY.FG_LOW,
options = {},
) =>
fetchJson(
substituteVars(SS_API_RANKING_GLOBAL_URL, { page }),
options,
priority,
);
const rankingGlobalPages = async (priority = PRIORITY.FG_LOW, options = {}) => fetchJson(SS_API_RANKING_GLOBAL_PAGES_URL, options, priority);
const rankingGlobalPages = async (priority = PRIORITY.FG_LOW, options = {}) =>
fetchJson(SS_API_RANKING_GLOBAL_PAGES_URL, options, priority);
return {
player,
@ -42,5 +86,5 @@ export default (options = {}) => {
PLAYER_SCORES_PER_PAGE,
PLAYERS_PER_PAGE,
...queueToReturn,
}
}
};
};

View File

@ -24,7 +24,7 @@ export const parseSsInt = (text) => {
export const parseSsFloat = (text) =>
text
? parseFloat(
getFirstRegexpMatch(/([0-9,.]+)\s*$/, text.replace(/[^\d.]/g, ""))
getFirstRegexpMatch(/([0-9,.]+)\s*$/, text.replace(/[^\d.]/g, "")),
)
: null;
@ -78,32 +78,32 @@ export default (options = {}) => {
const rankeds = async (
page = 1,
priority = PRIORITY.BG_NORMAL,
options = {}
options = {},
) =>
fetchJson(substituteVars(RANKEDS_URL, { page }), options, priority).then(
(r) => {
r.body = processRankeds(r.body);
return r;
}
},
);
const processPlayerProfile = (playerId, doc) => {
cfDecryptEmail(doc);
let avatar = getImgUrl(
opt(doc.querySelector(".column.avatar img"), "src", null)
opt(doc.querySelector(".column.avatar img"), "src", null),
);
let playerName = opt(
doc.querySelector(".content .column:not(.avatar) .title a"),
"innerText"
"innerText",
);
playerName = playerName ? playerName.trim() : null;
let country = getFirstRegexpMatch(
/^.*?\/flags\/([^.]+)\..*$/,
opt(doc.querySelector(".content .column .title img"), "src")
opt(doc.querySelector(".content .column .title img"), "src"),
);
country = country ? country.toUpperCase() : null;
@ -111,8 +111,8 @@ export default (options = {}) => {
opt(
doc.querySelector(".pagination .pagination-list li a.is-current"),
"innerText",
null
)
null,
),
);
pageNum = !isNaN(pageNum) ? pageNum : null;
@ -120,8 +120,8 @@ export default (options = {}) => {
opt(
doc.querySelector(".pagination .pagination-list li:last-of-type"),
"innerText",
null
)
null,
),
);
pageQty = !isNaN(pageQty) ? pageQty : null;
@ -130,31 +130,31 @@ export default (options = {}) => {
/^\s*<strong>(?:[^:]+)\s*:?\s*<\/strong>\s*(.*)$/,
opt(
doc.querySelector(
".columns .column:not(.is-narrow) ul li:nth-of-type(3)"
".columns .column:not(.is-narrow) ul li:nth-of-type(3)",
),
"innerHTML"
)
)
"innerHTML",
),
),
);
totalItems = !isNaN(totalItems) ? totalItems : 0;
let playerRank = parseSsInt(
opt(
doc.querySelector(
".content .column ul li:first-of-type a:first-of-type"
".content .column ul li:first-of-type a:first-of-type",
),
"innerText"
)
"innerText",
),
);
playerRank = !isNaN(playerRank) ? playerRank : null;
let countryRank = parseSsInt(
opt(
doc.querySelector(
'.content .column ul li:first-of-type a[href^="/global?country="]'
'.content .column ul li:first-of-type a[href^="/global?country="]',
),
"innerText"
)
"innerText",
),
);
countryRank = !isNaN(countryRank) ? countryRank : null;
@ -170,7 +170,7 @@ export default (options = {}) => {
[...doc.querySelectorAll(".content .column ul li")]
.map((li) => {
const matches = li.innerHTML.match(
/^\s*<strong>([^:]+)\s*:?\s*<\/strong>\s*(.*)$/
/^\s*<strong>([^:]+)\s*:?\s*<\/strong>\s*(.*)$/,
);
if (!matches) return null;
@ -219,7 +219,7 @@ export default (options = {}) => {
const item = mapping.find((m) => m.key === matches[1]);
return item ? { ...item, value } : { label: matches[1], value };
})
.filter((s) => s)
.filter((s) => s),
)
.reduce(
(cum, item) => {
@ -255,7 +255,7 @@ export default (options = {}) => {
return cum;
},
{ inactiveAccount: false, bannedAccount: false }
{ inactiveAccount: false, bannedAccount: false },
);
const scores = [...doc.querySelectorAll("table.ranking tbody tr")].map(
@ -274,7 +274,7 @@ export default (options = {}) => {
if (song) {
const leaderboardId = parseInt(
getFirstRegexpMatch(/leaderboard\/(\d+)/, song.href),
10
10,
);
ret.leaderboardId = leaderboardId ? leaderboardId : null;
} else {
@ -293,7 +293,7 @@ export default (options = {}) => {
.replace(/&amp;/g, "&")
.replace(
/<span class="__cf_email__" data-cfemail="[^"]+">\[email&nbsp;protected]<\/span>/g,
""
"",
)
.match(/^(.*?)\s*<span[^>]+>(.*?)<\/span>/)
: null;
@ -328,7 +328,7 @@ export default (options = {}) => {
ret.timeSet = songDate ? dateFromString(songDate.title) : null;
const pp = parseSsFloat(
opt(tr.querySelector("th.score .scoreTop.ppValue"), "innerText")
opt(tr.querySelector("th.score .scoreTop.ppValue"), "innerText"),
);
ret.pp = !isNaN(pp) ? pp : null;
@ -337,9 +337,9 @@ export default (options = {}) => {
/^\(([0-9.]+)pp\)$/,
opt(
tr.querySelector("th.score .scoreTop.ppWeightedValue"),
"innerText"
)
)
"innerText",
),
),
);
ret.ppWeighted = !isNaN(ppWeighted) ? ppWeighted : null;
@ -380,7 +380,7 @@ export default (options = {}) => {
}
return ret;
}
},
);
const recentPlay =
scores && scores.length && scores[0].timeSet ? scores[0].timeSet : null;
@ -394,18 +394,18 @@ export default (options = {}) => {
externalProfileUrl: opt(
doc.querySelector(".content .column:not(.avatar) .title a"),
"href",
null
null,
),
history: getFirstRegexpMatch(
/data:\s*\[([0-9,]+)\]/,
doc.body.innerHTML
doc.body.innerHTML,
),
country,
badges: [...doc.querySelectorAll(".column.avatar center img")].map(
(img) => ({
image: getImgUrl(img.src),
description: img.title,
})
}),
),
rank: stats.rank ? stats.rank : null,
countryRank: stats.countryRank ? stats.countryRank : null,
@ -435,7 +435,7 @@ export default (options = {}) => {
fetchHtml(
substituteVars(PLAYER_PROFILE_URL, { playerId }),
options,
priority
priority,
).then((r) => {
r.body = processPlayerProfile(playerId, r.body);
@ -451,17 +451,17 @@ export default (options = {}) => {
const id = getFirstRegexpMatch(/\/(\d+)$/, a.href);
const avatar = getImgUrl(
opt(tr.querySelector("td.picture img"), "src", null)
opt(tr.querySelector("td.picture img"), "src", null),
);
let country = getFirstRegexpMatch(
/^.*?\/flags\/([^.]+)\..*$/,
opt(tr.querySelector("td.player img"), "src", null)
opt(tr.querySelector("td.player img"), "src", null),
);
country = country ? country.toUpperCase() : null;
let difference = parseSsInt(
opt(tr.querySelector("td.diff"), "innerText", null)
opt(tr.querySelector("td.diff"), "innerText", null),
);
difference = !isNaN(difference) ? difference : null;
@ -469,15 +469,15 @@ export default (options = {}) => {
playerName = playerName || playerName === "" ? playerName.trim() : null;
let pp = parseSsFloat(
opt(tr.querySelector("td.pp .scoreTop.ppValue"), "innerText")
opt(tr.querySelector("td.pp .scoreTop.ppValue"), "innerText"),
);
pp = !isNaN(pp) ? pp : null;
let rank = parseSsInt(
getFirstRegexpMatch(
/^\s*#(\d+)\s*$/,
opt(tr.querySelector("td.rank"), "innerText", null)
)
opt(tr.querySelector("td.rank"), "innerText", null),
),
);
rank = !isNaN(rank) ? rank : null;
@ -491,7 +491,7 @@ export default (options = {}) => {
pp,
rank,
};
}
},
);
return { players: data };
@ -501,12 +501,12 @@ export default (options = {}) => {
country,
page = 1,
priority = PRIORITY.FG_LOW,
options = {}
options = {},
) =>
fetchHtml(
substituteVars(COUNTRY_RANKING_URL, { country, page }),
options,
priority
priority,
).then((r) => {
r.body = processCountryRanking(country, r.body);
@ -529,11 +529,11 @@ export default (options = {}) => {
};
ret.player.playerInfo.avatar = getImgUrl(
opt(tr.querySelector(".picture img"), "src", null)
opt(tr.querySelector(".picture img"), "src", null),
);
ret.score.rank = parseSsInt(
opt(tr.querySelector("td.rank"), "innerText")
opt(tr.querySelector("td.rank"), "innerText"),
);
if (isNaN(ret.score.rank)) ret.score.rank = null;
@ -541,7 +541,7 @@ export default (options = {}) => {
if (player) {
let country = getFirstRegexpMatch(
/^.*?\/flags\/([^.]+)\..*$/,
opt(player.querySelector("img"), "src", "")
opt(player.querySelector("img"), "src", ""),
);
country = country ? country.toUpperCase() : null;
if (country) {
@ -551,14 +551,14 @@ export default (options = {}) => {
ret.player.name = opt(
player.querySelector("span.songTop.pp"),
"innerText"
"innerText",
);
ret.player.name = ret.player.name
? ret.player.name.trim().replace("&#039;", "'")
: null;
ret.player.playerId = getFirstRegexpMatch(
/\/u\/(\d+)((\?|&|#).*)?$/,
opt(player, "href", "")
opt(player, "href", ""),
);
ret.player.playerId = ret.player.playerId
? ret.player.playerId.trim()
@ -574,7 +574,7 @@ export default (options = {}) => {
ret.score.timeSetString = opt(
tr.querySelector("td.timeset"),
"innerText",
null
null,
);
if (ret.score.timeSetString)
ret.score.timeSetString = ret.score.timeSetString.trim();
@ -602,7 +602,7 @@ export default (options = {}) => {
const diffs = [...doc.querySelectorAll(".tabs ul li a")].map((a) => {
let leaderboardId = parseInt(
getFirstRegexpMatch(/leaderboard\/(\d+)$/, a.href),
10
10,
);
if (isNaN(leaderboardId)) leaderboardId = null;
@ -615,7 +615,7 @@ export default (options = {}) => {
const currentDiffHuman = opt(
doc.querySelector(".tabs li.is-active a span"),
"innerText",
null
null,
);
let diff = null;
@ -628,20 +628,20 @@ export default (options = {}) => {
const songName = opt(
doc.querySelector(
".column.is-one-third-desktop .box:first-of-type .title a"
".column.is-one-third-desktop .box:first-of-type .title a",
),
"innerText",
null
null,
);
const imageUrl = getImgUrl(
opt(
doc.querySelector(
".column.is-one-third-desktop .box:first-of-type .columns .column.is-one-quarter img"
".column.is-one-third-desktop .box:first-of-type .columns .column.is-one-quarter img",
),
"src",
null
)
null,
),
);
const songInfo = [
@ -656,13 +656,13 @@ export default (options = {}) => {
]
.map((sid) => {
let songInfoBox = doc.querySelector(
".column.is-one-third-desktop .box:first-of-type"
".column.is-one-third-desktop .box:first-of-type",
);
return {
...sid,
value: songInfoBox
? songInfoBox.innerHTML.match(
new RegExp(sid.label + ":\\s*<b>(.*?)</b>", "i")
new RegExp(sid.label + ":\\s*<b>(.*?)</b>", "i"),
)
: null,
};
@ -708,7 +708,7 @@ export default (options = {}) => {
return cum;
},
{ imageUrl, stats: {} }
{ imageUrl, stats: {} },
);
const { stats, ...song } = songInfo;
@ -718,9 +718,9 @@ export default (options = {}) => {
opt(
doc.querySelector(".pagination .pagination-list li:last-of-type"),
"innerText",
null
null,
),
10
10,
);
if (isNaN(pageQty)) pageQty = null;
@ -736,7 +736,7 @@ export default (options = {}) => {
let diffChartText = getFirstRegexpMatch(
/'difficulty',\s*([0-9.,\s]+)\s*\]/,
doc.body.innerHTML
doc.body.innerHTML,
);
let diffChart = (diffChartText ? diffChartText : "")
.split(",")
@ -758,12 +758,12 @@ export default (options = {}) => {
leaderboardId,
page = 1,
priority = PRIORITY.FG_LOW,
options = {}
options = {},
) =>
fetchHtml(
substituteVars(LEADERBOARD_URL, { leaderboardId, page }),
options,
priority
priority,
).then((r) => {
r.body = processLeaderboard(leaderboardId, page, r.body);

View File

@ -1,44 +1,104 @@
import {default as createQueue, PRIORITY} from '../http-queue';
import ssrConfig from '../../../ssr-config'
import {substituteVars} from "../../../utils/format";
import { default as createQueue, PRIORITY } from "../http-queue";
import ssrConfig from "../../../ssr-config";
import { substituteVars } from "../../../utils/format";
const CLIENT_ID = 'u0swxz56n4iumc634at1osoqdk31qt';
const CLIENT_ID = "u0swxz56n4iumc634at1osoqdk31qt";
const TWITCH_AUTH_URL = 'https://id.twitch.tv/oauth2'
const AUTHORIZATION_URL = `${TWITCH_AUTH_URL}/authorize?client_id=${CLIENT_ID}&redirect_uri=${encodeURIComponent(ssrConfig.domain + '/twitch')}&response_type=token` + '&scope=${scopes}&state=${state}';
const VALIDATE_URL = `${TWITCH_AUTH_URL}/validate`
const TWITCH_AUTH_URL = "https://id.twitch.tv/oauth2";
const AUTHORIZATION_URL =
`${TWITCH_AUTH_URL}/authorize?client_id=${CLIENT_ID}&redirect_uri=${encodeURIComponent(
ssrConfig.domain + "/twitch",
)}&response_type=token` + "&scope=${scopes}&state=${state}";
const VALIDATE_URL = `${TWITCH_AUTH_URL}/validate`;
const TWITCH_API_URL = 'https://api.twitch.tv/helix';
const PROFILE_URL = TWITCH_API_URL + '/users?login=${login}';
const VIDEOS_URL = TWITCH_API_URL + '/videos?user_id=${userId}&type=${type}&first=100';
const STREAMS_URL = TWITCH_API_URL + '/streams?user_id=${userId}';
const TWITCH_API_URL = "https://api.twitch.tv/helix";
const PROFILE_URL = TWITCH_API_URL + "/users?login=${login}";
const VIDEOS_URL =
TWITCH_API_URL + "/videos?user_id=${userId}&type=${type}&first=100";
const STREAMS_URL = TWITCH_API_URL + "/streams?user_id=${userId}";
export default (options = {}) => {
const queue = createQueue(options);
const {fetchJson, fetchHtml, ...queueToReturn} = queue;
const { fetchJson, fetchHtml, ...queueToReturn } = queue;
const fetchApi = (url, accessToken, priority = PRIORITY.FG_LOW, options = {}) => fetchJson(
const fetchApi = (
url,
{
...options,
headers: {
'Client-ID': CLIENT_ID,
'Authorization': `Bearer ${accessToken}`
}
},
priority,
)
accessToken,
priority = PRIORITY.FG_LOW,
options = {},
) =>
fetchJson(
url,
{
...options,
headers: {
"Client-ID": CLIENT_ID,
Authorization: `Bearer ${accessToken}`,
},
},
priority,
);
const getAuthUrl = (state = '', scopes = '') => substituteVars(AUTHORIZATION_URL, {state: encodeURIComponent(state), scopes: encodeURIComponent(scopes)});
const getAuthUrl = (state = "", scopes = "") =>
substituteVars(AUTHORIZATION_URL, {
state: encodeURIComponent(state),
scopes: encodeURIComponent(scopes),
});
const validateToken = async (accessToken, priority = PRIORITY.FG_LOW, options = {}) => fetchJson(VALIDATE_URL, {...options, headers: {'Authorization': `OAuth ${accessToken}`}}, priority)
const validateToken = async (
accessToken,
priority = PRIORITY.FG_LOW,
options = {},
) =>
fetchJson(
VALIDATE_URL,
{ ...options, headers: { Authorization: `OAuth ${accessToken}` } },
priority,
);
const profile = async (accessToken, login, priority = PRIORITY.FG_LOW, options = {}) => fetchApi(substituteVars(PROFILE_URL, {login: encodeURIComponent(login)}), accessToken, priority, options)
const profile = async (
accessToken,
login,
priority = PRIORITY.FG_LOW,
options = {},
) =>
fetchApi(
substituteVars(PROFILE_URL, { login: encodeURIComponent(login) }),
accessToken,
priority,
options,
);
const videos = async (accessToken, userId, type = 'archive', priority = PRIORITY.FG_LOW, options = {}) => fetchApi(substituteVars(VIDEOS_URL, {userId: encodeURIComponent(userId), type: encodeURIComponent(type)}), accessToken, priority, options)
const videos = async (
accessToken,
userId,
type = "archive",
priority = PRIORITY.FG_LOW,
options = {},
) =>
fetchApi(
substituteVars(VIDEOS_URL, {
userId: encodeURIComponent(userId),
type: encodeURIComponent(type),
}),
accessToken,
priority,
options,
);
const streams = async (accessToken, userId, priority = PRIORITY.FG_LOW, options = {}) => fetchApi(substituteVars(STREAMS_URL, {userId: encodeURIComponent(userId)}), accessToken, priority, options)
const streams = async (
accessToken,
userId,
priority = PRIORITY.FG_LOW,
options = {},
) =>
fetchApi(
substituteVars(STREAMS_URL, { userId: encodeURIComponent(userId) }),
accessToken,
priority,
options,
);
return {
getAuthUrl,
@ -47,5 +107,5 @@ export default (options = {}) => {
videos,
streams,
...queueToReturn,
}
}
};
};