From f627a8e9db5fb6e359cd4bff5f4556be534147cb Mon Sep 17 00:00:00 2001 From: fallenbagel <98979876+fallenbagel@users.noreply.github.com> Date: Tue, 27 Jan 2026 00:52:44 +0500 Subject: [PATCH] refactor(api): replace plex-api package with internal implementation (#2335) Removes plex-api dependency and its type declarations. Then extends the ExternalApi class for PlexAPI implementation to mimick the exact same old behaviour. This should resolve the security vulnerabilities in transitive dependencies: form-data(critical), request (moderate, deprecated), tough-cookie (moderate), xml2js (moderate). Plex-api itself is also no longer maintained. --- package.json | 1 - pnpm-lock.yaml | 205 ------------------------------------- server/api/externalapi.ts | 2 + server/api/plexapi.ts | 104 +++++++++---------- server/types/plex-api.d.ts | 33 ------ 5 files changed, 51 insertions(+), 294 deletions(-) delete mode 100644 server/types/plex-api.d.ts diff --git a/package.json b/package.json index 6a1bb111..5513948d 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,6 @@ "nodemailer": "6.10.0", "openpgp": "6.3.0", "pg": "8.16.3", - "plex-api": "5.3.2", "pug": "3.0.3", "react": "^18.3.1", "react-ace": "10.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 41dac3d6..48a3eecc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -140,9 +140,6 @@ importers: pg: specifier: 8.16.3 version: 8.16.3 - plex-api: - specifier: 5.3.2 - version: 5.3.2 pug: specifier: 3.0.3 version: 3.0.3 @@ -5434,10 +5431,6 @@ packages: forever-agent@0.6.1: resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} - form-data@2.3.3: - resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} - engines: {node: '>= 0.12'} - form-data@4.0.5: resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} @@ -5659,15 +5652,6 @@ packages: engines: {node: '>=0.4.7'} hasBin: true - har-schema@2.0.0: - resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==} - engines: {node: '>=4'} - - har-validator@5.1.5: - resolution: {integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==} - engines: {node: '>=6'} - deprecated: this library is no longer supported - hard-rejection@2.1.0: resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} engines: {node: '>=6'} @@ -5790,10 +5774,6 @@ packages: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} - http-signature@1.2.0: - resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==} - engines: {node: '>=0.8', npm: '>=1.3.7'} - http-signature@1.4.0: resolution: {integrity: sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg==} engines: {node: '>=0.10'} @@ -6375,10 +6355,6 @@ packages: resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} engines: {'0': node >= 0.2.0} - jsprim@1.4.2: - resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==} - engines: {node: '>=0.6.0'} - jsprim@2.0.2: resolution: {integrity: sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==} engines: {'0': node >=0.6.0} @@ -7213,9 +7189,6 @@ packages: nullthrows@1.1.1: resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} - oauth-sign@0.9.0: - resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==} - ob1@0.80.12: resolution: {integrity: sha512-VMArClVT6LkhUGpnuEoBuyjG9rzUyEzg4PDkav6wK1cLhOK02gPCYFxoiB4mqVnrMhDpIzJcrGNAMVi9P+hXrw==} engines: {node: '>=18'} @@ -7520,18 +7493,6 @@ packages: resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==} engines: {node: '>=6'} - plex-api-credentials@3.0.1: - resolution: {integrity: sha512-E0PdSVSqE5rmdEFNsIvFPDJQZPdBX7UR4sgkm9HF4V8VNbX0N4elASnMuoste8i9eTh4hCIqt761NQfzl45XnQ==} - engines: {node: '>=4.0'} - - plex-api-headers@1.1.0: - resolution: {integrity: sha512-Igl37++MSa+4H8LNP3Ene9GU0e1YypmXvFVNvVUwoAx44e74jbUlJXy4Q5rLSBisn0O2lBKdE6VkFIwrDl+UnQ==} - engines: {node: '>=0.10'} - - plex-api@5.3.2: - resolution: {integrity: sha512-RCFMQKu1cx+G4Y/8NfaifWEWEyhFFUV/d1/qAD4O1Si/IeA1S4hueC9py0uzFKR2iz+knuEPtVXtq9Upc9GImg==} - engines: {node: '>=8.0'} - plimit-lit@1.6.1: resolution: {integrity: sha512-B7+VDyb8Tl6oMJT9oSO2CW8XC/T4UcJGrwOVoNGwOQsQYhlpfajmrMj5xeejqaASq3V/EqThyOeATEOMuSEXiA==} engines: {node: '>=12'} @@ -7752,9 +7713,6 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - psl@1.15.0: - resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} - pstree.remy@1.1.8: resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} @@ -7827,10 +7785,6 @@ packages: resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==} engines: {node: '>=0.6'} - qs@6.5.3: - resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==} - engines: {node: '>=0.6'} - querystring@0.2.1: resolution: {integrity: sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==} engines: {node: '>=0.4.x'} @@ -8145,24 +8099,6 @@ packages: request-progress@3.0.0: resolution: {integrity: sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==} - request-promise-core@1.1.2: - resolution: {integrity: sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==} - engines: {node: '>=0.10.0'} - peerDependencies: - request: ^2.34 - - request-promise@4.2.4: - resolution: {integrity: sha512-8wgMrvE546PzbR5WbYxUQogUnUDfM0S7QIFZMID+J73vdFARkFy+HElj4T+MWYhpXwlLp0EQ8Zoj8xUA0he4Vg==} - engines: {node: '>=0.10.0'} - deprecated: request-promise has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142 - peerDependencies: - request: ^2.34 - - request@2.88.2: - resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==} - engines: {node: '>= 6'} - deprecated: request has been deprecated, see https://github.com/request/request/issues/3142 - require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -8599,10 +8535,6 @@ packages: resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} - stealthy-require@1.1.1: - resolution: {integrity: sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==} - engines: {node: '>=0.10.0'} - stop-iteration-iterator@1.1.0: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} @@ -8899,10 +8831,6 @@ packages: resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==} hasBin: true - tough-cookie@2.5.0: - resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==} - engines: {node: '>=0.8'} - tough-cookie@5.1.2: resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} engines: {node: '>=16'} @@ -9289,11 +9217,6 @@ packages: resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} hasBin: true - uuid@3.4.0: - resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} - deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. - hasBin: true - uuid@8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true @@ -9488,12 +9411,6 @@ packages: utf-8-validate: optional: true - xml2js@0.4.16: - resolution: {integrity: sha512-9rH7UTUNphxeDRCeJBi4Fxp/z0fd92WeXNQ1dtUYMpqO3PaK59hVDCuUmOGHRZvufJDzcX8TG+Kdty7ylM0t2w==} - - xml2js@0.4.19: - resolution: {integrity: sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==} - xml2js@0.4.23: resolution: {integrity: sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==} engines: {node: '>=4.0.0'} @@ -9502,14 +9419,6 @@ packages: resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} engines: {node: '>=4.0'} - xmlbuilder@4.2.1: - resolution: {integrity: sha512-oEePiEefhQhAeUnwRnIBLBWmk/fsWWbQ53EEWsRuzECbQ3m5o/Esmq6H47CYYwSLW+Ynt0rS9hd0pd2ogMAWjg==} - engines: {node: '>=0.8.0'} - - xmlbuilder@9.0.7: - resolution: {integrity: sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ==} - engines: {node: '>=4.0'} - xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} @@ -16259,12 +16168,6 @@ snapshots: forever-agent@0.6.1: {} - form-data@2.3.3: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - form-data@4.0.5: dependencies: asynckit: 0.4.0 @@ -16552,13 +16455,6 @@ snapshots: uglify-js: 3.19.3 optional: true - har-schema@2.0.0: {} - - har-validator@5.1.5: - dependencies: - ajv: 6.12.6 - har-schema: 2.0.0 - hard-rejection@2.1.0: {} has-bigints@1.0.2: {} @@ -16702,12 +16598,6 @@ snapshots: transitivePeerDependencies: - supports-color - http-signature@1.2.0: - dependencies: - assert-plus: 1.0.0 - jsprim: 1.4.2 - sshpk: 1.18.0 - http-signature@1.4.0: dependencies: assert-plus: 1.0.0 @@ -17306,13 +17196,6 @@ snapshots: jsonparse@1.3.1: {} - jsprim@1.4.2: - dependencies: - assert-plus: 1.0.0 - extsprintf: 1.3.0 - json-schema: 0.4.0 - verror: 1.10.0 - jsprim@2.0.2: dependencies: assert-plus: 1.0.0 @@ -18416,8 +18299,6 @@ snapshots: nullthrows@1.1.1: {} - oauth-sign@0.9.0: {} - ob1@0.80.12: dependencies: flow-enums-runtime: 0.0.6 @@ -18718,25 +18599,6 @@ snapshots: dependencies: find-up: 3.0.0 - plex-api-credentials@3.0.1(request@2.88.2): - dependencies: - bluebird: 3.7.2 - plex-api-headers: 1.1.0 - request-promise: 4.2.4(request@2.88.2) - xml2js: 0.4.19 - transitivePeerDependencies: - - request - - plex-api-headers@1.1.0: {} - - plex-api@5.3.2: - dependencies: - plex-api-credentials: 3.0.1(request@2.88.2) - plex-api-headers: 1.1.0 - request: 2.88.2 - uuid: 3.4.0 - xml2js: 0.4.16 - plimit-lit@1.6.1: dependencies: queue-lit: 1.5.2 @@ -18909,10 +18771,6 @@ snapshots: proxy-from-env@1.1.0: {} - psl@1.15.0: - dependencies: - punycode: 2.3.1 - pstree.remy@1.1.8: {} pug-attrs@3.0.0: @@ -19011,8 +18869,6 @@ snapshots: dependencies: side-channel: 1.1.0 - qs@6.5.3: {} - querystring@0.2.1: {} queue-lit@1.5.2: {} @@ -19523,42 +19379,6 @@ snapshots: dependencies: throttleit: 1.0.1 - request-promise-core@1.1.2(request@2.88.2): - dependencies: - lodash: 4.17.21 - request: 2.88.2 - - request-promise@4.2.4(request@2.88.2): - dependencies: - bluebird: 3.7.2 - request: 2.88.2 - request-promise-core: 1.1.2(request@2.88.2) - stealthy-require: 1.1.1 - tough-cookie: 2.5.0 - - request@2.88.2: - dependencies: - aws-sign2: 0.7.0 - aws4: 1.13.2 - caseless: 0.12.0 - combined-stream: 1.0.8 - extend: 3.0.2 - forever-agent: 0.6.1 - form-data: 2.3.3 - har-validator: 5.1.5 - http-signature: 1.2.0 - is-typedarray: 1.0.0 - isstream: 0.1.2 - json-stringify-safe: 5.0.1 - mime-types: 2.1.35 - oauth-sign: 0.9.0 - performance-now: 2.1.0 - qs: 6.5.3 - safe-buffer: 5.2.1 - tough-cookie: 2.5.0 - tunnel-agent: 0.6.0 - uuid: 3.4.0 - require-directory@2.1.1: {} require-from-string@2.0.2: {} @@ -20070,8 +19890,6 @@ snapshots: statuses@2.0.2: {} - stealthy-require@1.1.1: {} - stop-iteration-iterator@1.1.0: dependencies: es-errors: 1.3.0 @@ -20392,11 +20210,6 @@ snapshots: touch@3.1.1: {} - tough-cookie@2.5.0: - dependencies: - psl: 1.15.0 - punycode: 2.3.1 - tough-cookie@5.1.2: dependencies: tldts: 6.1.86 @@ -20776,8 +20589,6 @@ snapshots: uuid@11.1.0: {} - uuid@3.4.0: {} - uuid@8.3.2: {} uuid@9.0.1: @@ -21044,16 +20855,6 @@ snapshots: ws@7.5.10: {} - xml2js@0.4.16: - dependencies: - sax: 1.4.1 - xmlbuilder: 4.2.1 - - xml2js@0.4.19: - dependencies: - sax: 1.4.1 - xmlbuilder: 9.0.7 - xml2js@0.4.23: dependencies: sax: 1.4.1 @@ -21061,12 +20862,6 @@ snapshots: xmlbuilder@11.0.1: {} - xmlbuilder@4.2.1: - dependencies: - lodash: 4.17.21 - - xmlbuilder@9.0.7: {} - xtend@4.0.2: {} y18n@4.0.3: {} diff --git a/server/api/externalapi.ts b/server/api/externalapi.ts index f25fc547..db9addcd 100644 --- a/server/api/externalapi.ts +++ b/server/api/externalapi.ts @@ -13,6 +13,7 @@ const DEFAULT_ROLLING_BUFFER = 10000; export interface ExternalAPIOptions { nodeCache?: NodeCache; headers?: Record; + timeout?: number; rateLimit?: { maxRPS: number; maxRequests: number; @@ -32,6 +33,7 @@ class ExternalAPI { this.axios = axios.create({ baseURL: baseUrl, params, + timeout: options.timeout, headers: { 'Content-Type': 'application/json', Accept: 'application/json', diff --git a/server/api/plexapi.ts b/server/api/plexapi.ts index 03cdaf66..61720344 100644 --- a/server/api/plexapi.ts +++ b/server/api/plexapi.ts @@ -1,7 +1,14 @@ +import ExternalAPI from '@server/api/externalapi'; import type { Library, PlexSettings } from '@server/lib/settings'; import { getSettings } from '@server/lib/settings'; import logger from '@server/logger'; -import NodePlexAPI from 'plex-api'; + +interface PlexStatusResponse { + MediaContainer: { + machineIdentifier: string; + friendlyName: string; + }; +} export interface PlexLibraryItem { ratingKey: string; @@ -84,9 +91,7 @@ interface PlexMetadataResponse { }; } -class PlexAPI { - private plexClient: NodePlexAPI; - +class PlexAPI extends ExternalAPI { constructor({ plexToken, plexSettings, @@ -97,48 +102,33 @@ class PlexAPI { timeout?: number; }) { const settings = getSettings(); - let settingsPlex: PlexSettings | undefined; - plexSettings - ? (settingsPlex = plexSettings) - : (settingsPlex = getSettings().plex); + const settingsPlex = plexSettings ?? settings.plex; - this.plexClient = new NodePlexAPI({ - hostname: settingsPlex.ip, - port: settingsPlex.port, - https: settingsPlex.useSsl, - timeout: timeout, - token: plexToken ?? undefined, - authenticator: { - authenticate: ( - _plexApi, - cb: (err?: string, token?: string) => void - ) => { - if (!plexToken) { - return cb('Plex Token not found!'); - } - cb(undefined, plexToken); + const protocol = settingsPlex.useSsl ? 'https' : 'http'; + const baseUrl = `${protocol}://${settingsPlex.ip}:${settingsPlex.port}`; + + super( + baseUrl, + {}, + { + timeout, + headers: { + 'X-Plex-Token': plexToken ?? '', + 'X-Plex-Client-Identifier': settings.clientId, + 'X-Plex-Product': 'Seerr', + 'X-Plex-Device-Name': 'Seerr', + 'X-Plex-Platform': 'Seerr', }, - }, - // requestOptions: { - // includeChildren: 1, - // }, - options: { - identifier: settings.clientId, - product: 'Seerr', - deviceName: 'Seerr', - platform: 'Seerr', - }, - }); + } + ); } - public async getStatus() { - return await this.plexClient.query('/'); + public async getStatus(): Promise { + return await this.get('/'); } public async getLibraries(): Promise { - const response = await this.plexClient.query( - '/library/sections' - ); + const response = await this.get('/library/sections'); return response.MediaContainer.Directory; } @@ -187,13 +177,15 @@ class PlexAPI { id: string, { offset = 0, size = 50 }: { offset?: number; size?: number } = {} ): Promise<{ totalSize: number; items: PlexLibraryItem[] }> { - const response = await this.plexClient.query({ - uri: `/library/sections/${id}/all?includeGuids=1`, - extraHeaders: { - 'X-Plex-Container-Start': `${offset}`, - 'X-Plex-Container-Size': `${size}`, - }, - }); + const response = await this.get( + `/library/sections/${id}/all?includeGuids=1`, + { + headers: { + 'X-Plex-Container-Start': `${offset}`, + 'X-Plex-Container-Size': `${size}`, + }, + } + ); return { totalSize: response.MediaContainer.totalSize, @@ -205,7 +197,7 @@ class PlexAPI { key: string, options: { includeChildren?: boolean } = {} ): Promise { - const response = await this.plexClient.query( + const response = await this.get( `/library/metadata/${key}${ options.includeChildren ? '?includeChildren=1' : '' }` @@ -215,7 +207,7 @@ class PlexAPI { } public async getChildrenMetadata(key: string): Promise { - const response = await this.plexClient.query( + const response = await this.get( `/library/metadata/${key}/children` ); @@ -229,15 +221,17 @@ class PlexAPI { }, mediaType: 'movie' | 'show' ): Promise { - const response = await this.plexClient.query({ - uri: `/library/sections/${id}/all?type=${ + const response = await this.get( + `/library/sections/${id}/all?type=${ mediaType === 'show' ? '4' : '1' }&sort=addedAt%3Adesc&addedAt>>=${Math.floor(options.addedAt / 1000)}`, - extraHeaders: { - 'X-Plex-Container-Start': `0`, - 'X-Plex-Container-Size': `500`, - }, - }); + { + headers: { + 'X-Plex-Container-Start': '0', + 'X-Plex-Container-Size': '500', + }, + } + ); return response.MediaContainer.Metadata; } diff --git a/server/types/plex-api.d.ts b/server/types/plex-api.d.ts deleted file mode 100644 index 77be0ff4..00000000 --- a/server/types/plex-api.d.ts +++ /dev/null @@ -1,33 +0,0 @@ -declare module 'plex-api' { - export default class PlexAPI { - constructor(intiialOptions: { - hostname: string; - port: number; - token?: string; - https?: boolean; - timeout?: number; - authenticator: { - authenticate: ( - _plexApi: PlexAPI, - cb: (err?: string, token?: string) => void - ) => void; - }; - options: { - identifier: string; - product: string; - deviceName: string; - platform: string; - }; - requestOptions?: Record; - }); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - query: >( - endpoint: - | string - | { - uri: string; - extraHeaders?: Record; - } - ) => Promise; - } -}