@ctrl/plex 3.10.0 → 3.12.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.
- package/dist/src/alert.js +3 -1
- package/dist/src/audio.js +49 -39
- package/dist/src/audio.types.d.ts +2 -2
- package/dist/src/base/partialPlexObject.js +26 -29
- package/dist/src/base/playable.d.ts +1 -1
- package/dist/src/base/plexObject.js +13 -5
- package/dist/src/client.d.ts +2 -2
- package/dist/src/client.js +12 -11
- package/dist/src/config.js +1 -1
- package/dist/src/exceptions.js +5 -5
- package/dist/src/library.d.ts +1 -1
- package/dist/src/library.js +43 -53
- package/dist/src/media.js +106 -113
- package/dist/src/myplex.js +30 -22
- package/dist/src/playlist.js +18 -15
- package/dist/src/playqueue.js +5 -8
- package/dist/src/search.js +2 -2
- package/dist/src/server.d.ts +1 -1
- package/dist/src/server.js +14 -8
- package/dist/src/settings.js +7 -16
- package/dist/src/util.d.ts +3 -3
- package/dist/src/util.js +10 -8
- package/dist/src/video.d.ts +1 -1
- package/dist/src/video.js +17 -35
- package/package.json +18 -18
package/dist/src/myplex.js
CHANGED
|
@@ -13,7 +13,13 @@ import { PlexServer } from './server.js';
|
|
|
13
13
|
* and return this object.
|
|
14
14
|
*/
|
|
15
15
|
export class MyPlexAccount {
|
|
16
|
-
|
|
16
|
+
baseUrl;
|
|
17
|
+
username;
|
|
18
|
+
password;
|
|
19
|
+
token;
|
|
20
|
+
timeout;
|
|
21
|
+
server;
|
|
22
|
+
static key = 'https://plex.tv/api/v2/user';
|
|
17
23
|
/**
|
|
18
24
|
* This follows the outline described in https://forums.plex.tv/t/authenticating-with-plex/609370
|
|
19
25
|
* to fetch a token and potentially compromise username and password. To use first call `getWebLogin()`
|
|
@@ -37,7 +43,7 @@ export class MyPlexAccount {
|
|
|
37
43
|
});
|
|
38
44
|
return {
|
|
39
45
|
...pin,
|
|
40
|
-
uri: `https://app.plex.tv/auth#?clientID=${encodeURIComponent(clientIdentifier)}&code=${encodeURIComponent(pin.code)}&context%5Bdevice%5D%5Bproduct%5D=${encodeURIComponent(appName)}${forwardUrl ?
|
|
46
|
+
uri: `https://app.plex.tv/auth#?clientID=${encodeURIComponent(clientIdentifier)}&code=${encodeURIComponent(pin.code)}&context%5Bdevice%5D%5Bproduct%5D=${encodeURIComponent(appName)}${forwardUrl ? `&forwardUrl=${encodeURIComponent(forwardUrl)}` : ''}`,
|
|
41
47
|
};
|
|
42
48
|
}
|
|
43
49
|
/**
|
|
@@ -79,6 +85,18 @@ export class MyPlexAccount {
|
|
|
79
85
|
}
|
|
80
86
|
throw new Error('Failed to authenticate before timeout');
|
|
81
87
|
}
|
|
88
|
+
FRIENDINVITE = 'https://plex.tv/api/servers/{machineId}/shared_servers'; // post with data
|
|
89
|
+
HOMEUSERCREATE = 'https://plex.tv/api/home/users?title={title}'; // post with data
|
|
90
|
+
EXISTINGUSER = 'https://plex.tv/api/home/users?invitedEmail={username}'; // post with data
|
|
91
|
+
FRIENDSERVERS = 'https://plex.tv/api/servers/{machineId}/shared_servers/{serverId}'; // put with data
|
|
92
|
+
PLEXSERVERS = 'https://plex.tv/api/servers/{machineId}'; // get
|
|
93
|
+
FRIENDUPDATE = 'https://plex.tv/api/friends/{userId}'; // put with args, delete
|
|
94
|
+
REMOVEHOMEUSER = 'https://plex.tv/api/home/users/{userId}'; // delete
|
|
95
|
+
REMOVEINVITE = 'https://plex.tv/api/invites/requested/{userId}?friend=0&server=1&home=0'; // delete
|
|
96
|
+
REQUESTED = 'https://plex.tv/api/invites/requested'; // get
|
|
97
|
+
REQUESTS = 'https://plex.tv/api/invites/requests'; // get
|
|
98
|
+
SIGNIN = 'https://plex.tv/users/sign_in.json'; // get with auth
|
|
99
|
+
WEBHOOKS = 'https://plex.tv/api/v2/user/webhooks'; // get, post with data
|
|
82
100
|
/**
|
|
83
101
|
*
|
|
84
102
|
* @param username Your MyPlex username
|
|
@@ -95,18 +113,6 @@ export class MyPlexAccount {
|
|
|
95
113
|
this.token = token;
|
|
96
114
|
this.timeout = timeout;
|
|
97
115
|
this.server = server;
|
|
98
|
-
this.FRIENDINVITE = 'https://plex.tv/api/servers/{machineId}/shared_servers'; // post with data
|
|
99
|
-
this.HOMEUSERCREATE = 'https://plex.tv/api/home/users?title={title}'; // post with data
|
|
100
|
-
this.EXISTINGUSER = 'https://plex.tv/api/home/users?invitedEmail={username}'; // post with data
|
|
101
|
-
this.FRIENDSERVERS = 'https://plex.tv/api/servers/{machineId}/shared_servers/{serverId}'; // put with data
|
|
102
|
-
this.PLEXSERVERS = 'https://plex.tv/api/servers/{machineId}'; // get
|
|
103
|
-
this.FRIENDUPDATE = 'https://plex.tv/api/friends/{userId}'; // put with args, delete
|
|
104
|
-
this.REMOVEHOMEUSER = 'https://plex.tv/api/home/users/{userId}'; // delete
|
|
105
|
-
this.REMOVEINVITE = 'https://plex.tv/api/invites/requested/{userId}?friend=0&server=1&home=0'; // delete
|
|
106
|
-
this.REQUESTED = 'https://plex.tv/api/invites/requested'; // get
|
|
107
|
-
this.REQUESTS = 'https://plex.tv/api/invites/requests'; // get
|
|
108
|
-
this.SIGNIN = 'https://plex.tv/users/sign_in.json'; // get with auth
|
|
109
|
-
this.WEBHOOKS = 'https://plex.tv/api/v2/user/webhooks'; // get, post with data
|
|
110
116
|
if (this.token) {
|
|
111
117
|
Object.defineProperty(this, 'token', {
|
|
112
118
|
enumerable: false,
|
|
@@ -214,7 +220,7 @@ export class MyPlexAccount {
|
|
|
214
220
|
*/
|
|
215
221
|
async claimToken() {
|
|
216
222
|
const url = 'https://plex.tv/api/claim/token.json';
|
|
217
|
-
const response = await this.query(url, 'get'
|
|
223
|
+
const response = await this.query(url, 'get');
|
|
218
224
|
return response.token;
|
|
219
225
|
}
|
|
220
226
|
/**
|
|
@@ -292,11 +298,13 @@ async function connect(cls, url, token, timeout) {
|
|
|
292
298
|
* content such as Plex Media Servers, iPhone or Android clients, etc.
|
|
293
299
|
*/
|
|
294
300
|
export class MyPlexResource {
|
|
295
|
-
|
|
301
|
+
account;
|
|
302
|
+
baseUrl;
|
|
303
|
+
static key = 'https://plex.tv/api/v2/resources?includeHttps=1&includeRelay=1';
|
|
304
|
+
TAG = 'Device';
|
|
296
305
|
constructor(account, data, baseUrl = null) {
|
|
297
306
|
this.account = account;
|
|
298
307
|
this.baseUrl = baseUrl;
|
|
299
|
-
this.TAG = 'Device';
|
|
300
308
|
this._loadData(data);
|
|
301
309
|
}
|
|
302
310
|
async connect(ssl = null, timeout) {
|
|
@@ -354,8 +362,8 @@ export class MyPlexResource {
|
|
|
354
362
|
}
|
|
355
363
|
}
|
|
356
364
|
export class ResourceConnection {
|
|
365
|
+
TAG = 'Connection';
|
|
357
366
|
constructor(data) {
|
|
358
|
-
this.TAG = 'Connection';
|
|
359
367
|
this._loadData(data);
|
|
360
368
|
}
|
|
361
369
|
_loadData(data) {
|
|
@@ -374,8 +382,8 @@ export class ResourceConnection {
|
|
|
374
382
|
* https://plex.tv/devices.xml
|
|
375
383
|
*/
|
|
376
384
|
export class MyPlexDevice extends PlexObject {
|
|
377
|
-
static
|
|
378
|
-
static
|
|
385
|
+
static TAG = 'Device';
|
|
386
|
+
static key = 'https://plex.tv/devices.xml';
|
|
379
387
|
async connect() {
|
|
380
388
|
// TODO: switch between PlexServer and PlexClient
|
|
381
389
|
// Try connecting to all known resource connections in parellel, but
|
|
@@ -414,8 +422,8 @@ export class MyPlexDevice extends PlexObject {
|
|
|
414
422
|
});
|
|
415
423
|
this.screenResolution = data.$.screenResolution;
|
|
416
424
|
this.screenDensity = data.$.screenDensity;
|
|
417
|
-
this.createdAt = new Date(parseInt(data.$.createdAt, 10));
|
|
418
|
-
this.lastSeenAt = new Date(parseInt(data.$.lastSeenAt, 10));
|
|
425
|
+
this.createdAt = new Date(Number.parseInt(data.$.createdAt, 10));
|
|
426
|
+
this.lastSeenAt = new Date(Number.parseInt(data.$.lastSeenAt, 10));
|
|
419
427
|
this.connections = data.Connection?.map(connection => connection.$.uri);
|
|
420
428
|
}
|
|
421
429
|
}
|
package/dist/src/playlist.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { URLSearchParams } from 'url';
|
|
1
|
+
import { URLSearchParams } from 'node:url';
|
|
2
2
|
import { Playable } from './base/playable.js';
|
|
3
3
|
import { Album, Artist, Track } from './audio.js';
|
|
4
4
|
import { fetchItems } from './baseFunctionality.js';
|
|
@@ -9,28 +9,28 @@ import { Episode, Movie } from './video.js';
|
|
|
9
9
|
*/
|
|
10
10
|
function contentClass(data) {
|
|
11
11
|
switch (data.type) {
|
|
12
|
-
case 'episode':
|
|
12
|
+
case 'episode': {
|
|
13
13
|
return Episode;
|
|
14
|
-
|
|
14
|
+
}
|
|
15
|
+
case 'movie': {
|
|
15
16
|
return Movie;
|
|
16
|
-
|
|
17
|
+
}
|
|
18
|
+
case 'track': {
|
|
17
19
|
return Track;
|
|
18
|
-
|
|
20
|
+
}
|
|
21
|
+
case 'album': {
|
|
19
22
|
return Album;
|
|
20
|
-
|
|
23
|
+
}
|
|
24
|
+
case 'artist': {
|
|
21
25
|
return Artist;
|
|
22
|
-
|
|
26
|
+
}
|
|
27
|
+
default: {
|
|
23
28
|
throw new Error(`Media type '${data.type}' not implemented`);
|
|
29
|
+
}
|
|
24
30
|
}
|
|
25
31
|
}
|
|
26
32
|
export class Playlist extends Playable {
|
|
27
|
-
|
|
28
|
-
super(...arguments);
|
|
29
|
-
this.TYPE = 'playlist';
|
|
30
|
-
/** Cache of playlist items */
|
|
31
|
-
this._items = null;
|
|
32
|
-
}
|
|
33
|
-
static { this.TAG = 'Playlist'; }
|
|
33
|
+
static TAG = 'Playlist';
|
|
34
34
|
static async create(server, title, options) {
|
|
35
35
|
if (options.smart) {
|
|
36
36
|
throw new Error('not yet supported');
|
|
@@ -86,6 +86,9 @@ export class Playlist extends Playable {
|
|
|
86
86
|
const data = await server.query(key, 'post');
|
|
87
87
|
return new Playlist(server, data.MediaContainer.Metadata[0], key);
|
|
88
88
|
}
|
|
89
|
+
TYPE = 'playlist';
|
|
90
|
+
/** Cache of playlist items */
|
|
91
|
+
_items = null;
|
|
89
92
|
async _edit(args) {
|
|
90
93
|
const searchparams = new URLSearchParams(args);
|
|
91
94
|
const key = `${this.key}?${searchparams.toString()}`;
|
|
@@ -99,7 +102,7 @@ export class Playlist extends Playable {
|
|
|
99
102
|
*/
|
|
100
103
|
async item(title) {
|
|
101
104
|
const items = await this.items();
|
|
102
|
-
const matched = items.find(item => item.title
|
|
105
|
+
const matched = items.find(item => item.title?.toLowerCase() === title.toLowerCase());
|
|
103
106
|
return matched ?? null;
|
|
104
107
|
}
|
|
105
108
|
async items() {
|
package/dist/src/playqueue.js
CHANGED
|
@@ -9,13 +9,10 @@ import { BadRequest } from './exceptions.js';
|
|
|
9
9
|
* removing, and reordering items.
|
|
10
10
|
*/
|
|
11
11
|
export class PlayQueue extends PlexObject {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
static { this.TAG = 'PlayQueue'; }
|
|
18
|
-
static { this.TYPE = 'playqueue'; }
|
|
12
|
+
static TAG = 'PlayQueue';
|
|
13
|
+
static TYPE = 'playqueue';
|
|
14
|
+
/** Cache of PlayQueue items */
|
|
15
|
+
_items = null;
|
|
19
16
|
/**
|
|
20
17
|
* Retrieve an existing PlayQueue by identifier.
|
|
21
18
|
*/
|
|
@@ -258,7 +255,7 @@ export class PlayQueue extends PlexObject {
|
|
|
258
255
|
this.playQueueSourceURI = data.playQueueSourceURI;
|
|
259
256
|
this.playQueueTotalCount = data.playQueueTotalCount;
|
|
260
257
|
this.playQueueVersion = data.playQueueVersion;
|
|
261
|
-
this.size = data.size
|
|
258
|
+
this.size = data.size > 0 ? data.size : this.playQueueTotalCount;
|
|
262
259
|
// selectedItem will be set lazily when accessing items
|
|
263
260
|
}
|
|
264
261
|
_invalidateCacheAndLoadData(data) {
|
package/dist/src/search.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PlexObject } from './base/plexObject.js';
|
|
2
2
|
import { rsplit } from './util.js';
|
|
3
3
|
export class SearchResult extends PlexObject {
|
|
4
|
-
static
|
|
4
|
+
static TAG = 'SearchResult';
|
|
5
5
|
_loadData(data) {
|
|
6
6
|
this.guid = data.guid;
|
|
7
7
|
this.lifespanEnded = data.lifespanEnded;
|
|
@@ -14,7 +14,7 @@ export class SearchResult extends PlexObject {
|
|
|
14
14
|
* Represents a single Agent
|
|
15
15
|
*/
|
|
16
16
|
export class Agent extends PlexObject {
|
|
17
|
-
static
|
|
17
|
+
static TAG = 'Agent';
|
|
18
18
|
// languageCode: any[] = [];
|
|
19
19
|
_loadData(data) {
|
|
20
20
|
this.hasAttribution = data.hasAttribution;
|
package/dist/src/server.d.ts
CHANGED
package/dist/src/server.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { URL, URLSearchParams } from 'node:url';
|
|
1
2
|
import { ofetch } from 'ofetch';
|
|
2
|
-
import { URL, URLSearchParams } from 'url';
|
|
3
3
|
import { fetchItem, fetchItems } from './baseFunctionality.js';
|
|
4
4
|
import { PlexClient } from './client.js';
|
|
5
5
|
import { BASE_HEADERS, TIMEOUT, X_PLEX_CONTAINER_SIZE } from './config.js';
|
|
@@ -17,6 +17,13 @@ import { Settings } from './settings.js';
|
|
|
17
17
|
* can also create an PlexServer instance from :class:`~plexapi.myplex.MyPlexAccount`.
|
|
18
18
|
*/
|
|
19
19
|
export class PlexServer {
|
|
20
|
+
baseurl;
|
|
21
|
+
token;
|
|
22
|
+
timeout;
|
|
23
|
+
key = '/';
|
|
24
|
+
_library;
|
|
25
|
+
_settings;
|
|
26
|
+
_myPlexAccount;
|
|
20
27
|
constructor(baseurl, token,
|
|
21
28
|
/**
|
|
22
29
|
* Default request timeout in milliseconds.
|
|
@@ -26,7 +33,6 @@ export class PlexServer {
|
|
|
26
33
|
this.baseurl = baseurl;
|
|
27
34
|
this.token = token;
|
|
28
35
|
this.timeout = timeout;
|
|
29
|
-
this.key = '/';
|
|
30
36
|
}
|
|
31
37
|
async agents(mediaType) {
|
|
32
38
|
let key = '/system/agents';
|
|
@@ -87,7 +93,7 @@ export class PlexServer {
|
|
|
87
93
|
if (limit) {
|
|
88
94
|
params.limit = limit.toString();
|
|
89
95
|
}
|
|
90
|
-
const key =
|
|
96
|
+
const key = `/hubs/search?${new URLSearchParams(params).toString()}`;
|
|
91
97
|
const hubs = await fetchItems(this, key, undefined, Hub, this);
|
|
92
98
|
return hubs;
|
|
93
99
|
}
|
|
@@ -131,7 +137,7 @@ export class PlexServer {
|
|
|
131
137
|
* @param accountId request history for a specific account ID.
|
|
132
138
|
* @param librarySectionId request history for a specific library section ID.
|
|
133
139
|
*/
|
|
134
|
-
async history(maxresults =
|
|
140
|
+
async history(maxresults = 9_999_999, mindate, ratingKey, accountId, librarySectionId) {
|
|
135
141
|
const args = { sort: 'viewedAt:desc' };
|
|
136
142
|
if (ratingKey !== undefined) {
|
|
137
143
|
args.metadataItemID = ratingKey.toString();
|
|
@@ -148,21 +154,21 @@ export class PlexServer {
|
|
|
148
154
|
args['X-Plex-Container-Start'] = '0';
|
|
149
155
|
args['X-Plex-Container-Size'] = Math.min(X_PLEX_CONTAINER_SIZE, maxresults).toString();
|
|
150
156
|
let results = [];
|
|
151
|
-
let key =
|
|
157
|
+
let key = `/status/sessions/history/all?${new URLSearchParams(args).toString()}`;
|
|
152
158
|
let raw = await this.query(key);
|
|
153
159
|
const totalResults = raw.MediaContainer.totalSize;
|
|
154
160
|
// Filter out null/undefined items from the metadata
|
|
155
161
|
const validMetadata = raw.MediaContainer.Metadata?.filter(Boolean) ?? [];
|
|
156
|
-
results
|
|
162
|
+
results.push(...validMetadata);
|
|
157
163
|
while (results.length <= totalResults &&
|
|
158
164
|
X_PLEX_CONTAINER_SIZE === raw.MediaContainer.size &&
|
|
159
165
|
maxresults > results.length) {
|
|
160
166
|
args['X-Plex-Container-Start'] = (Number(args['X-Plex-Container-Start']) + Number(args['X-Plex-Container-Size'])).toString();
|
|
161
|
-
key =
|
|
167
|
+
key = `/status/sessions/history/all?${new URLSearchParams(args).toString()}`;
|
|
162
168
|
raw = await this.query(key);
|
|
163
169
|
// Filter out null/undefined items from the metadata
|
|
164
170
|
const validMetadata = raw.MediaContainer.Metadata?.filter(item => item != null) ?? [];
|
|
165
|
-
results
|
|
171
|
+
results.push(...validMetadata);
|
|
166
172
|
}
|
|
167
173
|
return results;
|
|
168
174
|
}
|
package/dist/src/settings.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { URLSearchParams } from 'url';
|
|
1
|
+
import { URLSearchParams } from 'node:url';
|
|
2
2
|
import { PlexObject } from './base/plexObject.js';
|
|
3
3
|
import { NotFound } from './exceptions.js';
|
|
4
4
|
import { lowerFirst } from './util.js';
|
|
@@ -22,11 +22,8 @@ var Type;
|
|
|
22
22
|
Type["Text"] = "text";
|
|
23
23
|
})(Type || (Type = {}));
|
|
24
24
|
export class Settings extends PlexObject {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
this._data = [];
|
|
28
|
-
}
|
|
29
|
-
static { this.key = '/:/prefs'; }
|
|
25
|
+
static key = '/:/prefs';
|
|
26
|
+
_data = [];
|
|
30
27
|
all() {
|
|
31
28
|
return Object.entries(this._settings)
|
|
32
29
|
.sort((a, b) => a[0].localeCompare(b[0]))
|
|
@@ -70,17 +67,14 @@ export class Settings extends PlexObject {
|
|
|
70
67
|
* Represents a single Plex setting
|
|
71
68
|
*/
|
|
72
69
|
export class Setting extends PlexObject {
|
|
73
|
-
|
|
74
|
-
super(...arguments);
|
|
75
|
-
this._setValue = null;
|
|
76
|
-
}
|
|
70
|
+
_setValue = null;
|
|
77
71
|
/**
|
|
78
72
|
* Set a new value for this setitng. NOTE: You must call {@link Settings.save} before
|
|
79
73
|
* any changes to setting values are persisted to the PlexServer.
|
|
80
74
|
*/
|
|
81
75
|
set(value) {
|
|
82
76
|
if (typeof value !== typeof this.value) {
|
|
83
|
-
throw new
|
|
77
|
+
throw new TypeError('Invalid type');
|
|
84
78
|
}
|
|
85
79
|
this._setValue = value;
|
|
86
80
|
}
|
|
@@ -99,11 +93,8 @@ export class Setting extends PlexObject {
|
|
|
99
93
|
}
|
|
100
94
|
}
|
|
101
95
|
export class Preferences extends Setting {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
this.FILTER = 'preferences';
|
|
105
|
-
}
|
|
106
|
-
static { this.TAG = 'Preferences'; }
|
|
96
|
+
static TAG = 'Preferences';
|
|
97
|
+
FILTER = 'preferences';
|
|
107
98
|
}
|
|
108
99
|
// class Setting(PlexObject):
|
|
109
100
|
// """ Represents a single Plex setting.
|
package/dist/src/util.d.ts
CHANGED
|
@@ -10,11 +10,11 @@ export interface MetadataContainer<T extends {
|
|
|
10
10
|
export declare function rsplit(str: string, sep: string, maxsplit: number): string[];
|
|
11
11
|
/**
|
|
12
12
|
* Return the full agent identifier from a short identifier, name, or confirm full identifier.
|
|
13
|
-
* @param section
|
|
14
|
-
* @param agent
|
|
15
13
|
*/
|
|
16
14
|
export declare function getAgentIdentifier(section: Section, agent: string): Promise<string>;
|
|
17
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Simple tag helper for editing a object.
|
|
17
|
+
*/
|
|
18
18
|
export declare function tagHelper(tag: string, items: string[], locked?: boolean, remove?: boolean): Record<string, string | number>;
|
|
19
19
|
export declare function ltrim(x: string, characters: string[]): string;
|
|
20
20
|
export declare function lowerFirst(str: string): string;
|
package/dist/src/util.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
export function rsplit(str, sep, maxsplit) {
|
|
2
2
|
const split = str.split(sep);
|
|
3
|
-
|
|
3
|
+
if (maxsplit) {
|
|
4
|
+
return [split.slice(0, -maxsplit).join(sep), ...split.slice(-maxsplit)];
|
|
5
|
+
}
|
|
6
|
+
return split;
|
|
4
7
|
}
|
|
5
8
|
/**
|
|
6
9
|
* Return the full agent identifier from a short identifier, name, or confirm full identifier.
|
|
7
|
-
* @param section
|
|
8
|
-
* @param agent
|
|
9
10
|
*/
|
|
10
11
|
export async function getAgentIdentifier(section, agent) {
|
|
11
12
|
const agents = [];
|
|
@@ -14,11 +15,13 @@ export async function getAgentIdentifier(section, agent) {
|
|
|
14
15
|
if (identifiers.includes(agent)) {
|
|
15
16
|
return ag.identifier;
|
|
16
17
|
}
|
|
17
|
-
agents.
|
|
18
|
+
agents.push(...identifiers);
|
|
18
19
|
}
|
|
19
20
|
throw new Error(`Couldnt find "${agent}" in agents list (${agents.join(', ')})`);
|
|
20
21
|
}
|
|
21
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* Simple tag helper for editing a object.
|
|
24
|
+
*/
|
|
22
25
|
export function tagHelper(tag, items, locked = true, remove = false) {
|
|
23
26
|
const data = {};
|
|
24
27
|
if (remove) {
|
|
@@ -40,9 +43,8 @@ export function ltrim(x, characters) {
|
|
|
40
43
|
while (characters.includes(x[start])) {
|
|
41
44
|
start += 1;
|
|
42
45
|
}
|
|
43
|
-
|
|
44
|
-
return x.substr(start, end);
|
|
46
|
+
return x.slice(start);
|
|
45
47
|
}
|
|
46
48
|
export function lowerFirst(str) {
|
|
47
|
-
return str.charAt(0).
|
|
49
|
+
return str.charAt(0).toLowerCase() + str.slice(1);
|
|
48
50
|
}
|
package/dist/src/video.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { URL } from 'url';
|
|
1
|
+
import type { URL } from 'node:url';
|
|
2
2
|
import { Playable } from './base/playable.js';
|
|
3
3
|
import type { ExtrasData, FullShowData, MovieData, ShowData } from './library.types.js';
|
|
4
4
|
import { Chapter, Collection, Country, Director, Genre, Guid, Marker, Media, Poster, Producer, Rating, Role, Similar, Writer } from './media.js';
|
package/dist/src/video.js
CHANGED
|
@@ -2,11 +2,8 @@ import { Playable } from './base/playable.js';
|
|
|
2
2
|
import { fetchItem, fetchItems, findItems } from './baseFunctionality.js';
|
|
3
3
|
import { Chapter, Collection, Country, Director, Genre, Guid, Marker, Media, Poster, Producer, Rating, Role, Similar, Writer, } from './media.js';
|
|
4
4
|
class Video extends Playable {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
/** Hardcoded as 'video' (useful for search filters). */
|
|
8
|
-
this.listType = 'video';
|
|
9
|
-
}
|
|
5
|
+
/** Hardcoded as 'video' (useful for search filters). */
|
|
6
|
+
listType = 'video';
|
|
10
7
|
/**
|
|
11
8
|
* Returns True if this video is watched.
|
|
12
9
|
*/
|
|
@@ -109,12 +106,9 @@ class Video extends Playable {
|
|
|
109
106
|
* Represents a single Movie.
|
|
110
107
|
*/
|
|
111
108
|
export class Movie extends Video {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
this.TYPE = 'movie';
|
|
116
|
-
this.METADATA_TYPE = 'movie';
|
|
117
|
-
}
|
|
109
|
+
TAG = 'Video';
|
|
110
|
+
TYPE = 'movie';
|
|
111
|
+
METADATA_TYPE = 'movie';
|
|
118
112
|
get actors() {
|
|
119
113
|
return this.roles;
|
|
120
114
|
}
|
|
@@ -190,12 +184,9 @@ export class Movie extends Video {
|
|
|
190
184
|
* Represents a single Show (including all seasons and episodes).
|
|
191
185
|
*/
|
|
192
186
|
export class Show extends Video {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
this.TYPE = 'show';
|
|
197
|
-
this.METADATA_TYPE = 'episode';
|
|
198
|
-
}
|
|
187
|
+
TAG = 'Directory';
|
|
188
|
+
TYPE = 'show';
|
|
189
|
+
METADATA_TYPE = 'episode';
|
|
199
190
|
/** <:class:`~plexapi.media.Similar`>): List of Similar objects. */
|
|
200
191
|
// similar: List;
|
|
201
192
|
/**
|
|
@@ -256,12 +247,9 @@ export class Show extends Video {
|
|
|
256
247
|
* Represents a single Show Season (including all episodes).
|
|
257
248
|
*/
|
|
258
249
|
export class Season extends Video {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
this.TYPE = 'season';
|
|
263
|
-
this.METADATA_TYPE = 'episode';
|
|
264
|
-
}
|
|
250
|
+
TAG = 'Directory';
|
|
251
|
+
TYPE = 'season';
|
|
252
|
+
METADATA_TYPE = 'episode';
|
|
265
253
|
/** Returns season number */
|
|
266
254
|
get seasonNumber() {
|
|
267
255
|
return this.index;
|
|
@@ -290,12 +278,9 @@ export class Season extends Video {
|
|
|
290
278
|
}
|
|
291
279
|
}
|
|
292
280
|
export class Episode extends Video {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
this.METADATA_TYPE = 'episode';
|
|
297
|
-
}
|
|
298
|
-
static { this.TAG = 'Video'; }
|
|
281
|
+
static TAG = 'Video';
|
|
282
|
+
TYPE = 'episode';
|
|
283
|
+
METADATA_TYPE = 'episode';
|
|
299
284
|
/**
|
|
300
285
|
* Returns this episodes season number.
|
|
301
286
|
*/
|
|
@@ -380,12 +365,9 @@ export class Episode extends Video {
|
|
|
380
365
|
}
|
|
381
366
|
}
|
|
382
367
|
export class Clip extends Video {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
this.METADATA_TYPE = 'clip';
|
|
387
|
-
}
|
|
388
|
-
static { this.TAG = 'Video'; }
|
|
368
|
+
static TAG = 'Video';
|
|
369
|
+
TYPE = 'clip';
|
|
370
|
+
METADATA_TYPE = 'clip';
|
|
389
371
|
_loadData(data) {
|
|
390
372
|
super._loadData(data);
|
|
391
373
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ctrl/plex",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.12.0",
|
|
4
4
|
"description": "plex api client in typescript using ofetch",
|
|
5
5
|
"author": "Scott Cooper <scttcper@gmail.com>",
|
|
6
6
|
"publishConfig": {
|
|
@@ -34,33 +34,33 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@ctrl/mac-address": "^3.1.0",
|
|
37
|
-
"ofetch": "^1.
|
|
37
|
+
"ofetch": "^1.5.1",
|
|
38
38
|
"p-any": "^4.0.0",
|
|
39
|
-
"type-fest": "^5.
|
|
39
|
+
"type-fest": "^5.3.1",
|
|
40
40
|
"ws": "^8.18.3",
|
|
41
41
|
"xml2js": "^0.6.2"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@ctrl/oxlint-config": "1.
|
|
44
|
+
"@ctrl/oxlint-config": "1.3.3",
|
|
45
45
|
"@ctrl/video-filename-parser": "5.4.1",
|
|
46
|
-
"@sindresorhus/tsconfig": "8.0
|
|
47
|
-
"@trivago/prettier-plugin-sort-imports": "
|
|
48
|
-
"@types/node": "
|
|
46
|
+
"@sindresorhus/tsconfig": "8.1.0",
|
|
47
|
+
"@trivago/prettier-plugin-sort-imports": "6.0.0",
|
|
48
|
+
"@types/node": "25.0.3",
|
|
49
49
|
"@types/ws": "8.18.1",
|
|
50
50
|
"@types/xml2js": "0.4.14",
|
|
51
|
-
"@types/yargs": "17.0.
|
|
52
|
-
"@vitest/coverage-v8": "
|
|
53
|
-
"execa": "9.6.
|
|
54
|
-
"globby": "
|
|
51
|
+
"@types/yargs": "17.0.35",
|
|
52
|
+
"@vitest/coverage-v8": "4.0.16",
|
|
53
|
+
"execa": "9.6.1",
|
|
54
|
+
"globby": "16.1.0",
|
|
55
55
|
"make-dir": "5.1.0",
|
|
56
56
|
"ora": "9.0.0",
|
|
57
|
-
"oxlint": "1.
|
|
58
|
-
"p-retry": "7.1.
|
|
59
|
-
"prettier": "3.
|
|
60
|
-
"tsx": "4.
|
|
61
|
-
"typedoc": "0.28.
|
|
57
|
+
"oxlint": "1.35.0",
|
|
58
|
+
"p-retry": "7.1.1",
|
|
59
|
+
"prettier": "3.7.4",
|
|
60
|
+
"tsx": "4.21.0",
|
|
61
|
+
"typedoc": "0.28.15",
|
|
62
62
|
"typescript": "5.9.3",
|
|
63
|
-
"vitest": "
|
|
63
|
+
"vitest": "4.0.16",
|
|
64
64
|
"yargs": "18.0.0"
|
|
65
65
|
},
|
|
66
66
|
"release": {
|
|
@@ -91,5 +91,5 @@
|
|
|
91
91
|
"engines": {
|
|
92
92
|
"node": ">=18"
|
|
93
93
|
},
|
|
94
|
-
"packageManager": "pnpm@10.
|
|
94
|
+
"packageManager": "pnpm@10.26.1"
|
|
95
95
|
}
|