From a992aa0ebe1bd14e7d4be20f18f19fcc356721cb Mon Sep 17 00:00:00 2001 From: Janne Liuhtonen Date: Sat, 20 Apr 2024 14:08:00 +0300 Subject: [PATCH] Switch got to ky --- package-lock.json | 244 +++----------------------------------------- package.json | 2 +- src/bluOs/player.ts | 21 ++-- src/lastFm.ts | 39 +++++-- src/requestUtil.ts | 18 +--- src/util.ts | 20 ++++ 6 files changed, 79 insertions(+), 265 deletions(-) diff --git a/package-lock.json b/package-lock.json index 55bf37a..1c09950 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@jliuhtonen/nightvision": "^0.2.1", "dotenv": "^16.0.3", - "got": "^12.0.1", + "ky": "^1.2.4", "pino": "^8.20.0", "rxjs": "^7.5.2", "xml-js": "^1.6.11", @@ -28,33 +28,6 @@ "resolved": "https://registry.npmjs.org/@jliuhtonen/nightvision/-/nightvision-0.2.1.tgz", "integrity": "sha512-bsIH00ifHGB9UXdNNgMWF9JrkcMBV0hrKw5xXV0cXe8CAu39sAfHhGXsPbBkR8YW03PcM4XLPZvf5TynzGDvdw==" }, - "node_modules/@sindresorhus/is": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", - "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", - "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", - "dependencies": { - "defer-to-connect": "^2.0.1" - }, - "engines": { - "node": ">=14.16" - } - }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", - "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==" - }, "node_modules/@types/node": { "version": "20.12.7", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", @@ -64,6 +37,12 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/node/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -125,64 +104,6 @@ "ieee754": "^1.2.1" } }, - "node_modules/cacheable-lookup": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", - "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", - "engines": { - "node": ">=14.16" - } - }, - "node_modules/cacheable-request": { - "version": "10.2.14", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", - "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", - "dependencies": { - "@types/http-cache-semantics": "^4.0.2", - "get-stream": "^6.0.1", - "http-cache-semantics": "^4.1.1", - "keyv": "^4.5.3", - "mimic-response": "^4.0.0", - "normalize-url": "^8.0.0", - "responselike": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "engines": { - "node": ">=10" - } - }, "node_modules/dotenv": { "version": "16.4.5", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", @@ -218,66 +139,6 @@ "node": ">=6" } }, - "node_modules/form-data-encoder": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", - "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", - "engines": { - "node": ">= 14.17" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/got": { - "version": "12.6.1", - "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", - "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", - "dependencies": { - "@sindresorhus/is": "^5.2.0", - "@szmarczak/http-timer": "^5.0.1", - "cacheable-lookup": "^7.0.0", - "cacheable-request": "^10.2.8", - "decompress-response": "^6.0.0", - "form-data-encoder": "^2.1.2", - "get-stream": "^6.0.1", - "http2-wrapper": "^2.1.10", - "lowercase-keys": "^3.0.0", - "p-cancelable": "^3.0.0", - "responselike": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" - }, - "node_modules/http2-wrapper": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", - "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.2.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -297,50 +158,15 @@ } ] }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/lowercase-keys": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", - "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "node_modules/ky": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/ky/-/ky-1.2.4.tgz", + "integrity": "sha512-CfSrf4a0yj1n6WgPT6kQNQOopIGLkQzqSAXo05oKByaH7G3SiqW4a8jGox0p9whMXqO49H7ljgigivrMyycAVA==", "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mimic-response": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", - "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/normalize-url": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", - "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sindresorhus/ky?sponsor=1" } }, "node_modules/on-exit-leak-free": { @@ -351,14 +177,6 @@ "node": ">=14.0.0" } }, - "node_modules/p-cancelable": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", - "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", - "engines": { - "node": ">=12.20" - } - }, "node_modules/pino": { "version": "8.20.0", "resolved": "https://registry.npmjs.org/pino/-/pino-8.20.0.tgz", @@ -427,17 +245,6 @@ "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/readable-stream": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", @@ -461,25 +268,6 @@ "node": ">= 12.13.0" } }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" - }, - "node_modules/responselike": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", - "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", - "dependencies": { - "lowercase-keys": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -570,12 +358,6 @@ "node": ">=14.17" } }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, "node_modules/xml-js": { "version": "1.6.11", "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", diff --git a/package.json b/package.json index 850ff74..cd42934 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "dependencies": { "@jliuhtonen/nightvision": "^0.2.1", "dotenv": "^16.0.3", - "got": "^12.0.1", + "ky": "^1.2.4", "pino": "^8.20.0", "rxjs": "^7.5.2", "xml-js": "^1.6.11", diff --git a/src/bluOs/player.ts b/src/bluOs/player.ts index 0595b4a..31758ee 100644 --- a/src/bluOs/player.ts +++ b/src/bluOs/player.ts @@ -1,4 +1,4 @@ -import { got, Response } from "got" +import ky from "ky" import { map, Observable, share, switchMap, tap } from "rxjs" import { xml2js } from "xml-js" import * as zod from "zod" @@ -72,14 +72,19 @@ function fetchBluOsStatus( logger: Logger, statusUrl: string, etag: string | undefined, -): Promise> { +): Promise { logger.debug(`Calling BluOS status API with etag ${etag}`) - return Promise.resolve( - got.get(statusUrl, { - searchParams: { etag, timeout: longPollTimeoutSecs }, - timeout: { request: httpRequestTimeoutMillis }, - }), - ) + const queryObj = { + ...(etag ? { etag } : {}), + timeout: longPollTimeoutSecs.toString(), + } + + return ky + .get(statusUrl, { + searchParams: new URLSearchParams(queryObj), + timeout: httpRequestTimeoutMillis, + }) + .text() } function parseBluOsStatus(bluOsXml: string): StatusQueryResponse { diff --git a/src/lastFm.ts b/src/lastFm.ts index 4b26a66..9f0325b 100644 --- a/src/lastFm.ts +++ b/src/lastFm.ts @@ -1,10 +1,15 @@ -import got from "../node_modules/got/dist/source/index.js" +import ky from "ky" import { URLSearchParams } from "url" import * as zod from "zod" import crypto from "node:crypto" import { Logger } from "pino" import { z } from "zod" -import { knownValue, MaybeUnknown, unknownValue } from "./util.js" +import { + asUrlEncodedFormData, + knownValue, + MaybeUnknown, + unknownValue, +} from "./util.js" const baseUrl = "https://ws.audioscrobbler.com/2.0" @@ -28,7 +33,7 @@ export async function getAuthToken(apiKey: string): Promise { api_key: apiKey, format: "json", } - const response = await got(baseUrl, { searchParams }).json() + const response = await ky(baseUrl, { searchParams }).json() return tokenResponse.parse(response).token } @@ -47,7 +52,7 @@ export async function getSession( api_sig: apiSignature, format: "json", } - const response = await got(baseUrl, { searchParams }).json() + const response = await ky(baseUrl, { searchParams }).json() const parsedSession = sessionResponse.parse(response) config.logger.info({ msg: "Fetched Last.Fm session" }) return parsedSession.session.key @@ -78,13 +83,20 @@ export async function scrobbleTrack( sk: sessionKey, } - const body = { + const body = asUrlEncodedFormData({ ...callParams, api_sig: createApiSignature(callParams, config.apiSecret), format: "json", - } + }) - const response = await got.post(baseUrl, { form: body }).json() + const response = await ky + .post(baseUrl, { + body, + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + }) + .json() const maybeResponse = scrobblesResponse.safeParse(response) if (maybeResponse.success) { return knownValue(maybeResponse.data) @@ -113,13 +125,20 @@ export async function nowPlaying( sk: sessionKey, } - const body = { + const body = asUrlEncodedFormData({ ...callParams, api_sig: createApiSignature(callParams, config.apiSecret), format: "json", - } + }) - const response = await got.post(baseUrl, { form: body }).json() + const response = await ky + .post(baseUrl, { + body, + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + }) + .json() const playingResponse = nowPlayingResponse.safeParse(response) if (playingResponse.success) { return knownValue(playingResponse.data) diff --git a/src/requestUtil.ts b/src/requestUtil.ts index 8060a21..3fca626 100644 --- a/src/requestUtil.ts +++ b/src/requestUtil.ts @@ -1,20 +1,8 @@ -import { Response } from "got" -import { Observable, defer, switchMap, throwError, of, retry } from "rxjs" +import { Observable, defer, retry } from "rxjs" export function asRetryable( - fn: () => Promise>, + fn: () => Promise, delayMillis = 10000, ): Observable { - return defer(fn).pipe( - switchMap((response) => { - if (!response.ok) { - return throwError( - () => new Error(`Non-ok status code ${response.statusCode}`), - ) - } - - return of(response.body) - }), - retry({ delay: delayMillis }), - ) + return defer(fn).pipe(retry({ delay: delayMillis })) } diff --git a/src/util.ts b/src/util.ts index aff4f7b..d768b8a 100644 --- a/src/util.ts +++ b/src/util.ts @@ -20,3 +20,23 @@ export const omit = ( return newObj } + +const asFormData = (obj: Record): FormData => { + const formData = new FormData() + + for (const [key, value] of Object.entries(obj)) { + formData.append(key, value) + } + + return formData +} + +export const asUrlEncodedFormData = ( + obj: Record, +): URLSearchParams => + new URLSearchParams( + [...asFormData(obj).entries()].map(([k, v]): [string, string] => [ + k, + v.toString(), + ]), + )