@ctrl/plex 1.5.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +3 -2
  2. package/dist/src/alert.d.ts +12 -0
  3. package/dist/src/alert.js +29 -0
  4. package/dist/src/alert.types.d.ts +59 -0
  5. package/dist/src/alert.types.js +1 -0
  6. package/dist/{base → src/base}/partialPlexObject.d.ts +18 -12
  7. package/dist/{base → src/base}/partialPlexObject.js +29 -23
  8. package/dist/{base → src/base}/playable.d.ts +2 -2
  9. package/dist/src/base/playable.js +8 -0
  10. package/dist/{base → src/base}/plexObject.d.ts +8 -1
  11. package/dist/{base → src/base}/plexObject.js +21 -18
  12. package/dist/{baseFunctionality.d.ts → src/baseFunctionality.d.ts} +17 -1
  13. package/dist/{baseFunctionality.js → src/baseFunctionality.js} +7 -15
  14. package/dist/{client.d.ts → src/client.d.ts} +2 -2
  15. package/dist/{client.js → src/client.js} +12 -20
  16. package/dist/src/client.types.js +1 -0
  17. package/dist/src/config.js +35 -0
  18. package/dist/src/exceptions.d.ts +20 -0
  19. package/dist/src/exceptions.js +40 -0
  20. package/dist/src/index.d.ts +12 -0
  21. package/dist/src/index.js +11 -0
  22. package/dist/{library.d.ts → src/library.d.ts} +207 -21
  23. package/dist/{library.js → src/library.js} +348 -132
  24. package/dist/{library.types.d.ts → src/library.types.d.ts} +59 -1
  25. package/dist/src/library.types.js +1 -0
  26. package/dist/{media.d.ts → src/media.d.ts} +16 -4
  27. package/dist/{media.js → src/media.js} +42 -49
  28. package/dist/src/media.types.d.ts +7 -0
  29. package/dist/src/media.types.js +1 -0
  30. package/dist/{myplex.d.ts → src/myplex.d.ts} +16 -6
  31. package/dist/{myplex.js → src/myplex.js} +71 -57
  32. package/dist/src/myplex.types.js +10 -0
  33. package/dist/src/playlist.d.ts +75 -0
  34. package/dist/src/playlist.js +142 -0
  35. package/dist/src/playlist.types.d.ts +17 -0
  36. package/dist/src/playlist.types.js +1 -0
  37. package/dist/{search.d.ts → src/search.d.ts} +4 -3
  38. package/dist/{search.js → src/search.js} +13 -19
  39. package/dist/src/search.types.js +1 -0
  40. package/dist/{server.d.ts → src/server.d.ts} +22 -10
  41. package/dist/{server.js → src/server.js} +65 -50
  42. package/dist/src/server.types.js +1 -0
  43. package/dist/src/settings.d.ts +79 -0
  44. package/dist/src/settings.js +160 -0
  45. package/dist/{util.d.ts → src/util.d.ts} +2 -1
  46. package/dist/{util.js → src/util.js} +8 -12
  47. package/dist/{video.d.ts → src/video.d.ts} +38 -60
  48. package/dist/{video.js → src/video.js} +109 -92
  49. package/dist/{video.types.d.ts → src/video.types.d.ts} +1 -1
  50. package/dist/src/video.types.js +6 -0
  51. package/package.json +46 -44
  52. package/dist/base/playable.js +0 -12
  53. package/dist/client.types.js +0 -2
  54. package/dist/config.js +0 -41
  55. package/dist/index.d.ts +0 -8
  56. package/dist/index.js +0 -23
  57. package/dist/library.types.js +0 -2
  58. package/dist/myplex.types.js +0 -13
  59. package/dist/playlist.d.ts +0 -7
  60. package/dist/playlist.js +0 -19
  61. package/dist/search.types.js +0 -2
  62. package/dist/server.types.js +0 -2
  63. package/dist/video.types.js +0 -9
  64. /package/dist/{client.types.d.ts → src/client.types.d.ts} +0 -0
  65. /package/dist/{config.d.ts → src/config.d.ts} +0 -0
  66. /package/dist/{myplex.types.d.ts → src/myplex.types.d.ts} +0 -0
  67. /package/dist/{search.types.d.ts → src/search.types.d.ts} +0 -0
  68. /package/dist/{server.types.d.ts → src/server.types.d.ts} +0 -0
package/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # @ctrl/plex
2
2
 
3
+ [![npm](https://badgen.net/npm/v/@ctrl/plex)](https://www.npmjs.com/package/@ctrl/plex)
4
+ [![coverage](https://badgen.net/codecov/c/github/scttcper/plex)](https://codecov.io/gh/scttcper/plex)
5
+
3
6
  > A TypeScript [Plex](https://www.plex.tv/) API client based on [pkkid/python-plexapi](https://github.com/pkkid/python-plexapi)
4
7
 
5
8
  ### Install
@@ -71,8 +74,6 @@ and accessing properties normally cannot make requests either.
71
74
 
72
75
  Tests are run against a real instance of plex.
73
76
 
74
- Start docker container [scttcper/plex-with-media](https://hub.docker.com/r/scttcper/plex-with-media)
75
-
76
77
  Setup test environment variables, create a plex account just for testing. Using a real account will break everything
77
78
 
78
79
  ```sh
@@ -0,0 +1,12 @@
1
+ import WebSocket from 'ws';
2
+ import { AlertTypes } from './alert.types.js';
3
+ import { PlexServer } from './server.js';
4
+ export declare class AlertListener {
5
+ private readonly server;
6
+ callback: (data: AlertTypes) => void;
7
+ key: string;
8
+ _ws?: WebSocket;
9
+ constructor(server: PlexServer, callback: (data: AlertTypes) => void);
10
+ run(): Promise<void>;
11
+ stop(): void;
12
+ }
@@ -0,0 +1,29 @@
1
+ import WebSocket from 'ws';
2
+ export class AlertListener {
3
+ constructor(server, callback) {
4
+ this.server = server;
5
+ this.callback = callback;
6
+ this.key = '/:/websockets/notifications';
7
+ }
8
+ async run() {
9
+ const url = this.server.url(this.key, true).toString().replace('http', 'ws');
10
+ this._ws = new WebSocket(url);
11
+ this._ws.on('message', (buffer) => {
12
+ try {
13
+ const data = JSON.parse(buffer.toString());
14
+ this.callback(data.NotificationContainer);
15
+ }
16
+ catch (err) {
17
+ console.error(err);
18
+ }
19
+ });
20
+ return new Promise(resolve => {
21
+ this._ws.on('open', () => {
22
+ resolve();
23
+ });
24
+ });
25
+ }
26
+ stop() {
27
+ this._ws?.close();
28
+ }
29
+ }
@@ -0,0 +1,59 @@
1
+ export interface NotificationContainer<T> {
2
+ NotificationContainer: T;
3
+ }
4
+ export interface ActivityNotification {
5
+ type: 'activity';
6
+ size: number;
7
+ ActivityNotification: Array<{
8
+ event: string;
9
+ uuid: string;
10
+ Activity: {
11
+ uuid: string;
12
+ type: 'library.update.section';
13
+ cancellable: false;
14
+ userID: 1;
15
+ title: string;
16
+ subtitle: string;
17
+ progress: 0;
18
+ };
19
+ }>;
20
+ }
21
+ export interface StatusNotification {
22
+ type: 'status';
23
+ size: number;
24
+ StatusNotification: Array<{
25
+ title: string;
26
+ description: string;
27
+ notificationName: string;
28
+ }>;
29
+ }
30
+ export interface TimelineNotification {
31
+ type: 'timeline';
32
+ size: number;
33
+ TimelineEntry: Array<{
34
+ /** eg com.plexapp.plugins.library */
35
+ identifier: string;
36
+ sectionID: string;
37
+ itemID: string;
38
+ type: number;
39
+ title: string;
40
+ state: number;
41
+ updatedAt: number;
42
+ }>;
43
+ }
44
+ export interface ReachabilityNotification {
45
+ type: 'reachability';
46
+ size: number;
47
+ TimelineEntry: Array<{
48
+ reachability: false;
49
+ }>;
50
+ }
51
+ export interface BackgroundProcessingQueueEventNotification {
52
+ type: 'backgroundProcessingQueue';
53
+ size: number;
54
+ TimelineEntry: Array<{
55
+ queueID: number;
56
+ event: 'queueRegenerated';
57
+ }>;
58
+ }
59
+ export type AlertTypes = ActivityNotification | StatusNotification | TimelineNotification | ReachabilityNotification | BackgroundProcessingQueueEventNotification;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,13 +1,7 @@
1
- import { PlexObject } from './plexObject';
2
- import { SearchResult } from '../search';
1
+ import { SearchResult } from '../search.js';
2
+ import { PlexObject } from './plexObject.js';
3
3
  export declare abstract class PartialPlexObject extends PlexObject {
4
- ratingKey?: string;
5
- title?: string;
6
- type?: string;
7
- year?: number;
8
- librarySectionID?: number;
9
- protected _detailsKey: string;
10
- protected _INCLUDES: {
4
+ _INCLUDES: {
11
5
  checkFiles: number;
12
6
  includeAllConcerts: number;
13
7
  includeBandwidths: number;
@@ -28,6 +22,12 @@ export declare abstract class PartialPlexObject extends PlexObject {
28
22
  includeReviews: number;
29
23
  includeStations: number;
30
24
  };
25
+ ratingKey?: string;
26
+ title?: string;
27
+ type?: string;
28
+ year?: number;
29
+ librarySectionID?: number;
30
+ protected _detailsKey: string;
31
31
  /**
32
32
  * Tell Plex Media Server to performs analysis on it this item to gather
33
33
  * information. Analysis includes:
@@ -99,8 +99,8 @@ export declare abstract class PartialPlexObject extends PlexObject {
99
99
  * @param maxresults Only return the specified number of results (optional).
100
100
  * @param mindate Min datetime to return results from.
101
101
  */
102
- history(maxresults?: number, mindate?: Date): Promise<import("../server.types").HistoryMetadatum[]>;
103
- section(): Promise<import("..").Section>;
102
+ history(maxresults?: number, mindate?: Date): Promise<import("../server.types.js").HistoryMetadatum[]>;
103
+ section(): Promise<import("../library.js").Section>;
104
104
  /**
105
105
  * Delete a media element. This has to be enabled under settings > server > library in plex webui.
106
106
  */
@@ -117,6 +117,7 @@ export declare abstract class PartialPlexObject extends PlexObject {
117
117
  addGenre(genres: string[]): Promise<void>;
118
118
  /** Remove a genre(s). */
119
119
  removeGenre(genres: string[]): Promise<void>;
120
+ getWebURL(base?: string): string;
120
121
  /**
121
122
  * Edit an object.
122
123
  * @param changeObj Obj of settings to edit.
@@ -128,6 +129,12 @@ export declare abstract class PartialPlexObject extends PlexObject {
128
129
  * 'collection.locked': 0}
129
130
  */
130
131
  edit(changeObj: Record<string, string | number>): Promise<void>;
132
+ protected abstract _loadFullData(data: any): void;
133
+ /**
134
+ * Get the Plex Web URL with the correct parameters.
135
+ * Private method to allow overriding parameters from subclasses.
136
+ */
137
+ private _getWebURL;
131
138
  /**
132
139
  * Helper to edit and refresh a tags.
133
140
  * @param tag tag name
@@ -136,5 +143,4 @@ export declare abstract class PartialPlexObject extends PlexObject {
136
143
  * @param remove If this is active remove the tags in items.
137
144
  */
138
145
  private _editTags;
139
- protected abstract _loadFullData(data: any): void;
140
146
  }
@@ -1,14 +1,10 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PartialPlexObject = void 0;
4
- const url_1 = require("url");
5
- const plexObject_1 = require("./plexObject");
6
- const search_1 = require("../search");
7
- const util_1 = require("../util");
8
- class PartialPlexObject extends plexObject_1.PlexObject {
1
+ import { URLSearchParams } from 'url';
2
+ import { SearchResult, searchType } from '../search.js';
3
+ import { getAgentIdentifier, ltrim, tagHelper } from '../util.js';
4
+ import { PlexObject } from './plexObject.js';
5
+ export class PartialPlexObject extends PlexObject {
9
6
  constructor() {
10
7
  super(...arguments);
11
- this._detailsKey = this._buildDetailsKey();
12
8
  this._INCLUDES = {
13
9
  checkFiles: 1,
14
10
  includeAllConcerts: 1,
@@ -30,6 +26,7 @@ class PartialPlexObject extends plexObject_1.PlexObject {
30
26
  includeReviews: 1,
31
27
  includeStations: 1,
32
28
  };
29
+ this._detailsKey = this._buildDetailsKey();
33
30
  }
34
31
  /**
35
32
  * Tell Plex Media Server to performs analysis on it this item to gather
@@ -50,22 +47,21 @@ class PartialPlexObject extends plexObject_1.PlexObject {
50
47
  * 'Skip Intro' button in clients.
51
48
  */
52
49
  async analyze() {
53
- const key = `/${util_1.ltrim(this.key, ['/'])}/analyze`;
50
+ const key = `/${ltrim(this.key, ['/'])}/analyze`;
54
51
  await this.server.query(key, 'put');
55
52
  }
56
53
  /**
57
54
  * load full data / reload the data for this object from this.key.
58
55
  */
59
56
  async reload(ekey, args) {
60
- var _a;
61
57
  this._detailsKey = this._buildDetailsKey(args);
62
- const key = (_a = ekey !== null && ekey !== void 0 ? ekey : this._detailsKey) !== null && _a !== void 0 ? _a : this.key;
58
+ const key = ekey ?? this._detailsKey ?? this.key;
63
59
  if (!key) {
64
60
  throw new Error('Cannot reload an object not built from a URL');
65
61
  }
66
62
  this.initpath = key;
67
63
  const data = await this.server.query(key);
68
- const innerData = data.MediaContainer ? data.MediaContainer : data;
64
+ const innerData = data.MediaContainer ?? data;
69
65
  this._loadFullData(innerData);
70
66
  }
71
67
  /**
@@ -97,7 +93,7 @@ class PartialPlexObject extends plexObject_1.PlexObject {
97
93
  else if (!searchResult) {
98
94
  throw new Error('Must either provide a searchResult or set auto parameter to true');
99
95
  }
100
- const params = new url_1.URLSearchParams({ guid: searchResult.guid, name: searchResult.name });
96
+ const params = new URLSearchParams({ guid: searchResult.guid, name: searchResult.name });
101
97
  const url = `${key}?${params.toString()}`;
102
98
  await this.server.query(url, 'put');
103
99
  }
@@ -129,11 +125,11 @@ class PartialPlexObject extends plexObject_1.PlexObject {
129
125
  */
130
126
  async matches(agent, title, year, language) {
131
127
  const key = `/library/metadata/${this.ratingKey}/matches`;
132
- const params = new url_1.URLSearchParams({ manual: '1' });
128
+ const params = new URLSearchParams({ manual: '1' });
133
129
  if (agent && [title, year, language].some(x => x)) {
134
130
  const section = await this.section();
135
131
  params.append('language', section.language);
136
- const ident = await util_1.getAgentIdentifier(section, agent);
132
+ const ident = await getAgentIdentifier(section, agent);
137
133
  params.append('agent', ident);
138
134
  }
139
135
  else if ([agent, title, year, language].some(x => x)) {
@@ -165,7 +161,7 @@ class PartialPlexObject extends plexObject_1.PlexObject {
165
161
  }
166
162
  }
167
163
  const data = await this.server.query(`${key}?${params.toString()}`, 'get');
168
- return data.MediaContainer.SearchResult.map(r => new search_1.SearchResult(this.server, r));
164
+ return data.MediaContainer.SearchResult.map(r => new SearchResult(this.server, r));
169
165
  }
170
166
  /** Unmatches metadata match from object. */
171
167
  async unmatch() {
@@ -213,6 +209,9 @@ class PartialPlexObject extends plexObject_1.PlexObject {
213
209
  async removeGenre(genres) {
214
210
  await this._editTags('genre', genres, undefined, true);
215
211
  }
212
+ getWebURL(base) {
213
+ return this._getWebURL(base);
214
+ }
216
215
  /**
217
216
  * Edit an object.
218
217
  * @param changeObj Obj of settings to edit.
@@ -237,13 +236,22 @@ class PartialPlexObject extends plexObject_1.PlexObject {
237
236
  changeObj.id = this.ratingKey;
238
237
  }
239
238
  if (changeObj.type === undefined) {
240
- changeObj.type = search_1.searchType(this.type);
239
+ changeObj.type = searchType(this.type);
241
240
  }
242
241
  const strObj = Object.fromEntries(Object.entries(changeObj).map(([key, value]) => [key, value.toString()]));
243
- const params = new url_1.URLSearchParams(strObj);
242
+ const params = new URLSearchParams(strObj);
244
243
  const url = this.server.url(`/library/sections/${this.librarySectionID}/all`, true, params);
245
244
  await this.server.query(url.toString(), 'put');
246
245
  }
246
+ /**
247
+ * Get the Plex Web URL with the correct parameters.
248
+ * Private method to allow overriding parameters from subclasses.
249
+ */
250
+ _getWebURL(base) {
251
+ const params = new URLSearchParams();
252
+ params.append('key', this.key);
253
+ return this.server._buildWebURL(base, 'details', params);
254
+ }
247
255
  /**
248
256
  * Helper to edit and refresh a tags.
249
257
  * @param tag tag name
@@ -252,12 +260,10 @@ class PartialPlexObject extends plexObject_1.PlexObject {
252
260
  * @param remove If this is active remove the tags in items.
253
261
  */
254
262
  async _editTags(tag, items, locked = true, remove = false) {
255
- var _a;
256
263
  const value = this[tag + 's'];
257
- const existingCols = (_a = value === null || value === void 0 ? void 0 : value.filter(x => x && remove).map(x => x.tag)) !== null && _a !== void 0 ? _a : [];
258
- const d = util_1.tagHelper(tag, [...existingCols, ...items], locked, remove);
264
+ const existingCols = value?.filter((x) => x && remove).map((x) => x.tag) ?? [];
265
+ const d = tagHelper(tag, [...existingCols, ...items], locked, remove);
259
266
  await this.edit(d);
260
267
  await this.reload();
261
268
  }
262
269
  }
263
- exports.PartialPlexObject = PartialPlexObject;
@@ -1,4 +1,4 @@
1
- import { PartialPlexObject } from './partialPlexObject';
1
+ import { PartialPlexObject } from './partialPlexObject.js';
2
2
  /**
3
3
  * This is a general place to store functions specific to media that is Playable.
4
4
  * Things were getting mixed up a bit when dealing with Shows, Season, Artists,
@@ -18,5 +18,5 @@ export declare abstract class Playable extends PartialPlexObject {
18
18
  /** (datetime): Datetime item was last viewed (history). */
19
19
  viewedAt: any;
20
20
  /** (int): Playlist item ID (only populated for :class:`~plexapi.playlist.Playlist` items). */
21
- playlistItemID: any;
21
+ playlistItemID?: number;
22
22
  }
@@ -0,0 +1,8 @@
1
+ import { PartialPlexObject } from './partialPlexObject.js';
2
+ /**
3
+ * This is a general place to store functions specific to media that is Playable.
4
+ * Things were getting mixed up a bit when dealing with Shows, Season, Artists,
5
+ * Albums which are all not playable.
6
+ */
7
+ export class Playable extends PartialPlexObject {
8
+ }
@@ -1,4 +1,4 @@
1
- import type { PlexServer } from '../server';
1
+ import type { PlexServer } from '../server.js';
2
2
  /**
3
3
  * Base class for all? Plex objects
4
4
  */
@@ -22,6 +22,13 @@ export declare abstract class PlexObject {
22
22
  * Reload the data for this object from this.key.
23
23
  */
24
24
  reload(ekey?: string): Promise<void>;
25
+ /**
26
+ * Refreshing a Library or individual item causes the metadata for the item to be
27
+ * refreshed, even if it already has metadata. You can think of refreshing as
28
+ * "update metadata for the requested item even if it already has some". You should
29
+ * refresh a Library or individual item if:
30
+ */
31
+ refresh(): Promise<void>;
25
32
  /**
26
33
  * Returns True if this object is a child of the given class.
27
34
  */
@@ -1,14 +1,15 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PlexObject = void 0;
4
- const url_1 = require("url");
1
+ import { URLSearchParams } from 'url';
5
2
  /**
6
3
  * Base class for all? Plex objects
7
4
  */
8
- class PlexObject {
5
+ export class PlexObject {
6
+ /** xml element tag */
7
+ static { this.TAG = null; }
8
+ /** xml element type */
9
+ static { this.TYPE = null; }
9
10
  constructor(server, data, initpath, parent) {
10
11
  this.server = server;
11
- this.initpath = initpath !== null && initpath !== void 0 ? initpath : this.key;
12
+ this.initpath = initpath ?? this.key;
12
13
  this.parent = parent ? new WeakRef(parent) : undefined;
13
14
  this._loadData(data);
14
15
  this._detailsKey = this._buildDetailsKey();
@@ -17,8 +18,7 @@ class PlexObject {
17
18
  * Reload the data for this object from this.key.
18
19
  */
19
20
  async reload(ekey) {
20
- var _a;
21
- const key = (_a = ekey !== null && ekey !== void 0 ? ekey : this._detailsKey) !== null && _a !== void 0 ? _a : this.key;
21
+ const key = ekey ?? this._detailsKey ?? this.key;
22
22
  if (!key) {
23
23
  throw new Error('Cannot reload an object not built from a URL');
24
24
  }
@@ -26,21 +26,29 @@ class PlexObject {
26
26
  const innerData = data.MediaContainer ? data.MediaContainer : data;
27
27
  this._loadData(innerData);
28
28
  }
29
+ /**
30
+ * Refreshing a Library or individual item causes the metadata for the item to be
31
+ * refreshed, even if it already has metadata. You can think of refreshing as
32
+ * "update metadata for the requested item even if it already has some". You should
33
+ * refresh a Library or individual item if:
34
+ */
35
+ async refresh() {
36
+ const key = `${this.key}/refresh`;
37
+ await this.server.query(key, 'put');
38
+ }
29
39
  /**
30
40
  * Returns True if this object is a child of the given class.
31
41
  */
32
42
  isChildOf(cls) {
33
- var _a;
34
- const parent = (_a = this.parent) === null || _a === void 0 ? void 0 : _a.deref();
43
+ const parent = this.parent?.deref();
35
44
  return (parent && parent.constructor === cls.constructor) || false;
36
45
  }
37
46
  _buildDetailsKey(args = {}) {
38
- var _a;
39
47
  let detailsKey = this.key;
40
48
  if (detailsKey && this._INCLUDES !== undefined) {
41
- const params = new url_1.URLSearchParams();
49
+ const params = new URLSearchParams();
42
50
  for (const [k, v] of Object.entries(this._INCLUDES)) {
43
- let value = (_a = args[k]) !== null && _a !== void 0 ? _a : v;
51
+ const value = args[k] ?? v;
44
52
  if (![false, 0, '0'].includes(value)) {
45
53
  params.set(k, (value === true ? 1 : value).toString());
46
54
  }
@@ -52,8 +60,3 @@ class PlexObject {
52
60
  return detailsKey;
53
61
  }
54
62
  }
55
- exports.PlexObject = PlexObject;
56
- /** xml element tag */
57
- PlexObject.TAG = null;
58
- /** xml element type */
59
- PlexObject.TYPE = null;
@@ -1,4 +1,20 @@
1
- import type { PlexServer } from './server';
1
+ import type { PlexServer } from './server.js';
2
+ export declare const OPERATORS: {
3
+ readonly exact: (v: string | number, q: string | number) => boolean;
4
+ readonly iexact: (v: string, q: string) => boolean;
5
+ readonly contains: (v: string, q: string) => boolean;
6
+ readonly icontains: (v: string, q: string) => boolean;
7
+ readonly ne: (v: string, q: string) => boolean;
8
+ readonly in: (v: string, q: any) => boolean;
9
+ readonly gt: (v: number, q: number) => boolean;
10
+ readonly gte: (v: number, q: number) => boolean;
11
+ readonly lt: (v: number, q: number) => boolean;
12
+ readonly lte: (v: number, q: number) => boolean;
13
+ readonly startswith: (v: string, q: string) => boolean;
14
+ readonly istartswith: (v: string, q: string) => boolean;
15
+ readonly endswith: (v: string, q: string) => boolean;
16
+ readonly iendswith: (v: string, q: string) => boolean;
17
+ };
2
18
  /**
3
19
  * Load the specified key to find and build the first item with the
4
20
  * specified tag and attrs. If no tag or attrs are specified then
@@ -1,7 +1,4 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.findItems = exports.fetchItems = exports.fetchItem = void 0;
4
- const OPERATORS = {
1
+ export const OPERATORS = {
5
2
  exact: (v, q) => v === q,
6
3
  iexact: (v, q) => v.toLowerCase() === q.toLowerCase(),
7
4
  contains: (v, q) => q.includes(v),
@@ -29,12 +26,11 @@ const OPERATORS = {
29
26
  * in, the key will be translated to /library/metadata/<key>. This allows
30
27
  * fetching an item only knowing its key-id.
31
28
  */
32
- async function fetchItem(server, ekey, options, cls) {
33
- var _a, _b;
29
+ export async function fetchItem(server, ekey, options, cls) {
34
30
  const key = typeof ekey === 'number' ? `/library/metadata/${ekey.toString()}` : ekey;
35
31
  const response = await server.query(key);
36
- const containerKey = (_a = cls === null || cls === void 0 ? void 0 : cls.TAG) !== null && _a !== void 0 ? _a : 'Metadata';
37
- const elems = (_b = response.MediaContainer[containerKey]) !== null && _b !== void 0 ? _b : [];
32
+ const containerKey = cls?.TAG ?? 'Metadata';
33
+ const elems = response.MediaContainer[containerKey] ?? [];
38
34
  for (const elem of elems) {
39
35
  if (checkAttrs(elem, options)) {
40
36
  return elem;
@@ -42,27 +38,24 @@ async function fetchItem(server, ekey, options, cls) {
42
38
  }
43
39
  throw new Error('Unable to find item');
44
40
  }
45
- exports.fetchItem = fetchItem;
46
41
  /**
47
42
  * Load the specified key to find and build all items with the specified tag
48
43
  * and attrs. See :func:`~plexapi.base.PlexObject.fetchItem` for more details
49
44
  * on how this is used.
50
45
  */
51
- async function fetchItems(server, ekey, options, Cls, parent) {
52
- var _a, _b;
46
+ export async function fetchItems(server, ekey, options, Cls, parent) {
53
47
  const response = await server.query(ekey);
54
48
  const { MediaContainer } = response;
55
- const elems = (_b = (_a = MediaContainer[Cls === null || Cls === void 0 ? void 0 : Cls.TAG]) !== null && _a !== void 0 ? _a : MediaContainer.Metadata) !== null && _b !== void 0 ? _b : [];
49
+ const elems = MediaContainer[Cls?.TAG] ?? MediaContainer.Metadata ?? [];
56
50
  const items = findItems(elems, options, Cls, server, parent);
57
51
  return items;
58
52
  }
59
- exports.fetchItems = fetchItems;
60
53
  /**
61
54
  * Load the specified data to find and build all items with the specified tag
62
55
  * and attrs. See :func:`~plexapi.base.PlexObject.fetchItem` for more details
63
56
  * on how this is used.
64
57
  */
65
- function findItems(data, options = {}, Cls, server, parent) {
58
+ export function findItems(data, options = {}, Cls, server, parent) {
66
59
  // if (Cls?.TAG && !('tag' in options)) {
67
60
  // options.etag = Cls.TAG;
68
61
  // }
@@ -77,7 +70,6 @@ function findItems(data, options = {}, Cls, server, parent) {
77
70
  }
78
71
  return items;
79
72
  }
80
- exports.findItems = findItems;
81
73
  function checkAttrs(elem, obj = {}) {
82
74
  const attrsFound = {};
83
75
  for (const [attr, query] of Object.entries(obj)) {
@@ -1,6 +1,6 @@
1
- /// <reference types="node" />
1
+ /// <reference types="node" resolution-mode="require"/>
2
2
  import { URL } from 'url';
3
- import { Player } from './client.types';
3
+ import { Player } from './client.types.js';
4
4
  export interface PlexOptions {
5
5
  /** (:class:`~plexapi.server.PlexServer`): PlexServer this client is connected to (optional). */
6
6
  server?: any;
@@ -1,12 +1,6 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.PlexClient = void 0;
7
- const got_1 = __importDefault(require("got"));
8
- const url_1 = require("url");
9
- const config_1 = require("./config");
1
+ import { URL, URLSearchParams } from 'url';
2
+ import got from 'got';
3
+ import { BASE_HEADERS, TIMEOUT } from './config.js';
10
4
  /**
11
5
  * Main class for interacting with a Plex client. This class can connect
12
6
  * directly to the client and control it or proxy commands through your
@@ -37,9 +31,8 @@ const config_1 = require("./config");
37
31
  * _proxyThroughServer (bool): Set to True after calling
38
32
  * :func:`~plexapi.client.PlexClient.proxyThroughServer()` (default False).
39
33
  */
40
- class PlexClient {
34
+ export class PlexClient {
41
35
  constructor(options = {}) {
42
- var _a, _b;
43
36
  /**
44
37
  * HTTP address of the client
45
38
  */
@@ -58,8 +51,8 @@ class PlexClient {
58
51
  this._baseurl = options.baseurl;
59
52
  }
60
53
  }
61
- this._baseurl = (_a = options.baseurl) !== null && _a !== void 0 ? _a : 'http://localhost:32400';
62
- this._token = (_b = options.token) !== null && _b !== void 0 ? _b : null;
54
+ this._baseurl = options.baseurl ?? 'http://localhost:32400';
55
+ this._token = options.token ?? null;
63
56
  }
64
57
  /**
65
58
  * Alias of reload as any subsequent requests to this client will be
@@ -89,12 +82,12 @@ class PlexClient {
89
82
  */
90
83
  async query(path, method = 'get', headers, timeout) {
91
84
  const headersObj = this.headers(headers);
92
- const response = await got_1.default({
85
+ const response = await got({
93
86
  method,
94
87
  url: this.url(path),
95
- timeout: timeout !== null && timeout !== void 0 ? timeout : config_1.TIMEOUT,
88
+ timeout: { request: timeout ?? TIMEOUT },
96
89
  headers: headersObj,
97
- retry: 0,
90
+ retry: { limit: 0 },
98
91
  }).json();
99
92
  return response;
100
93
  }
@@ -108,9 +101,9 @@ class PlexClient {
108
101
  if (!this._baseurl) {
109
102
  throw new Error('PlexClient object missing baseurl.');
110
103
  }
111
- const url = new url_1.URL(key, this._baseurl);
104
+ const url = new URL(key, this._baseurl);
112
105
  if (this._token && includeToken) {
113
- const searchParams = new url_1.URLSearchParams();
106
+ const searchParams = new URLSearchParams();
114
107
  searchParams.append('X-Plex-Token', this._token);
115
108
  url.search = searchParams.toString();
116
109
  return url;
@@ -133,7 +126,7 @@ class PlexClient {
133
126
  */
134
127
  headers(headers = {}) {
135
128
  const headersObj = {
136
- ...config_1.BASE_HEADERS,
129
+ ...BASE_HEADERS,
137
130
  ...headers,
138
131
  };
139
132
  if (this._token) {
@@ -142,4 +135,3 @@ class PlexClient {
142
135
  return headersObj;
143
136
  }
144
137
  }
145
- exports.PlexClient = PlexClient;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,35 @@
1
+ import os from 'os';
2
+ import { getMAC, parseMAC } from '@ctrl/mac-address';
3
+ // TODO: Load User Defined Config
4
+ // const DEFAULT_CONFIG_PATH = os.path.expanduser('~/.config/plexapi/config.ini');
5
+ // const CONFIG_PATH = os.environ.get('PLEXAPI_CONFIG_PATH', DEFAULT_CONFIG_PATH);
6
+ // const CONFIG = PlexConfig(CONFIG_PATH);
7
+ // PlexAPI Settings
8
+ export const PROJECT = 'PlexAPI';
9
+ export const VERSION = '3.3.0';
10
+ export const TIMEOUT = 30000;
11
+ export const X_PLEX_CONTAINER_SIZE = 100;
12
+ export const X_PLEX_ENABLE_FAST_CONNECT = false;
13
+ // Plex Header Configuation
14
+ export const X_PLEX_PROVIDES = 'controller';
15
+ export const X_PLEX_PLATFORM = os.type();
16
+ export const X_PLEX_PLATFORM_VERSION = os.release();
17
+ export const X_PLEX_PRODUCT = PROJECT;
18
+ export const X_PLEX_VERSION = VERSION;
19
+ export const X_PLEX_DEVICE = X_PLEX_PLATFORM;
20
+ export const X_PLEX_DEVICE_NAME = os.hostname();
21
+ const mac = getMAC();
22
+ const base16Mac = parseMAC(mac).toLong().toString(16);
23
+ export const X_PLEX_IDENTIFIER = `0x${base16Mac}`;
24
+ export const BASE_HEADERS = {
25
+ 'X-Plex-Platform': X_PLEX_PLATFORM,
26
+ 'X-Plex-Platform-Version': X_PLEX_PLATFORM_VERSION,
27
+ 'X-Plex-Provides': X_PLEX_PROVIDES,
28
+ 'X-Plex-Product': X_PLEX_PRODUCT,
29
+ 'X-Plex-Version': X_PLEX_VERSION,
30
+ 'X-Plex-Device': X_PLEX_DEVICE,
31
+ 'X-Plex-Device-Name': X_PLEX_DEVICE_NAME,
32
+ 'X-Plex-Client-Identifier': X_PLEX_IDENTIFIER,
33
+ 'X-Plex-Sync-Version': '2',
34
+ 'X-Plex-Language': 'en',
35
+ };