@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
@@ -0,0 +1,75 @@
1
+ import { Playable } from './base/playable.js';
2
+ import type { Section } from './library.js';
3
+ import { PlaylistResponse } from './playlist.types.js';
4
+ import type { PlexServer } from './server.js';
5
+ import { Episode, Movie, VideoType } from './video.js';
6
+ interface CreateRegularPlaylistOptions {
7
+ /** True to create a smart playlist */
8
+ smart?: false;
9
+ /** Regular playlists only */
10
+ items?: VideoType[];
11
+ }
12
+ interface CreateSmartPlaylistOptions {
13
+ /** True to create a smart playlist */
14
+ smart: true;
15
+ /** Smart playlists only, the library section to create the playlist in. */
16
+ section?: Section;
17
+ /** Smart playlists only, limit the number of items in the playlist. */
18
+ limit?: number;
19
+ /**
20
+ * Smart playlists only, a string of comma separated sort fields
21
+ * or a list of sort fields in the format ``column:dir``.
22
+ * See {@link Section.search} for more info.
23
+ */
24
+ sort?: string;
25
+ /**
26
+ * Smart playlists only, a dictionary of advanced filters.
27
+ * See {@link Section.search} for more info.
28
+ */
29
+ filters?: Record<string, any>;
30
+ }
31
+ type CreatePlaylistOptions = CreateRegularPlaylistOptions | CreateSmartPlaylistOptions;
32
+ type PlaylistContent = Episode | Movie;
33
+ export declare class Playlist extends Playable {
34
+ static TAG: string;
35
+ static create(server: PlexServer, title: string, options: CreatePlaylistOptions): Promise<Playlist>;
36
+ /** Create a smart playlist. */
37
+ private static _create;
38
+ TYPE: string;
39
+ addedAt: Date;
40
+ updatedAt: Date;
41
+ composite: string;
42
+ guid: string;
43
+ leafCount: number;
44
+ playlistType: string;
45
+ smart: boolean;
46
+ summary: string;
47
+ allowSync?: boolean;
48
+ duration?: number;
49
+ durationInSeconds?: number;
50
+ /** Cache of playlist items */
51
+ private _items;
52
+ _edit(args: {
53
+ title?: string;
54
+ summary?: string;
55
+ }): Promise<void>;
56
+ edit(changeObj: {
57
+ title?: string;
58
+ summary?: string;
59
+ }): Promise<void>;
60
+ /**
61
+ * @returns the item in the playlist that matches the specified title.
62
+ */
63
+ item(title: string): Promise<PlaylistContent | null>;
64
+ items(): Promise<PlaylistContent[]>;
65
+ /** Add items to a playlist. */
66
+ addItems(items: PlaylistContent[]): Promise<void>;
67
+ /** Remove an item from a playlist. */
68
+ removeItems(items: PlaylistContent[]): Promise<void>;
69
+ /** Delete the playlist. */
70
+ delete(): Promise<void>;
71
+ protected _loadData(data: PlaylistResponse): void;
72
+ protected _loadFullData(data: any): void;
73
+ private _getPlaylistItemID;
74
+ }
75
+ export {};
@@ -0,0 +1,142 @@
1
+ import { URLSearchParams } from 'url';
2
+ import { Playable } from './base/playable.js';
3
+ import { fetchItems } from './baseFunctionality.js';
4
+ import { BadRequest, NotFound } from './exceptions.js';
5
+ import { Episode, Movie } from './video.js';
6
+ /**
7
+ * Map media types to their respective class
8
+ */
9
+ function contentClass(data) {
10
+ switch (data.type) {
11
+ case 'episode':
12
+ return Episode;
13
+ case 'movie':
14
+ return Movie;
15
+ default:
16
+ throw new Error('Media type not implemented');
17
+ }
18
+ }
19
+ export class Playlist extends Playable {
20
+ constructor() {
21
+ super(...arguments);
22
+ this.TYPE = 'playlist';
23
+ /** Cache of playlist items */
24
+ this._items = null;
25
+ }
26
+ static { this.TAG = 'Playlist'; }
27
+ static async create(server, title, options) {
28
+ if (options.smart) {
29
+ throw new Error('not yet supported');
30
+ // return this._createSmart(server, title, options);
31
+ }
32
+ return this._create(server, title, options.items);
33
+ }
34
+ /** Create a smart playlist. */
35
+ // private static _createSmart(server: PlexServer, title: string, options: CreatePlaylistOptions) {}
36
+ static async _create(server, title, items) {
37
+ if (!items || items.length === 0) {
38
+ throw new BadRequest('Must include items to add when creating new playlist.');
39
+ }
40
+ const { listType } = items[0];
41
+ const ratingKeys = items ? items.map(x => x.ratingKey) : [];
42
+ const uri = `${server._uriRoot()}/library/metadata/${ratingKeys.join(',')}`;
43
+ const params = new URLSearchParams({
44
+ uri,
45
+ type: listType,
46
+ title,
47
+ smart: '0',
48
+ });
49
+ const key = `/playlists?${params.toString()}`;
50
+ const data = await server.query(key, 'post');
51
+ return new Playlist(server, data.MediaContainer.Metadata[0], key);
52
+ }
53
+ async _edit(args) {
54
+ const searchparams = new URLSearchParams(args);
55
+ const key = `${this.key}?${searchparams.toString()}`;
56
+ await this.server.query(key, 'put');
57
+ }
58
+ async edit(changeObj) {
59
+ await this._edit(changeObj);
60
+ }
61
+ /**
62
+ * @returns the item in the playlist that matches the specified title.
63
+ */
64
+ async item(title) {
65
+ const items = await this.items();
66
+ const matched = items.find(item => item.title.toLowerCase() === title.toLowerCase());
67
+ return matched ?? null;
68
+ }
69
+ async items() {
70
+ if (this._items === null) {
71
+ const key = `/playlists/${this.ratingKey}/items`;
72
+ const items = await fetchItems(this.server, key);
73
+ this._items = items.map(data => {
74
+ const Cls = contentClass(data);
75
+ return new Cls(this.server, data, key, this);
76
+ });
77
+ }
78
+ return this._items;
79
+ }
80
+ /** Add items to a playlist. */
81
+ async addItems(items) {
82
+ if (this.smart) {
83
+ throw new BadRequest('Cannot add items to a smart playlist.');
84
+ }
85
+ const isInvalidType = items.some(x => x.listType !== this.playlistType);
86
+ if (isInvalidType) {
87
+ throw new BadRequest('Can not mix media types when building a playlist');
88
+ }
89
+ const ratingKeys = items.map(x => x.ratingKey);
90
+ const params = new URLSearchParams({
91
+ uri: `${this.server._uriRoot()}/library/metadata/${ratingKeys.join(',')}`,
92
+ });
93
+ const key = `${this.key}/items?${params.toString()}`;
94
+ await this.server.query(key, 'put');
95
+ }
96
+ /** Remove an item from a playlist. */
97
+ async removeItems(items) {
98
+ if (this.smart) {
99
+ throw new BadRequest('Cannot remove items to a smart playlist.');
100
+ }
101
+ for (const item of items) {
102
+ // eslint-disable-next-line no-await-in-loop
103
+ const playlistItemId = await this._getPlaylistItemID(item);
104
+ const key = `${this.key}/items/${playlistItemId}`;
105
+ // eslint-disable-next-line no-await-in-loop
106
+ await this.server.query(key, 'delete');
107
+ }
108
+ }
109
+ /** Delete the playlist. */
110
+ async delete() {
111
+ await this.server.query(this.key, 'delete');
112
+ }
113
+ _loadData(data) {
114
+ this.key = data.key.replace('/items', '');
115
+ this.ratingKey = data.ratingKey;
116
+ this.title = data.title;
117
+ this.type = data.type;
118
+ this.addedAt = new Date(data.addedAt);
119
+ this.updatedAt = new Date(data.updatedAt);
120
+ this.composite = data.composite;
121
+ this.guid = data.guid;
122
+ this.playlistType = data.playlistType;
123
+ this.summary = data.summary;
124
+ this.smart = data.smart;
125
+ this.leafCount = data.leafCount;
126
+ // TODO: verify these. Possibly audio playlist related
127
+ this.allowSync = data.allowSync;
128
+ this.duration = data.duration;
129
+ this.durationInSeconds = data.durationInSeconds;
130
+ }
131
+ _loadFullData(data) {
132
+ this._loadData(data.Metadata[0]);
133
+ }
134
+ async _getPlaylistItemID(item) {
135
+ const items = await this.items();
136
+ const playlistItem = items.find(i => i.ratingKey === item.ratingKey);
137
+ if (!playlistItem) {
138
+ throw new NotFound(`Item with title "${item.title}" not found in the playlist`);
139
+ }
140
+ return playlistItem.playlistItemID;
141
+ }
142
+ }
@@ -0,0 +1,17 @@
1
+ export interface PlaylistResponse {
2
+ ratingKey: string;
3
+ key: string;
4
+ guid: string;
5
+ type: string;
6
+ title: string;
7
+ summary: string;
8
+ smart: boolean;
9
+ playlistType: string;
10
+ composite: string;
11
+ leafCount: number;
12
+ addedAt: number;
13
+ updatedAt: number;
14
+ allowSync?: boolean;
15
+ duration?: number;
16
+ durationInSeconds?: number;
17
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,6 @@
1
1
  import { ValueOf } from 'type-fest';
2
- import { PlexObject } from './base/plexObject';
3
- import { MatchSearchResult } from './search.types';
2
+ import { PlexObject } from './base/plexObject.js';
3
+ import { MatchSearchResult } from './search.types.js';
4
4
  export declare class SearchResult extends PlexObject {
5
5
  static TAG: string;
6
6
  guid: string;
@@ -41,9 +41,10 @@ export declare const SEARCHTYPES: {
41
41
  readonly playlist: 15;
42
42
  readonly playlistFolder: 16;
43
43
  readonly collection: 18;
44
+ readonly optimizedVersion: 42;
44
45
  readonly userPlaylistItem: 1001;
45
46
  };
46
- declare type SearchTypesValues = ValueOf<typeof SEARCHTYPES>;
47
+ type SearchTypesValues = ValueOf<typeof SEARCHTYPES>;
47
48
  /**
48
49
  * Returns the integer value of the library string type.
49
50
  * @param libtype to lookup (movie, show, season, episode, artist, album, track, collection)
@@ -1,9 +1,7 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.searchType = exports.SEARCHTYPES = exports.Agent = exports.SearchResult = void 0;
4
- const plexObject_1 = require("./base/plexObject");
5
- const util_1 = require("./util");
6
- class SearchResult extends plexObject_1.PlexObject {
1
+ import { PlexObject } from './base/plexObject.js';
2
+ import { rsplit } from './util.js';
3
+ export class SearchResult extends PlexObject {
4
+ static { this.TAG = 'SearchResult'; }
7
5
  _loadData(data) {
8
6
  this.guid = data.guid;
9
7
  this.lifespanEnded = data.lifespanEnded;
@@ -12,19 +10,18 @@ class SearchResult extends plexObject_1.PlexObject {
12
10
  this.year = data.year;
13
11
  }
14
12
  }
15
- exports.SearchResult = SearchResult;
16
- SearchResult.TAG = 'SearchResult';
17
13
  /**
18
14
  * Represents a single Agent
19
15
  */
20
- class Agent extends plexObject_1.PlexObject {
16
+ export class Agent extends PlexObject {
17
+ static { this.TAG = 'Agent'; }
21
18
  // languageCode: any[] = [];
22
19
  _loadData(data) {
23
20
  this.hasAttribution = data.hasAttribution;
24
21
  this.hasPrefs = data.hasPrefs;
25
22
  this.identifier = data.identifier;
26
23
  this.primary = data.primary;
27
- this.shortIdentifier = util_1.rsplit(this.identifier, '.', 1)[1];
24
+ this.shortIdentifier = rsplit(this.identifier, '.', 1)[1];
28
25
  if (this.initpath.includes('mediaType')) {
29
26
  this.name = data.name;
30
27
  // this.languageCode = [];
@@ -32,9 +29,7 @@ class Agent extends plexObject_1.PlexObject {
32
29
  }
33
30
  }
34
31
  }
35
- exports.Agent = Agent;
36
- Agent.TAG = 'Agent';
37
- exports.SEARCHTYPES = {
32
+ export const SEARCHTYPES = {
38
33
  movie: 1,
39
34
  show: 2,
40
35
  season: 3,
@@ -52,23 +47,22 @@ exports.SEARCHTYPES = {
52
47
  playlist: 15,
53
48
  playlistFolder: 16,
54
49
  collection: 18,
50
+ optimizedVersion: 42,
55
51
  userPlaylistItem: 1001,
56
52
  };
57
53
  /**
58
54
  * Returns the integer value of the library string type.
59
55
  * @param libtype to lookup (movie, show, season, episode, artist, album, track, collection)
60
56
  */
61
- function searchType(libtype) {
57
+ export function searchType(libtype) {
62
58
  if (libtype &&
63
- Object.values(exports.SEARCHTYPES)
59
+ Object.values(SEARCHTYPES)
64
60
  .map(num => num.toString())
65
61
  .includes(`${libtype}`)) {
66
62
  return Number(libtype);
67
63
  }
68
- if (libtype && exports.SEARCHTYPES[libtype] !== undefined) {
69
- return exports.SEARCHTYPES[libtype];
64
+ if (libtype && SEARCHTYPES[libtype] !== undefined) {
65
+ return SEARCHTYPES[libtype];
70
66
  }
71
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
72
67
  throw new Error(`Unknown libtype: ${libtype}`);
73
68
  }
74
- exports.searchType = searchType;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,11 +1,12 @@
1
- /// <reference types="node" />
1
+ /// <reference types="node" resolution-mode="require"/>
2
2
  import { URL, URLSearchParams } from 'url';
3
- import { HistoryMetadatum } from './server.types';
4
- import { Library, Hub } from './library';
5
- import { Optimized } from './media';
6
- import { Agent, SEARCHTYPES } from './search';
7
- import { PlexClient } from './client';
8
- import { MyPlexAccount } from './myplex';
3
+ import { PlexClient } from './client.js';
4
+ import { Hub, Library } from './library.js';
5
+ import { Optimized } from './media.js';
6
+ import { MyPlexAccount } from './myplex.js';
7
+ import { Agent, SEARCHTYPES } from './search.js';
8
+ import { HistoryMetadatum } from './server.types.js';
9
+ import { Settings } from './settings.js';
9
10
  /**
10
11
  * This is the main entry point to interacting with a Plex server. It allows you to
11
12
  * list connected clients, browse your library sections and perform actions such as
@@ -16,7 +17,7 @@ import { MyPlexAccount } from './myplex';
16
17
  export declare class PlexServer {
17
18
  readonly baseurl: string;
18
19
  readonly token: string;
19
- readonly timeout?: number | undefined;
20
+ readonly timeout?: number;
20
21
  key: string;
21
22
  /** True if server allows camera upload */
22
23
  allowCameraUpload: boolean;
@@ -51,7 +52,7 @@ export declare class PlexServer {
51
52
  */
52
53
  hubSearch: boolean;
53
54
  /** Unique ID for this server (looks like an md5) */
54
- machineIdentifier: string;
55
+ machineIdentifier?: string;
55
56
  /**
56
57
  * True if `multiusers <https!://support.plex.tv/hc/en-us/articles/200250367-Multi-User-Support>`_ are enabled.
57
58
  */
@@ -128,8 +129,9 @@ export declare class PlexServer {
128
129
  /** Unknown */
129
130
  pushNotifications: boolean;
130
131
  _library?: Library;
132
+ _settings?: Settings;
131
133
  private _myPlexAccount?;
132
- constructor(baseurl: string, token: string, timeout?: number | undefined);
134
+ constructor(baseurl: string, token: string, timeout?: number);
133
135
  agents(mediaType?: number | string): Promise<Agent[]>;
134
136
  connect(): Promise<void>;
135
137
  /**
@@ -175,6 +177,7 @@ export declare class PlexServer {
175
177
  * @param librarySectionId request history for a specific library section ID.
176
178
  */
177
179
  history(maxresults?: number, mindate?: Date, ratingKey?: number | string, accountId?: number | string, librarySectionId?: number | string): Promise<HistoryMetadatum[]>;
180
+ settings(): Promise<Settings>;
178
181
  /**
179
182
  * Returns a :class:`~plexapi.myplex.MyPlexAccount` object using the same
180
183
  * token to access this server. If you are not the owner of this PlexServer
@@ -189,6 +192,15 @@ export declare class PlexServer {
189
192
  * if either includeToken is True or TODO: CONFIG.log.show_secrets is 'true'.
190
193
  */
191
194
  url(key: string, includeToken?: boolean, params?: URLSearchParams): URL;
195
+ /**
196
+ * Build the Plex Web URL for the object.
197
+ * @param base The base URL before the fragment (``#!``).
198
+ * Default is https://app.plex.tv/desktop.
199
+ * @param endpoint The Plex Web URL endpoint.
200
+ * None for server, 'playlist' for playlists, 'details' for all other media types.
201
+ */
202
+ _buildWebURL(base?: string, endpoint?: string, params?: URLSearchParams): string;
203
+ _uriRoot(): string;
192
204
  private _headers;
193
205
  private _loadData;
194
206
  /**
@@ -1,18 +1,13 @@
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.PlexServer = void 0;
7
- const got_1 = __importDefault(require("got"));
8
- const url_1 = require("url");
9
- const config_1 = require("./config");
10
- const library_1 = require("./library");
11
- const baseFunctionality_1 = require("./baseFunctionality");
12
- const media_1 = require("./media");
13
- const search_1 = require("./search");
14
- const client_1 = require("./client");
15
- const myplex_1 = require("./myplex");
1
+ import { URL, URLSearchParams } from 'url';
2
+ import got from 'got';
3
+ import { fetchItem, fetchItems } from './baseFunctionality.js';
4
+ import { PlexClient } from './client.js';
5
+ import { BASE_HEADERS, TIMEOUT, X_PLEX_CONTAINER_SIZE } from './config.js';
6
+ import { Hub, Library } from './library.js';
7
+ import { Optimized } from './media.js';
8
+ import { MyPlexAccount } from './myplex.js';
9
+ import { Agent, SEARCHTYPES } from './search.js';
10
+ import { Settings } from './settings.js';
16
11
  /**
17
12
  * This is the main entry point to interacting with a Plex server. It allows you to
18
13
  * list connected clients, browse your library sections and perform actions such as
@@ -20,7 +15,7 @@ const myplex_1 = require("./myplex");
20
15
  * server, or simply want to access your server with your username and password, you
21
16
  * can also create an PlexServer instance from :class:`~plexapi.myplex.MyPlexAccount`.
22
17
  */
23
- class PlexServer {
18
+ export class PlexServer {
24
19
  constructor(baseurl, token, timeout) {
25
20
  this.baseurl = baseurl;
26
21
  this.token = token;
@@ -32,7 +27,7 @@ class PlexServer {
32
27
  if (mediaType) {
33
28
  key += `?mediaType=${mediaType}`;
34
29
  }
35
- return baseFunctionality_1.fetchItems(this, key, undefined, search_1.Agent, this);
30
+ return fetchItems(this, key, undefined, Agent, this);
36
31
  }
37
32
  async connect() {
38
33
  const data = await this.query(this.key, undefined, undefined, this.timeout);
@@ -53,13 +48,13 @@ class PlexServer {
53
48
  return this._library;
54
49
  }
55
50
  try {
56
- const data = await this.query(library_1.Library.key);
57
- this._library = new library_1.Library(this, data.MediaContainer);
51
+ const data = await this.query(Library.key);
52
+ this._library = new Library(this, data.MediaContainer);
58
53
  }
59
- catch (_a) {
54
+ catch {
60
55
  // TODO: validate error type, also TODO figure out how this is used
61
56
  const data = await this.query('/library/sections/');
62
- this._library = new library_1.Library(this, data.MediaContainer);
57
+ this._library = new Library(this, data.MediaContainer);
63
58
  }
64
59
  return this._library;
65
60
  }
@@ -81,13 +76,13 @@ class PlexServer {
81
76
  async search(query, mediatype, limit) {
82
77
  const params = { query };
83
78
  if (mediatype) {
84
- params.section = search_1.SEARCHTYPES[mediatype].toString();
79
+ params.section = SEARCHTYPES[mediatype].toString();
85
80
  }
86
81
  if (limit) {
87
82
  params.limit = limit.toString();
88
83
  }
89
- const key = '/hubs/search?' + new url_1.URLSearchParams(params).toString();
90
- const hubs = await baseFunctionality_1.fetchItems(this, key, undefined, library_1.Hub, this);
84
+ const key = '/hubs/search?' + new URLSearchParams(params).toString();
85
+ const hubs = await fetchItems(this, key, undefined, Hub, this);
91
86
  return hubs;
92
87
  }
93
88
  /**
@@ -107,14 +102,14 @@ class PlexServer {
107
102
  requestHeaders.Authorization = `Basic ${credentials}`;
108
103
  }
109
104
  const url = this.url(path);
110
- const response = await got_1.default({
105
+ const response = await got({
111
106
  method,
112
107
  url,
113
108
  headers: requestHeaders,
114
- timeout: timeout !== null && timeout !== void 0 ? timeout : config_1.TIMEOUT,
115
- username,
116
- password,
117
- retry: 0,
109
+ timeout: { request: timeout ?? TIMEOUT },
110
+ ...(username ? { username } : {}),
111
+ ...(password ? { password } : {}),
112
+ retry: { limit: 0 },
118
113
  }).json();
119
114
  return response;
120
115
  }
@@ -144,23 +139,30 @@ class PlexServer {
144
139
  args['viewedAt>'] = mindate.getTime().toString();
145
140
  }
146
141
  args['X-Plex-Container-Start'] = '0';
147
- args['X-Plex-Container-Size'] = Math.min(config_1.X_PLEX_CONTAINER_SIZE, maxresults).toString();
142
+ args['X-Plex-Container-Size'] = Math.min(X_PLEX_CONTAINER_SIZE, maxresults).toString();
148
143
  let results = [];
149
- let key = '/status/sessions/history/all?' + new url_1.URLSearchParams(args).toString();
144
+ let key = '/status/sessions/history/all?' + new URLSearchParams(args).toString();
150
145
  let raw = await this.query(key);
151
146
  const totalResults = raw.MediaContainer.totalSize;
152
147
  results = results.concat(raw.MediaContainer.Metadata);
153
148
  while (results.length <= totalResults &&
154
- config_1.X_PLEX_CONTAINER_SIZE === raw.MediaContainer.size &&
149
+ X_PLEX_CONTAINER_SIZE === raw.MediaContainer.size &&
155
150
  maxresults > results.length) {
156
151
  args['X-Plex-Container-Start'] = (Number(args['X-Plex-Container-Start']) + Number(args['X-Plex-Container-Size'])).toString();
157
- key = '/status/sessions/history/all?' + new url_1.URLSearchParams(args).toString();
152
+ key = '/status/sessions/history/all?' + new URLSearchParams(args).toString();
158
153
  // eslint-disable-next-line no-await-in-loop
159
154
  raw = await this.query(key);
160
155
  results = results.concat(raw.MediaContainer.Metadata);
161
156
  }
162
157
  return results;
163
158
  }
159
+ async settings() {
160
+ if (!this._settings) {
161
+ const data = await this.query(Settings.key);
162
+ this._settings = new Settings(this, data.MediaContainer.Setting);
163
+ }
164
+ return this._settings;
165
+ }
164
166
  // TODO: not sure if this works
165
167
  // /**
166
168
  // * Returns a list of all playlist objects saved on the server.
@@ -178,38 +180,37 @@ class PlexServer {
178
180
  */
179
181
  myPlexAccount() {
180
182
  if (!this._myPlexAccount) {
181
- this._myPlexAccount = new myplex_1.MyPlexAccount(this.baseurl, undefined, undefined, this.token, this.timeout, this);
183
+ this._myPlexAccount = new MyPlexAccount(this.baseurl, undefined, undefined, this.token, this.timeout, this);
182
184
  }
183
185
  return this._myPlexAccount;
184
186
  }
185
187
  // Returns list of all :class:`~plexapi.client.PlexClient` objects connected to server.
186
188
  async clients() {
187
- var _a, _b;
188
189
  const items = [];
189
190
  const response = await this.query('/clients');
190
- if (((_a = response.MediaContainer) === null || _a === void 0 ? void 0 : _a.Server) === undefined) {
191
+ if (response.MediaContainer?.Server === undefined) {
191
192
  return [];
192
193
  }
193
194
  const shouldFetchPorts = response.MediaContainer.Server.some(server => server.port === null || server.port === undefined);
194
- let ports;
195
+ let ports = {};
195
196
  if (shouldFetchPorts) {
196
197
  ports = await this._myPlexClientPorts();
197
198
  }
198
199
  for (const server of response.MediaContainer.Server) {
199
- let port = server.port;
200
+ let { port } = server;
200
201
  if (!port) {
201
202
  // TODO: print warning about doing weird port stuff
202
- port = (_b = ports) === null || _b === void 0 ? void 0 : _b[server.machineIdentifier];
203
+ port = Number(ports?.[server.machineIdentifier]);
203
204
  }
204
205
  const baseurl = `http://${server.host}:${port}`;
205
- items.push(new client_1.PlexClient({ baseurl, token: this.token, server: this, data: server }));
206
+ items.push(new PlexClient({ baseurl, token: this.token, server: this, data: server }));
206
207
  }
207
208
  return items;
208
209
  }
209
210
  /** Returns list of all :class:`~plexapi.media.Optimized` objects connected to server. */
210
211
  async optimizedItems() {
211
- const backgroundProcessing = await baseFunctionality_1.fetchItem(this, '/playlists?type=42');
212
- const items = await baseFunctionality_1.fetchItems(this, backgroundProcessing.key, undefined, media_1.Optimized, this);
212
+ const backgroundProcessing = await fetchItem(this, '/playlists?type=42');
213
+ const items = await fetchItems(this, backgroundProcessing.key, undefined, Optimized, this);
213
214
  return items;
214
215
  }
215
216
  /**
@@ -220,18 +221,34 @@ class PlexServer {
220
221
  if (!this.baseurl) {
221
222
  throw new Error('PlexClient object missing baseurl.');
222
223
  }
223
- const url = new url_1.URL(key, this.baseurl);
224
+ const url = new URL(key, this.baseurl);
224
225
  if (this.token && includeToken) {
225
- const searchParams = new url_1.URLSearchParams(params);
226
+ const searchParams = new URLSearchParams(params);
226
227
  searchParams.append('X-Plex-Token', this.token);
227
228
  url.search = searchParams.toString();
228
229
  return url;
229
230
  }
230
231
  return url;
231
232
  }
233
+ /**
234
+ * Build the Plex Web URL for the object.
235
+ * @param base The base URL before the fragment (``#!``).
236
+ * Default is https://app.plex.tv/desktop.
237
+ * @param endpoint The Plex Web URL endpoint.
238
+ * None for server, 'playlist' for playlists, 'details' for all other media types.
239
+ */
240
+ _buildWebURL(base = 'https://app.plex.tv/desktop/', endpoint, params) {
241
+ if (endpoint) {
242
+ return `${base}#!/server/${this.machineIdentifier}/${endpoint}?${params?.toString()}`;
243
+ }
244
+ return `${base}#!/media/${this.machineIdentifier}/com.plexapp.plugins.library?${params?.toString()}`;
245
+ }
246
+ _uriRoot() {
247
+ return `server://${this.machineIdentifier}/com.plexapp.plugins.library`;
248
+ }
232
249
  _headers() {
233
250
  const headers = {
234
- ...config_1.BASE_HEADERS,
251
+ ...BASE_HEADERS,
235
252
  'Content-type': 'application/json',
236
253
  };
237
254
  if (this.token) {
@@ -292,16 +309,14 @@ class PlexServer {
292
309
  * See python plex issue #126: Make PlexServer.clients() more user friendly.
293
310
  */
294
311
  async _myPlexClientPorts() {
295
- var _a;
296
- let ports = {};
312
+ const ports = {};
297
313
  const account = this.myPlexAccount();
298
314
  const devices = await account.devices();
299
315
  for (const device of devices) {
300
- if ((_a = device.connections) === null || _a === void 0 ? void 0 : _a.length) {
301
- ports[device.clientIdentifier] = new url_1.URL('http://172.17.0.2:32400').port;
316
+ if (device.connections?.length) {
317
+ ports[device.clientIdentifier] = new URL('http://172.17.0.2:32400').port;
302
318
  }
303
319
  }
304
320
  return ports;
305
321
  }
306
322
  }
307
- exports.PlexServer = PlexServer;
@@ -0,0 +1 @@
1
+ export {};