forked from samuelthomas2774/nxapi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutil.ts
151 lines (126 loc) · 6.24 KB
/
util.ts
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
140
141
142
143
144
145
146
147
148
149
150
151
import DiscordRPC from 'discord-rpc';
import { Game, PresenceState } from '../api/coral-types.js';
import { defaultTitle, titles } from './titles.js';
import { product, version } from '../util/product.js';
import { getTitleIdFromEcUrl, hrduration } from '../util/misc.js';
import { DiscordPresence, DiscordPresenceContext, DiscordPresencePlayTime } from './types.js';
export function getDiscordPresence(
state: PresenceState, game: Game, context?: DiscordPresenceContext
): DiscordPresence {
const titleid = getTitleIdFromEcUrl(game.shopUri);
const title = titles.find(t => t.id === titleid) || defaultTitle;
const text: (string | undefined)[] = [];
if (title.titleName === true) text.push(game.name);
else if (title.titleName) text.push(title.titleName);
const online = state === PresenceState.PLAYING;
const members = context?.activeevent?.members.filter(m => m.isPlaying);
const event_text = title.showActiveEvent && context?.activeevent ?
' (' + members?.length + ' player' + (members?.length === 1 ? '' : 's') +
')' : '';
if ((title.showDescription ?? true) && game.sysDescription) text.push(game.sysDescription + event_text);
else if (online && title.showPlayingOnline === true) text.push('Playing online' + event_text);
else if (online && title.showPlayingOnline) text.push(title.showPlayingOnline as string + event_text);
// Always show play time as `state`, not `details`
// This doesn't normally have a noticeable effect, but the Active Now panel does show details/state differently
if (!text.length) text.push(undefined);
if ((title.showPlayTime ?? true) && game.totalPlayTime >= 60) {
const play_time_text = getPlayTimeText(context?.show_play_time ??
DiscordPresencePlayTime.DETAILED_PLAY_TIME_SINCE, game);
if (play_time_text) text.push(play_time_text);
}
const nintendo_eshop_redirect_url = titleid ?
'https://fancy.org.uk/api/nxapi/title/' + titleid + '/redirect?source=nxapi-' + version + '-discord' : null;
const activity: DiscordRPC.Presence = {
details: text[0],
state: text[1],
largeImageKey: title.largeImageKey ?? game.imageUri,
largeImageText: title.largeImageText ? title.largeImageText + ' | ' + product : product,
smallImageKey: title.smallImageKey || (context?.friendcode ? context?.user?.imageUri : undefined),
smallImageText: title.smallImageKey ? title.smallImageText :
context?.friendcode && context?.user?.imageUri ? 'SW-' + context.friendcode.id : undefined,
buttons: game.shopUri ? [
{
label: 'Nintendo eShop',
url: nintendo_eshop_redirect_url ?? game.shopUri,
},
] : [],
};
if (online && title.showActiveEvent) {
activity.buttons!.push({
label: context?.activeevent?.shareUri ? 'Join' : 'Join via Nintendo Switch',
url: context?.activeevent?.shareUri ?? 'https://lounge.nintendo.com',
});
}
title.callback?.call(null, activity, game, context);
return {
id: title.client || defaultTitle.client,
title: titleid,
activity,
showTimestamp: title.showTimestamp ?? true,
};
}
function getPlayTimeText(type: DiscordPresencePlayTime, game: Game) {
if (type === DiscordPresencePlayTime.NINTENDO) {
const days = Math.floor(Date.now() / 1000 / 86400) - Math.floor(game.firstPlayedAt / 86400);
if (days <= 10) return getFirstPlayedText(game.firstPlayedAt);
if (game.totalPlayTime < 60) return 'Played for a little while';
return 'Played for ' + hrduration(getApproximatePlayTime(game.totalPlayTime)) + ' or more';
}
if (type === DiscordPresencePlayTime.HIDDEN || game.totalPlayTime < 0) return null;
const since = game.firstPlayedAt ? new Date(game.firstPlayedAt * 1000).toLocaleDateString('en-GB') : 'now';
switch (type) {
case DiscordPresencePlayTime.APPROXIMATE_PLAY_TIME:
if (game.totalPlayTime < 60) return null;
return 'Played for ' + hrduration(getApproximatePlayTime(game.totalPlayTime)) + ' or more';
case DiscordPresencePlayTime.APPROXIMATE_PLAY_TIME_SINCE:
if (game.totalPlayTime < 60) return null;
return 'Played for ' + hrduration(getApproximatePlayTime(game.totalPlayTime)) + ' or more since ' + since;
case DiscordPresencePlayTime.DETAILED_PLAY_TIME:
return 'Played for ' + hrduration(game.totalPlayTime);
case DiscordPresencePlayTime.DETAILED_PLAY_TIME_SINCE:
return 'Played for ' + hrduration(game.totalPlayTime) + ' since ' + since;
}
return null;
}
function getFirstPlayedText(first_played_at: number) {
const minutes = Math.floor(Date.now() / 1000 / 60) - Math.floor(first_played_at / 60);
if (minutes <= 0) return null;
if (minutes <= 60) {
return 'First played ' + minutes + ' minute' + (minutes === 1 ? '' : 's') + ' ago';
}
const hours = Math.floor(Date.now() / 1000 / 3600) - Math.floor(first_played_at / 3600);
if (hours <= 24) {
return 'First played ' + hours + ' hour' + (hours === 1 ? '' : 's') + ' ago';
}
const days = Math.floor(Date.now() / 1000 / 86400) - Math.floor(first_played_at / 86400);
return 'First played ' + days + ' day' + (days === 1 ? '' : 's') + ' ago';
}
function getApproximatePlayTime(minutes: number) {
if (minutes < 300) {
// Less than 5 hours
return Math.floor(minutes / 60) * 60;
} else {
return Math.floor(minutes / 300) * 300;
}
}
export function getInactiveDiscordPresence(
state: PresenceState, logoutAt: number, context?: DiscordPresenceContext
): DiscordPresence {
return {
id: defaultTitle.client,
title: null,
activity: {
state: 'Not playing',
largeImageKey: 'nintendoswitch',
largeImageText: product,
smallImageKey: context?.friendcode ? context?.user?.imageUri : undefined,
smallImageText: context?.friendcode && context?.user?.imageUri ? 'SW-' + context.friendcode.id : undefined,
},
};
}
export function getTitleConfiguration(game: Game, id: string) {
return titles.find(title => {
if (title.id !== id) return false;
return true;
});
}