diff --git a/package.json b/package.json index fe1aff3..11ecb46 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "blowfish-cbc": "^1.0.1", "image-size": "^1.1.1", "librespot": "^0.2.4", - "node-fetch": "^3.3.2", + "undici": "^6.19.4", "xmldom-qsa": "^1.1.3" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 35a0308..a5855a9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,9 +17,9 @@ importers: librespot: specifier: ^0.2.4 version: 0.2.4 - node-fetch: - specifier: ^3.3.2 - version: 3.3.2 + undici: + specifier: ^6.19.4 + version: 6.19.4 xmldom-qsa: specifier: ^1.1.3 version: 1.1.3 @@ -266,10 +266,6 @@ packages: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} - data-uri-to-buffer@4.0.1: - resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} - engines: {node: '>= 12'} - debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -353,10 +349,6 @@ packages: fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} - fetch-blob@3.2.0: - resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} - engines: {node: ^12.20 || >= 14.13} - file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -376,10 +368,6 @@ packages: flatted@3.2.9: resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} - formdata-polyfill@4.0.10: - resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} - engines: {node: '>=12.20.0'} - fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -521,14 +509,6 @@ packages: resolution: {integrity: sha512-yBY+qqWSv3dWKGODD6OGE6GnTX7Q2r+4+DfpqxHSHh8x0B4EKP9+wVGLS6U/AM1vxSNNmUEuIV5EGhYwPpfOwQ==} engines: {node: ^18 || ^20 || >= 21} - node-domexception@1.0.0: - resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} - engines: {node: '>=10.5.0'} - - node-fetch@3.3.2: - resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -674,13 +654,13 @@ packages: resolution: {integrity: sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==} engines: {node: '>=14.0'} + undici@6.19.4: + resolution: {integrity: sha512-i3uaEUwNdkRq2qtTRRJb13moW5HWqviu7Vl7oYRYz++uPtGHJj+x7TGjcEuwS5Mt2P4nA0U9dhIX3DdB6JGY0g==} + engines: {node: '>=18.17'} + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - web-streams-polyfill@3.3.2: - resolution: {integrity: sha512-3pRGuxRF5gpuZc0W+EpwQRmCD7gRqcDOMt688KmdlDAgAyaB1XlN0zq2njfDNm44XVdIouE7pZ6GzbdyH47uIQ==} - engines: {node: '>= 8'} - which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -935,8 +915,6 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - data-uri-to-buffer@4.0.1: {} - debug@4.3.4: dependencies: ms: 2.1.2 @@ -1047,11 +1025,6 @@ snapshots: dependencies: reusify: 1.0.4 - fetch-blob@3.2.0: - dependencies: - node-domexception: 1.0.0 - web-streams-polyfill: 3.3.2 - file-entry-cache@6.0.1: dependencies: flat-cache: 3.2.0 @@ -1073,10 +1046,6 @@ snapshots: flatted@3.2.9: {} - formdata-polyfill@4.0.10: - dependencies: - fetch-blob: 3.2.0 - fs.realpath@1.0.0: {} glob-parent@5.1.2: @@ -1208,14 +1177,6 @@ snapshots: node-addon-api@8.1.0: {} - node-domexception@1.0.0: {} - - node-fetch@3.3.2: - dependencies: - data-uri-to-buffer: 4.0.1 - fetch-blob: 3.2.0 - formdata-polyfill: 4.0.10 - once@1.4.0: dependencies: wrappy: 1.0.2 @@ -1342,12 +1303,12 @@ snapshots: dependencies: '@fastify/busboy': 2.1.0 + undici@6.19.4: {} + uri-js@4.4.1: dependencies: punycode: 2.3.1 - web-streams-polyfill@3.3.2: {} - which@2.0.2: dependencies: isexe: 2.0.0 diff --git a/src/streamers/deezer/main.ts b/src/streamers/deezer/main.ts index b808295..b747781 100644 --- a/src/streamers/deezer/main.ts +++ b/src/streamers/deezer/main.ts @@ -1,4 +1,4 @@ -import fetch from 'node-fetch' +import { fetch } from 'undici' import { Album, Artist, @@ -24,7 +24,7 @@ import { parseArtist, parseTrack } from './parse.js' -import { Transform } from 'stream' +import { Readable, Transform } from 'stream' import { Blowfish } from 'blowfish-cbc' interface DeezerOptions { @@ -406,7 +406,7 @@ export default class Deezer implements StreamerWithLogin { }) return { - stream: streamResp.body!.pipe(decryption), + stream: Readable.fromWeb(streamResp.body!).pipe(decryption), mimeType } } diff --git a/src/streamers/qobuz/main.ts b/src/streamers/qobuz/main.ts index e6e7f8b..11e20fc 100644 --- a/src/streamers/qobuz/main.ts +++ b/src/streamers/qobuz/main.ts @@ -1,5 +1,5 @@ import crypto from 'crypto' -import fetch from 'node-fetch' +import { fetch } from 'undici' import { ItemType, StreamerWithLogin, @@ -11,6 +11,7 @@ import { } from '../../types.js' import { DEFAULT_HEADERS } from './constants.js' import { parseAlbum, parseTrack, parseArtist, RawAlbum, RawArtist, RawTrack } from './parse.js' +import { Readable } from 'stream' function headers(token?: string): HeadersInit { const headers: HeadersInit = DEFAULT_HEADERS @@ -182,7 +183,7 @@ export default class Qobuz implements StreamerWithLogin { return { mimeType: trackFileResponse.mime_type, sizeBytes: parseInt(streamResponse.headers.get('Content-Length')), - stream: streamResponse.body + stream: Readable.fromWeb(streamResponse.body!) } } diff --git a/src/streamers/soundcloud/main.ts b/src/streamers/soundcloud/main.ts index e302e7a..faae745 100644 --- a/src/streamers/soundcloud/main.ts +++ b/src/streamers/soundcloud/main.ts @@ -1,4 +1,4 @@ -import fetch, { HeadersInit } from 'node-fetch' +import { fetch, HeadersInit } from 'undici' import { DEFAULT_HEADERS, SC_VERSION } from './constants.js' import { ItemType, @@ -20,6 +20,7 @@ import { RawArtist, ScClient } from './parse.js' +import { Readable } from 'stream' function headers(oauthToken?: string | undefined): HeadersInit { const headers: HeadersInit = DEFAULT_HEADERS @@ -307,8 +308,8 @@ async function getStream( const streamResp = await fetch(json.url) return { mimeType: transcoding.format.mime_type, - sizeBytes: parseInt(streamResp.headers.get('Content-Length')), - stream: streamResp.body + sizeBytes: parseInt(streamResp.headers.get('Content-Length')!), + stream: Readable.fromWeb(streamResp.body!) } } else { const container = transcoding.format.mime_type.split('/')[1].split(';')[0].split('+')[0] diff --git a/src/streamers/soundcloud/parse.ts b/src/streamers/soundcloud/parse.ts index 1de43b7..de45c3b 100644 --- a/src/streamers/soundcloud/parse.ts +++ b/src/streamers/soundcloud/parse.ts @@ -1,6 +1,6 @@ import { Artist, Album, Track } from '../../types.js' import { spawn } from 'child_process' -import fetch from 'node-fetch' +import { fetch } from 'undici' import { imageSize as sizeOf } from 'image-size' import os from 'node:os' import fs from 'node:fs' @@ -9,11 +9,8 @@ import path from 'node:path' async function parseCoverArtwork(url: string) { const resp = await fetch(url) if (!resp.body) throw new Error('No body on image') - const chunks = [] - for await (const chunk of resp.body) { - chunks.push(Buffer.from(chunk)) - } - const dimensions = sizeOf(Buffer.concat(chunks)) + const body = await resp.arrayBuffer() + const dimensions = sizeOf(new Uint8Array(body)) if (!dimensions.width || !dimensions.height) throw new Error(`Couldn't get dimensions`) return { url, diff --git a/src/streamers/tidal/main.ts b/src/streamers/tidal/main.ts index f8af92d..6cc010f 100644 --- a/src/streamers/tidal/main.ts +++ b/src/streamers/tidal/main.ts @@ -1,4 +1,4 @@ -import fetch from 'node-fetch' +import { fetch } from 'undici' import { spawn } from 'child_process' import { ItemType, @@ -21,7 +21,7 @@ import { parseMpd, parseTrack } from './parse.js' -import Stream from 'stream' +import Stream, { Readable } from 'stream' interface TidalOptions { tvToken: string @@ -354,7 +354,7 @@ export default class Tidal implements Streamer { return { mimeType: manifest.mimeType, sizeBytes: parseInt(streamResponse.headers.get('Content-Length')), - stream: streamResponse.body + stream: Readable.fromWeb(streamResponse.body!) } }