Move Nintendo Switch Online commands

This commit is contained in:
Samuel Elliott
2022-03-17 13:03:00 +00:00
parent 3919ceeb21
commit 311d13d0d1
21 changed files with 104 additions and 91 deletions

View File

@@ -1,7 +1,7 @@
nintendo-znc
nxapi
===
Set Discord Rich Presence and get notifications for Nintendo Switch friends using the Nintendo Switch Online app API.
Access the Nintendo Switch Online and Nintendo Switch Parental Controls app APIs. Includes Discord Rich Presence and friend notifications.
### Links

View File

@@ -1,2 +1,2 @@
#!/usr/bin/env sh
"$(dirname "$0")/../node_modules/.bin/node" "$(dirname "$0")/nintendo-znc.js" $@
"$(dirname "$0")/../node_modules/.bin/node" "$(dirname "$0")/nxapi.js" $@

6
package-lock.json generated
View File

@@ -1,11 +1,11 @@
{
"name": "nintendo-znc",
"name": "nxapi",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "nintendo-znc",
"name": "nxapi",
"version": "1.0.0",
"dependencies": {
"cli-table": "^0.3.11",
@@ -22,7 +22,7 @@
"yargs": "^17.3.1"
},
"bin": {
"nintendo-znc": "bin/nintendo-znc.js"
"nxapi": "bin/nxapi.js"
},
"devDependencies": {
"@types/cli-table": "^0.3.0",

View File

@@ -1,5 +1,5 @@
{
"name": "nintendo-znc",
"name": "nxapi",
"version": "1.0.0",
"description": "",
"author": "Samuel Elliott",
@@ -7,18 +7,18 @@
"type": "module",
"repository": {
"type": "git",
"url": "git@gitlab.fancy.org.uk:samuel/nintendo-znc.git"
"url": "git@gitlab.fancy.org.uk:samuel/nxapi.git"
},
"bin": {
"nintendo-znc": "bin/nintendo-znc.js"
"nxapi": "bin/nxapi.js"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"cli": "node bin/nintendo-znc.js",
"build-macos-linux": "caxa --input . --exclude src dist/bin data node_modules --prepare-command \"npm ci --production\" --output dist/bin/nintendo-znc -- \"{{caxa}}/node_modules/.bin/node\" \"{{caxa}}/bin/nintendo-znc.js\"",
"build-macosapp": "caxa --input . --exclude src dist/bin data node_modules --prepare-command \"npm ci --production\" --output dist/bin/nintendo-znc.app -- \"{{caxa}}/node_modules/.bin/node\" \"{{caxa}}/bin/nintendo-znc.js\" \"presence\"",
"build-windows": "caxa --input . --exclude src dist/bin data node_modules --prepare-command \"npm ci --production\" --output dist/bin/nintendo-znc.exe -- \"{{caxa}}/node_modules/.bin/node\" \"{{caxa}}/bin/nintendo-znc.js\"",
"start": "node bin/nintendo-znc.js presence"
"cli": "node bin/nxapi.js",
"build-macos-linux": "caxa --input . --exclude src dist/bin data node_modules --prepare-command \"npm ci --production\" --output dist/bin/nintendo-znc -- \"{{caxa}}/node_modules/.bin/node\" \"{{caxa}}/bin/nxapi.js\"",
"build-macosapp": "caxa --input . --exclude src dist/bin data node_modules --prepare-command \"npm ci --production\" --output dist/bin/nintendo-znc.app -- \"{{caxa}}/node_modules/.bin/node\" \"{{caxa}}/bin/nxapi.js\" \"presence\"",
"build-windows": "caxa --input . --exclude src dist/bin data node_modules --prepare-command \"npm ci --production\" --output dist/bin/nintendo-znc.exe -- \"{{caxa}}/node_modules/.bin/node\" \"{{caxa}}/bin/nxapi.js\"",
"start": "node bin/nxapi.js presence"
},
"dependencies": {
"cli-table": "^0.3.11",

View File

@@ -9,9 +9,6 @@ const yargs = Yargs(process.argv.slice(2)).option('data-path', {
describe: 'Data storage path',
type: 'string',
default: paths.data,
}).option('znc-proxy-url', {
describe: 'URL of Nintendo Switch Online app API proxy server to use',
type: 'string',
});
export type Arguments = YargsArguments<typeof yargs>;
@@ -22,7 +19,7 @@ for (const command of Object.values(commands)) {
}
yargs
.scriptName('nintendo-znc')
.scriptName('nxapi')
.demandCommand()
.help()
// .version(false)

View File

@@ -1,12 +1,3 @@
export * as token from './token.js';
export * as auth from './auth.js';
export * as users from './users.js';
export * as user from './user.js';
export * as announcements from './announcements.js';
export * as webservices from './webservices.js';
export * as webservicetoken from './webservicetoken.js';
export * as friends from './friends.js';
export * as presence from './presence.js';
export * as notify from './notify.js';
export * as httpServer from './http-server.js';
export * as nso from './nso.js';
export * as pctl from './pctl.js';

23
src/cli/nso.ts Normal file
View File

@@ -0,0 +1,23 @@
import createDebug from 'debug';
import type { Arguments as ParentArguments } from '../cli.js';
import { Argv, YargsArguments } from '../util.js';
import * as commands from './nso/index.js';
const debug = createDebug('cli:nso');
export const command = 'nso <command>';
export const desc = 'Nintendo Switch Online';
export function builder(yargs: Argv<ParentArguments>) {
for (const command of Object.values(commands)) {
// @ts-expect-error
yargs.command(command);
}
return yargs.option('znc-proxy-url', {
describe: 'URL of Nintendo Switch Online app API proxy server to use',
type: 'string',
});
}
export type Arguments = YargsArguments<ReturnType<typeof builder>>;

View File

@@ -1,10 +1,10 @@
import createDebug from 'debug';
// @ts-expect-error
import Table from 'cli-table/lib/index.js';
import type { Arguments as ParentArguments } from '../cli.js';
import { ArgumentsCamelCase, Argv, getToken, initStorage, YargsArguments } from '../util.js';
import type { Arguments as ParentArguments } from '../nso.js';
import { ArgumentsCamelCase, Argv, getToken, initStorage, YargsArguments } from '../../util.js';
const debug = createDebug('cli:announcements');
const debug = createDebug('cli:nso:announcements');
export const command = 'announcements';
export const desc = 'List Nintendo Switch Online app announcements';
@@ -34,8 +34,7 @@ export async function handler(argv: ArgumentsCamelCase<Arguments>) {
const usernsid = argv.user ?? await storage.getItem('SelectedUser');
const token: string = argv.token ||
await storage.getItem('NintendoAccountToken.' + usernsid) ||
await storage.getItem('SessionToken');
await storage.getItem('NintendoAccountToken.' + usernsid);
const {nso, data} = await getToken(storage, token, argv.zncProxyUrl);
const announcements = await nso.getAnnouncements();

View File

@@ -1,12 +1,12 @@
import * as util from 'util';
import createDebug from 'debug';
import * as crypto from 'crypto';
import type { Arguments as ParentArguments } from '../cli.js';
import { ArgumentsCamelCase, Argv, getToken, initStorage, YargsArguments } from '../util.js';
import { getNintendoAccountSessionToken } from '../api/na.js';
import { ZNCA_CLIENT_ID } from '../api/znc.js';
import type { Arguments as ParentArguments } from '../nso.js';
import { ArgumentsCamelCase, Argv, getToken, initStorage, YargsArguments } from '../../util.js';
import { getNintendoAccountSessionToken } from '../../api/na.js';
import { ZNCA_CLIENT_ID } from '../../api/znc.js';
const debug = createDebug('cli:auth');
const debug = createDebug('cli:nso:auth');
export const command = 'auth';
export const desc = 'Generate a link to login to a Nintendo Account';

View File

@@ -1,11 +1,11 @@
import createDebug from 'debug';
// @ts-expect-error
import Table from 'cli-table/lib/index.js';
import { PresenceState } from '../api/znc-types.js';
import type { Arguments as ParentArguments } from '../cli.js';
import { ArgumentsCamelCase, Argv, getToken, hrduration, initStorage, YargsArguments } from '../util.js';
import { PresenceState } from '../../api/znc-types.js';
import type { Arguments as ParentArguments } from '../nso.js';
import { ArgumentsCamelCase, Argv, getToken, hrduration, initStorage, YargsArguments } from '../../util.js';
const debug = createDebug('cli:friends');
const debug = createDebug('cli:nso:friends');
export const command = 'friends';
export const desc = 'List Nintendo Switch friends';
@@ -35,8 +35,7 @@ export async function handler(argv: ArgumentsCamelCase<Arguments>) {
const usernsid = argv.user ?? await storage.getItem('SelectedUser');
const token: string = argv.token ||
await storage.getItem('NintendoAccountToken.' + usernsid) ||
await storage.getItem('SessionToken');
await storage.getItem('NintendoAccountToken.' + usernsid);
const {nso, data} = await getToken(storage, token, argv.zncProxyUrl);
const announcements = await nso.getAnnouncements();

View File

@@ -2,10 +2,10 @@ import createDebug from 'debug';
import express from 'express';
import * as net from 'net';
import persist from 'node-persist';
import { ActiveEvent, Announcement, CurrentUser, Friend, Presence, WebService } from '../api/znc-types.js';
import ZncApi from '../api/znc.js';
import type { Arguments as ParentArguments } from '../cli.js';
import { ArgumentsCamelCase, Argv, getToken, initStorage, SavedToken, YargsArguments } from '../util.js';
import { ActiveEvent, Announcement, CurrentUser, Friend, Presence, WebService } from '../../api/znc-types.js';
import ZncApi from '../../api/znc.js';
import type { Arguments as ParentArguments } from '../nso.js';
import { ArgumentsCamelCase, Argv, getToken, initStorage, SavedToken, YargsArguments } from '../../util.js';
import { ZncNotifications } from './notify.js';
declare global {

10
src/cli/nso/index.ts Normal file
View File

@@ -0,0 +1,10 @@
export * as token from './token.js';
export * as auth from './auth.js';
export * as user from './user.js';
export * as announcements from './announcements.js';
export * as webservices from './webservices.js';
export * as webservicetoken from './webservicetoken.js';
export * as friends from './friends.js';
export * as presence from './presence.js';
export * as notify from './notify.js';
export * as httpServer from './http-server.js';

View File

@@ -1,14 +1,14 @@
import createDebug from 'debug';
import persist from 'node-persist';
import notifier from 'node-notifier';
import { CurrentUser, Friend, Game, PresenceState } from '../api/znc-types.js';
import ZncApi from '../api/znc.js';
import type { Arguments as ParentArguments } from '../cli.js';
import { ArgumentsCamelCase, Argv, getTitleIdFromEcUrl, getToken, initStorage, SavedToken, YargsArguments } from '../util.js';
import ZncProxyApi from '../api/znc-proxy.js';
import { CurrentUser, Friend, Game, PresenceState } from '../../api/znc-types.js';
import ZncApi from '../../api/znc.js';
import type { Arguments as ParentArguments } from '../nso.js';
import { ArgumentsCamelCase, Argv, getTitleIdFromEcUrl, getToken, initStorage, SavedToken, YargsArguments } from '../../util.js';
import ZncProxyApi from '../../api/znc-proxy.js';
const debug = createDebug('cli:notify');
const debugFriends = createDebug('cli:notify:friends');
const debug = createDebug('cli:nso:notify');
const debugFriends = createDebug('cli:nso:notify:friends');
export const command = 'notify';
export const desc = 'Show notifications when friends come online without starting Discord Rich Presence';
@@ -46,8 +46,7 @@ export async function handler(argv: ArgumentsCamelCase<Arguments>) {
const usernsid = argv.user ?? await storage.getItem('SelectedUser');
const token: string = argv.token ||
await storage.getItem('NintendoAccountToken.' + usernsid) ||
await storage.getItem('SessionToken');
await storage.getItem('NintendoAccountToken.' + usernsid);
const {nso, data} = await getToken(storage, token, argv.zncProxyUrl);
const i = new ZncNotifications(argv, storage, token, nso, data);

View File

@@ -2,16 +2,16 @@ import createDebug from 'debug';
import persist from 'node-persist';
import DiscordRPC from 'discord-rpc';
import fetch from 'node-fetch';
import { CurrentUser, Friend, Presence, PresenceState } from '../api/znc-types.js';
import ZncApi from '../api/znc.js';
import type { Arguments as ParentArguments } from '../cli.js';
import { ArgumentsCamelCase, Argv, getDiscordPresence, getTitleIdFromEcUrl, getToken, initStorage, SavedToken, YargsArguments } from '../util.js';
import { CurrentUser, Friend, Presence, PresenceState } from '../../api/znc-types.js';
import ZncApi from '../../api/znc.js';
import type { Arguments as ParentArguments } from '../nso.js';
import { ArgumentsCamelCase, Argv, getDiscordPresence, getTitleIdFromEcUrl, getToken, initStorage, SavedToken, YargsArguments } from '../../util.js';
import { ZncNotifications } from './notify.js';
import ZncProxyApi from '../api/znc-proxy.js';
import ZncProxyApi from '../../api/znc-proxy.js';
const debug = createDebug('cli:presence');
const debugProxy = createDebug('cli:presence:proxy');
const debugDiscord = createDebug('cli:presence:discordrpc');
const debug = createDebug('cli:nso:presence');
const debugProxy = createDebug('cli:nso:presence:proxy');
const debugDiscord = createDebug('cli:nso:presence:discordrpc');
export const command = 'presence';
export const desc = 'Start Discord Rich Presence';
@@ -42,7 +42,7 @@ export function builder(yargs: Argv<ParentArguments>) {
type: 'number',
default: 30,
}).option('presence-url', {
describe: 'URL to get user presence from, for use with `nintendo-znc http-server`',
describe: 'URL to get user presence from, for use with `nxapi nso http-server`',
type: 'string',
});
}
@@ -74,8 +74,7 @@ export async function handler(argv: ArgumentsCamelCase<Arguments>) {
const usernsid = argv.user ?? await storage.getItem('SelectedUser');
const token: string = argv.token ||
await storage.getItem('NintendoAccountToken.' + usernsid) ||
await storage.getItem('SessionToken');
await storage.getItem('NintendoAccountToken.' + usernsid);
const {nso, data} = await getToken(storage, token, argv.zncProxyUrl);
const i = new ZncDiscordPresence(argv, storage, token, nso, data);

View File

@@ -1,9 +1,9 @@
import * as util from 'util';
import createDebug from 'debug';
import type { Arguments as ParentArguments } from '../cli.js';
import { ArgumentsCamelCase, Argv, getToken, initStorage, YargsArguments } from '../util.js';
import type { Arguments as ParentArguments } from '../nso.js';
import { ArgumentsCamelCase, Argv, getToken, initStorage, YargsArguments } from '../../util.js';
const debug = createDebug('cli:token');
const debug = createDebug('cli:nso:token');
export const command = 'token [token]';
export const desc = 'Set the default Nintendo Account session token';

View File

@@ -1,8 +1,8 @@
import createDebug from 'debug';
import type { Arguments as ParentArguments } from '../cli.js';
import { ArgumentsCamelCase, Argv, getToken, initStorage, YargsArguments } from '../util.js';
import type { Arguments as ParentArguments } from '../nso.js';
import { ArgumentsCamelCase, Argv, getToken, initStorage, YargsArguments } from '../../util.js';
const debug = createDebug('cli:user');
const debug = createDebug('cli:nso:user');
export const command = 'user';
export const desc = 'Get the authenticated Nintendo Account';
@@ -28,8 +28,7 @@ export async function handler(argv: ArgumentsCamelCase<Arguments>) {
const usernsid = argv.user ?? await storage.getItem('SelectedUser');
const token: string = argv.token ||
await storage.getItem('NintendoAccountToken.' + usernsid) ||
await storage.getItem('SessionToken');
await storage.getItem('NintendoAccountToken.' + usernsid);
const {nso, data} = await getToken(storage, token, argv.zncProxyUrl);
if (argv.forceRefresh && 'expires_at' in data) {

View File

@@ -1,10 +1,10 @@
import createDebug from 'debug';
// @ts-expect-error
import Table from 'cli-table/lib/index.js';
import type { Arguments as ParentArguments } from '../cli.js';
import { ArgumentsCamelCase, Argv, getToken, initStorage, YargsArguments } from '../util.js';
import type { Arguments as ParentArguments } from '../nso.js';
import { ArgumentsCamelCase, Argv, getToken, initStorage, YargsArguments } from '../../util.js';
const debug = createDebug('cli:announcements');
const debug = createDebug('cli:nso:webservices');
export const command = 'webservices';
export const desc = 'List Nintendo Switch Online web services';
@@ -34,8 +34,7 @@ export async function handler(argv: ArgumentsCamelCase<Arguments>) {
const usernsid = argv.user ?? await storage.getItem('SelectedUser');
const token: string = argv.token ||
await storage.getItem('NintendoAccountToken.' + usernsid) ||
await storage.getItem('SessionToken');
await storage.getItem('NintendoAccountToken.' + usernsid);
const {nso, data} = await getToken(storage, token, argv.zncProxyUrl);
const announcements = await nso.getAnnouncements();

View File

@@ -1,9 +1,8 @@
import createDebug from 'debug';
import fetch from 'node-fetch';
import type { Arguments as ParentArguments } from '../cli.js';
import { ArgumentsCamelCase, Argv, getToken, initStorage, YargsArguments } from '../util.js';
import type { Arguments as ParentArguments } from '../nso.js';
import { ArgumentsCamelCase, Argv, getToken, initStorage, YargsArguments } from '../../util.js';
const debug = createDebug('cli:announcements');
const debug = createDebug('cli:nso:webservicetoken');
export const command = 'webservicetoken <id>';
export const desc = 'Get a token for a web service';
@@ -35,8 +34,7 @@ export async function handler(argv: ArgumentsCamelCase<Arguments>) {
const usernsid = argv.user ?? await storage.getItem('SelectedUser');
const token: string = argv.token ||
await storage.getItem('NintendoAccountToken.' + usernsid) ||
await storage.getItem('SessionToken');
await storage.getItem('NintendoAccountToken.' + usernsid);
const {nso, data} = await getToken(storage, token, argv.zncProxyUrl);
const announcements = await nso.getAnnouncements();

View File

@@ -66,7 +66,7 @@ export function builder(yargs: Argv<ParentArguments>) {
const token: string | undefined = await storage.getItem('NintendoAccountToken.' + argv.user);
if (!token) {
console.error('No session token for this user. Set a Nintendo Account session token by running `nintendo-znc token --select`.');
console.error('No session token for this user. Set a Nintendo Account session token by running `nxapi nso token --select` or `nxapi pctl token --select`.');
throw new Error('Unknown user');
}

View File

@@ -15,7 +15,7 @@ import MoonApi from './api/moon.js';
const debug = createDebug('cli');
export const paths = getPaths('nintendo-znc');
export const paths = getPaths('nxapi');
export type YargsArguments<T extends yargs.Argv> = T extends yargs.Argv<infer R> ? R : any;
export type Argv<T = {}> = yargs.Argv<T>;
@@ -52,7 +52,7 @@ export async function initStorage(dir: string) {
export async function getToken(storage: persist.LocalStorage, token: string, proxy_url?: string) {
if (!token) {
console.error('No token set. Set a Nintendo Account session token using the `--token` option or by running `nintendo-znc token`.');
console.error('No token set. Set a Nintendo Account session token using the `--token` option or by running `nxapi nso token`.');
throw new Error('Invalid token');
}
@@ -90,7 +90,7 @@ export async function getToken(storage: persist.LocalStorage, token: string, pro
export async function getPctlToken(storage: persist.LocalStorage, token: string) {
if (!token) {
console.error('No token set. Set a Nintendo Account session token using the `--token` option or by running `nintendo-znc pctl users add`.');
console.error('No token set. Set a Nintendo Account session token using the `--token` option or by running `nxapi pctl auth`.');
throw new Error('Invalid token');
}