From 5c79874118d7fe4663e4e9be59c2335ae87e8dc4 Mon Sep 17 00:00:00 2001 From: Samuel Elliott Date: Sat, 26 Mar 2022 22:12:04 +0000 Subject: [PATCH] Allow automatically updating iksm_session while monitoring SplatNet 2 --- src/cli/nso/notify.ts | 7 ++++++- src/cli/nso/presence.ts | 27 +++++++++++++++++++++------ src/cli/splatnet2/monitor.ts | 2 +- src/discord/util.ts | 21 ++++++++++++++------- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/cli/nso/notify.ts b/src/cli/nso/notify.ts index b2d83b0..95c76a8 100644 --- a/src/cli/nso/notify.ts +++ b/src/cli/nso/notify.ts @@ -84,6 +84,11 @@ export function builder(yargs: Argv) { type: 'number', // 3 minutes - the monitor is only active while the authenticated user is playing Splatoon 2 online default: 3 * 60, + }).option('splatnet2-auto-update-session', { + alias: ['sn2-auto-update-session'], + describe: 'Automatically obtain and refresh the iksm_session cookie', + type: 'boolean', + default: true, }); } @@ -461,7 +466,7 @@ export function handleEnableSplatNet2Monitoring( return async () => { const directory = argv.splatnet2MonitorDirectory ?? path.join(argv.dataPath, 'splatnet2'); - const {splatnet, data} = await getIksmToken(storage, token, argv.zncProxyUrl); + const {splatnet, data} = await getIksmToken(storage, token, argv.zncProxyUrl, argv.splatnet2AutoUpdateSession); const records = await splatnet.getRecords(); const stages = await splatnet.getStages(); diff --git a/src/cli/nso/presence.ts b/src/cli/nso/presence.ts index da65c13..8d097c2 100644 --- a/src/cli/nso/presence.ts +++ b/src/cli/nso/presence.ts @@ -6,7 +6,7 @@ import { CurrentUser, Friend, Presence, PresenceState, ZncErrorResponse, ZncSucc import ZncApi from '../../api/znc.js'; import type { Arguments as ParentArguments } from '../nso.js'; import { ArgumentsCamelCase, Argv, getToken, initStorage, LoopResult, SavedToken, YargsArguments } from '../../util.js'; -import { getDiscordPresence, getInactiveDiscordPresence } from '../../discord/util.js'; +import { DiscordPresenceContext, getDiscordPresence, getInactiveDiscordPresence } from '../../discord/util.js'; import { handleEnableSplatNet2Monitoring, ZncNotifications } from './notify.js'; import ZncProxyApi from '../../api/znc-proxy.js'; import { ErrorResponse } from '../../index.js'; @@ -98,6 +98,11 @@ export function builder(yargs: Argv) { type: 'number', // 3 minutes - the monitor is only active while the authenticated user is playing Splatoon 2 online default: 3 * 60, + }).option('splatnet2-auto-update-session', { + alias: ['sn2-auto-update-session'], + describe: 'Automatically obtain and refresh the iksm_session cookie', + type: 'boolean', + default: true, }); } @@ -170,7 +175,7 @@ export async function handler(argv: ArgumentsCamelCase) { } } -class ZncDiscordPresence extends ZncNotifications { +export class ZncDiscordPresence extends ZncNotifications { show_friend_code = false; force_friend_code: CurrentUser['links']['friendCode'] | undefined = undefined; show_console_online = false; @@ -261,7 +266,13 @@ class ZncDiscordPresence extends ZncNotifications { title: {id: string; since: number} | null = null; i = 0; + last_presence: Presence | null = null; + friendcode: CurrentUser['links']['friendCode'] | undefined = undefined; + async updatePresence(presence: Presence | null, friendcode?: CurrentUser['links']['friendCode']) { + this.last_presence = presence; + this.friendcode = friendcode; + const online = presence?.state === PresenceState.ONLINE || presence?.state === PresenceState.PLAYING; const show_presence = @@ -279,10 +290,14 @@ class ZncDiscordPresence extends ZncNotifications { return; } - const fc = this.show_friend_code ? this.force_friend_code ?? friendcode : undefined; + const presencecontext: DiscordPresenceContext = { + friendcode: this.show_friend_code ? this.force_friend_code ?? friendcode : undefined, + znc_discord_presence: this, + nsaid: this.friend_nsaid ?? this.data.nsoAccount.user.nsaId, + }; const discordpresence = 'name' in presence.game ? - getDiscordPresence(presence.state, presence.game, fc) : - getInactiveDiscordPresence(presence.state, presence.logoutAt, fc); + getDiscordPresence(presence.state, presence.game, presencecontext) : + getInactiveDiscordPresence(presence.state, presence.logoutAt, presencecontext); if (this.rpc && this.rpc.id !== discordpresence.id) { const client = this.rpc.client; @@ -446,7 +461,7 @@ class ZncDiscordPresence extends ZncNotifications { } } -class ZncProxyDiscordPresence extends ZncDiscordPresence { +export class ZncProxyDiscordPresence extends ZncDiscordPresence { constructor( readonly argv: ArgumentsCamelCase, public presence_url: string diff --git a/src/cli/splatnet2/monitor.ts b/src/cli/splatnet2/monitor.ts index ad97e94..4afdf16 100644 --- a/src/cli/splatnet2/monitor.ts +++ b/src/cli/splatnet2/monitor.ts @@ -72,7 +72,7 @@ export async function handler(argv: ArgumentsCamelCase) { const usernsid = argv.user ?? await storage.getItem('SelectedUser'); const token: string = argv.token || await storage.getItem('NintendoAccountToken.' + usernsid); - const {splatnet, data} = await getIksmToken(storage, token, argv.zncProxyUrl); + const {splatnet, data} = await getIksmToken(storage, token, argv.zncProxyUrl, argv.autoUpdateSession); const records = await splatnet.getRecords(); const stages = await splatnet.getStages(); diff --git a/src/discord/util.ts b/src/discord/util.ts index 6caace2..909d00c 100644 --- a/src/discord/util.ts +++ b/src/discord/util.ts @@ -2,10 +2,10 @@ import DiscordRPC from 'discord-rpc'; import { CurrentUser, Game, PresenceState } from '../api/znc-types.js'; import titles, { defaultTitle } from './titles.js'; import { getTitleIdFromEcUrl, hrduration } from '../util.js'; +import { ZncDiscordPresence } from '../cli/nso/presence.js'; export function getDiscordPresence( - state: PresenceState, game: Game, - friendcode?: CurrentUser['links']['friendCode'] + state: PresenceState, game: Game, context?: DiscordPresenceContext ): DiscordPresence { const titleid = getTitleIdFromEcUrl(game.shopUri); const title = titles.find(t => t.id === titleid) || defaultTitle; @@ -28,7 +28,7 @@ export function getDiscordPresence( details: text[0], state: text[1], largeImageKey: title.largeImageKey ?? game.imageUri, - largeImageText: friendcode ? 'SW-' + friendcode.id : undefined, + largeImageText: context?.friendcode ? 'SW-' + context.friendcode.id : undefined, smallImageKey: title.smallImageKey, buttons: game.shopUri ? [ { @@ -38,7 +38,7 @@ export function getDiscordPresence( ] : [], }; - title.callback?.call(null, activity, game); + title.callback?.call(null, activity, game, context); return { id: title.client || defaultTitle.client, @@ -49,8 +49,7 @@ export function getDiscordPresence( } export function getInactiveDiscordPresence( - state: PresenceState, logoutAt: number, - friendcode?: CurrentUser['links']['friendCode'] + state: PresenceState, logoutAt: number, context?: DiscordPresenceContext ): DiscordPresence { return { id: defaultTitle.client, @@ -58,11 +57,17 @@ export function getInactiveDiscordPresence( activity: { state: 'Not playing', largeImageKey: 'nintendoswitch', - largeImageText: friendcode ? 'SW-' + friendcode.id : undefined, + largeImageText: context?.friendcode ? 'SW-' + context.friendcode.id : undefined, }, }; } +export interface DiscordPresenceContext { + friendcode?: CurrentUser['links']['friendCode']; + znc_discord_presence?: ZncDiscordPresence; + nsaid?: string; +} + export interface DiscordPresence { id: string; title: string | null; @@ -90,4 +95,6 @@ export interface Title { showTimestamp?: boolean; /** Show "Playing online" if playing online and the game doesn't set activity details */ showPlayingOnline?: string | boolean; + + callback?: (activity: DiscordRPC.Presence, game: Game, context?: DiscordPresenceContext) => void; }