feat: extended-player-profile - add a new action 'Show other servers'
continuous-integration/drone/tag Build is passing Details

This commit is contained in:
Dawid Wysokiński 2023-01-31 07:11:56 +01:00
parent 11c95967d9
commit 8cd531ed8b
Signed by: Kichiyaki
GPG Key ID: B5445E357FB8B892
5 changed files with 157 additions and 21 deletions

View File

@ -1,7 +1,7 @@
const preambles = {
'extended-player-profile': `// ==UserScript==
// @name Extended player profile
// @version 1.0.2
// @version 1.1.0
// @description Adds additional info and actions to a player's profile.
// @author Dawid Wysokiński - Kichiyaki - contact@dwysokinski.me
// @match https://*/game.php?*screen=info_player*

View File

@ -4,14 +4,16 @@ import { Player, PlayerSnapshot, TWHelpClient } from './lib/twhelp';
import { DialogTable } from './common/dialog-table';
import { InADayClient } from './lib/tw';
import { createTranslationFunc } from './utils';
import { buildURL } from './lib/twstats';
const t = createTranslationFunc({
pl_PL: {
'Joined at': 'Dołączył o',
'Last activity at': 'Ostatnio aktywny o',
'Best rank': 'Najlepszy ranking',
'Best rank': 'Najwyższy ranking',
'Most points': 'Najwięcej punktów',
'Most villages': 'Najwięcej wiosek',
'Show other servers': 'Pokaż inne serwery',
'Show in a day ranks': 'Pokaż dzienne rankingi',
'Show tribe changes': 'Pokaż zmiany plemion',
'Show history': 'Pokaż historię',
@ -51,6 +53,8 @@ const t = createTranslationFunc({
'Resources gathered': 'Zebrane surowce',
'Villages conquered': 'Przejęte wioski',
Changes: 'Zmiany',
Open: 'Otwarty',
Closed: 'Zamknięty',
},
});
@ -94,6 +98,13 @@ class TWHelpConnector {
sort: ['date:desc'],
});
}
playerOtherServers(page: number, limit: number) {
return this.client.playerOtherServers(this.version, this.server, this.id, {
offset: (page - 1) * limit,
limit,
});
}
}
class InADayConnector {
@ -108,6 +119,7 @@ class InADayConnector {
}
enum DialogId {
OTHER_SERVERS = 'kichiyaki_other_servers',
IN_A_DAY_RANKS = 'kichiyaki_in_a_day_ranks',
TRIBE_CHANGES = 'kichiyaki_tribe_changes',
ENNOBLEMENTS = 'kichiyaki_ennoblements',
@ -276,6 +288,10 @@ class UI {
}
[
{
name: t('Show other servers'),
handler: this.showOtherServers.bind(this),
},
{
name: t('Show in a day ranks'),
handler: this.showInADayRanks.bind(this),
@ -304,6 +320,57 @@ class UI {
});
}
private async showOtherServers(e: Event) {
e.preventDefault();
await new DialogTable(
DialogId.OTHER_SERVERS,
[
{
header: t('Server'),
accessor: (p) =>
`<a href="${buildURL({
server: p.server.key,
id: p.id,
entity: 'player',
})}">${p.server.key} (${
p.server.open ? t('Open') : t('Closed')
})</a>`,
},
{
header: t('Tribe'),
accessor: (p) => {
if (!p.tribe) {
return '-';
}
const url = buildURL({
server: p.server.key,
id: p.tribe.id,
entity: 'tribe',
});
return `<a href="${url}">${p.tribe.tag}</a>`;
},
},
{
header: t('Best rank'),
accessor: (p) => p.bestRank.toString(),
},
{
header: t('Most points'),
accessor: (p) => p.mostPoints.toLocaleString(),
},
{
header: t('Most villages'),
accessor: (p) => p.mostVillages.toLocaleString(),
},
],
30,
(page: number, limit: number) => {
return this.twhelpConnector.playerOtherServers(page, limit);
}
).render();
}
private async showInADayRanks(e: Event) {
e.preventDefault();

View File

@ -2,8 +2,6 @@ import axios, { AxiosInstance } from 'axios';
import random from 'lodash/random';
import { wait } from '../utils';
const DEFAULT_TIMEOUT = 10000;
type InADayScore = {
player: {
id: number;
@ -128,9 +126,9 @@ export type InADayPlayer = {
export class InADayClient {
client: AxiosInstance;
constructor(timeout?: number) {
constructor(timeout: number = 10000) {
this.client = axios.create({
timeout: timeout ?? DEFAULT_TIMEOUT,
timeout,
});
}

View File

@ -1,7 +1,8 @@
import axios, { AxiosInstance } from 'axios';
const DEFAULT_TIMEOUT = 10000;
const X_TOTAL_COUNT_HEADER = 'x-total-count';
import axios, {
AxiosInstance,
AxiosResponseHeaders,
RawAxiosResponseHeaders,
} from 'axios';
export type Version = {
code: string;
@ -10,6 +11,18 @@ export type Version = {
timezone: string;
};
export type ServerMeta = {
key: string;
open: boolean;
};
export type TribeMeta = {
id: number;
name: string;
tag: string;
profileUrl: string;
};
export type Player = {
id: number;
points: number;
@ -31,13 +44,11 @@ export type Player = {
mostVillagesAt: string;
lastActivityAt: string;
createdAt: string;
tribe: TribeMeta | null;
};
export type TribeMeta = {
id: number;
name: string;
tag: string;
profileUrl: string;
export type PlayerWithServer = Player & {
server: ServerMeta;
};
export type PlayerMeta = {
@ -112,13 +123,18 @@ export type ListPlayerSnapshotsParams = {
sort?: string[];
};
export type ListPlayerOtherServersParams = {
offset?: number;
limit?: number;
};
export class TWHelpClient {
client: AxiosInstance;
constructor(url: string, timeout?: number) {
constructor(url: string, timeout: number = 10000) {
this.client = axios.create({
baseURL: url,
timeout: timeout ?? DEFAULT_TIMEOUT,
timeout,
});
}
@ -126,7 +142,7 @@ export class TWHelpClient {
const resp = await this.client.get('/api/v1/versions');
return {
data: resp.data.data,
total: parseInt(resp.headers[X_TOTAL_COUNT_HEADER] ?? '0'),
total: this.parseTotal(resp.headers),
};
}
@ -168,7 +184,7 @@ export class TWHelpClient {
);
return {
data: resp.data.data,
total: parseInt(resp.headers[X_TOTAL_COUNT_HEADER] ?? '0'),
total: this.parseTotal(resp.headers),
};
}
@ -199,7 +215,7 @@ export class TWHelpClient {
);
return {
data: resp.data.data,
total: parseInt(resp.headers[X_TOTAL_COUNT_HEADER] ?? '0'),
total: this.parseTotal(resp.headers),
};
}
@ -230,7 +246,38 @@ export class TWHelpClient {
);
return {
data: resp.data.data,
total: parseInt(resp.headers[X_TOTAL_COUNT_HEADER] ?? '0'),
total: this.parseTotal(resp.headers),
};
}
public async playerOtherServers(
version: string,
server: string,
id: number,
queryParams?: ListPlayerOtherServersParams
): Promise<ListResult<PlayerWithServer>> {
const params = new URLSearchParams();
if (queryParams?.limit) {
params.set('limit', queryParams.limit.toString());
}
if (queryParams?.offset) {
params.set('offset', queryParams.offset.toString());
}
const resp = await this.client.get(
`/api/v1/versions/${version}/servers/${server}/players/${id}/other-servers?${params.toString()}`
);
return {
data: resp.data.data,
total: this.parseTotal(resp.headers),
};
}
private parseTotal(
headers: RawAxiosResponseHeaders | AxiosResponseHeaders
): number {
return parseInt(headers['x-total-count'] ?? '0');
}
}

24
src/lib/twstats.ts Normal file
View File

@ -0,0 +1,24 @@
const BASE = 'https://www.twstats.com';
export type BuildURLParams =
| {
entity: 'player';
id: number;
server: string;
}
| {
entity: 'tribe';
id: number;
server: string;
};
export const buildURL = (params: BuildURLParams) => {
switch (params.entity) {
case 'player':
return `${BASE}/in/${params.server}/player/${params.id}`;
case 'tribe':
return `${BASE}/in/${params.server}/tribe/${params.id}`;
default:
throw new Error(`Incorrect params.entity`);
}
};