@ctrl/plex 3.4.0 → 3.6.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/README.md +9 -3
- package/dist/src/alert.d.ts +2 -2
- package/dist/src/base/partialPlexObject.js +13 -13
- package/dist/src/client.d.ts +1 -1
- package/dist/src/config.d.ts +2 -1
- package/dist/src/config.js +2 -1
- package/dist/src/library.d.ts +6 -6
- package/dist/src/library.js +2 -2
- package/dist/src/library.types.d.ts +1 -1
- package/dist/src/media.d.ts +139 -1
- package/dist/src/media.js +153 -4
- package/dist/src/myplex.js +0 -1
- package/dist/src/playlist.d.ts +2 -2
- package/dist/src/search.d.ts +2 -2
- package/dist/src/server.d.ts +1 -1
- package/dist/src/video.d.ts +3 -3
- package/package.json +21 -20
package/README.md
CHANGED
|
@@ -105,7 +105,8 @@ npm run test-cleanup
|
|
|
105
105
|
get a claim token from https://www.plex.tv/claim/
|
|
106
106
|
export PLEX_CLAIM_TOKEN=claim-token
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
start plex container for testing
|
|
109
|
+
```console
|
|
109
110
|
docker run -d \
|
|
110
111
|
--name=plex \
|
|
111
112
|
--net=host \
|
|
@@ -132,7 +133,12 @@ docker run -d \
|
|
|
132
133
|
lscr.io/linuxserver/plex:latest
|
|
133
134
|
```
|
|
134
135
|
|
|
135
|
-
|
|
136
|
+
Pull latest plex container if needed
|
|
137
|
+
```console
|
|
138
|
+
docker pull lscr.io/linuxserver/plex:latest
|
|
136
139
|
```
|
|
137
|
-
|
|
140
|
+
|
|
141
|
+
bootstrap plex server with test media
|
|
142
|
+
```console
|
|
143
|
+
NODE_OPTIONS="--loader ts-node/esm" node scripts/bootstraptest.ts --no-docker --server-name=orbstack --password=$PLEX_PASSWORD --username=$PLEX_USERNAME
|
|
138
144
|
```
|
package/dist/src/alert.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import WebSocket from 'ws';
|
|
2
|
-
import { AlertTypes } from './alert.types.js';
|
|
3
|
-
import { PlexServer } from './server.js';
|
|
2
|
+
import type { AlertTypes } from './alert.types.js';
|
|
3
|
+
import type { PlexServer } from './server.js';
|
|
4
4
|
export declare class AlertListener {
|
|
5
5
|
private readonly server;
|
|
6
6
|
callback: (data: AlertTypes) => void;
|
|
@@ -6,25 +6,25 @@ export class PartialPlexObject extends PlexObject {
|
|
|
6
6
|
constructor() {
|
|
7
7
|
super(...arguments);
|
|
8
8
|
this._INCLUDES = {
|
|
9
|
-
checkFiles:
|
|
10
|
-
includeAllConcerts:
|
|
9
|
+
checkFiles: 0,
|
|
10
|
+
includeAllConcerts: 0,
|
|
11
11
|
includeBandwidths: 1,
|
|
12
12
|
includeChapters: 1,
|
|
13
|
-
includeChildren:
|
|
14
|
-
includeConcerts:
|
|
15
|
-
includeExternalMedia:
|
|
16
|
-
includeExtras:
|
|
13
|
+
includeChildren: 0,
|
|
14
|
+
includeConcerts: 0,
|
|
15
|
+
includeExternalMedia: 0,
|
|
16
|
+
includeExtras: 0,
|
|
17
17
|
includeFields: 'thumbBlurHash,artBlurHash',
|
|
18
18
|
includeGeolocation: 1,
|
|
19
19
|
includeLoudnessRamps: 1,
|
|
20
20
|
includeMarkers: 1,
|
|
21
|
-
includeOnDeck:
|
|
22
|
-
includePopularLeaves:
|
|
23
|
-
includePreferences:
|
|
24
|
-
includeRelated:
|
|
25
|
-
includeRelatedCount:
|
|
26
|
-
includeReviews:
|
|
27
|
-
includeStations:
|
|
21
|
+
includeOnDeck: 0,
|
|
22
|
+
includePopularLeaves: 0,
|
|
23
|
+
includePreferences: 0,
|
|
24
|
+
includeRelated: 0,
|
|
25
|
+
includeRelatedCount: 0,
|
|
26
|
+
includeReviews: 0,
|
|
27
|
+
includeStations: 0,
|
|
28
28
|
};
|
|
29
29
|
this._detailsKey = this._buildDetailsKey();
|
|
30
30
|
}
|
package/dist/src/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { URL } from 'url';
|
|
2
|
-
import { Player } from './client.types.js';
|
|
2
|
+
import type { Player } from './client.types.js';
|
|
3
3
|
export interface PlexOptions {
|
|
4
4
|
/** (:class:`~plexapi.server.PlexServer`): PlexServer this client is connected to (optional). */
|
|
5
5
|
server?: any;
|
package/dist/src/config.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export declare const BASE_HEADERS: {
|
|
|
23
23
|
readonly 'X-Plex-Device': string;
|
|
24
24
|
readonly 'X-Plex-Device-Name': string;
|
|
25
25
|
readonly 'X-Plex-Client-Identifier': string;
|
|
26
|
-
readonly 'X-Plex-Sync-Version': "2";
|
|
27
26
|
readonly 'X-Plex-Language': "en";
|
|
27
|
+
readonly 'X-Plex-Sync-Version': "2";
|
|
28
|
+
readonly 'X-Plex-Features': "external-media";
|
|
28
29
|
};
|
package/dist/src/config.js
CHANGED
|
@@ -33,6 +33,7 @@ export const BASE_HEADERS = {
|
|
|
33
33
|
'X-Plex-Device': X_PLEX_DEVICE,
|
|
34
34
|
'X-Plex-Device-Name': X_PLEX_DEVICE_NAME,
|
|
35
35
|
'X-Plex-Client-Identifier': X_PLEX_IDENTIFIER,
|
|
36
|
-
'X-Plex-Sync-Version': '2',
|
|
37
36
|
'X-Plex-Language': 'en',
|
|
37
|
+
'X-Plex-Sync-Version': '2',
|
|
38
|
+
'X-Plex-Features': 'external-media',
|
|
38
39
|
};
|
package/dist/src/library.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { Class } from 'type-fest';
|
|
1
|
+
import type { Class } from 'type-fest';
|
|
2
2
|
import { PartialPlexObject } from './base/partialPlexObject.js';
|
|
3
3
|
import { PlexObject } from './base/plexObject.js';
|
|
4
|
-
import { CollectionData, LibraryRootResponse, Location, SectionsDirectory } from './library.types.js';
|
|
4
|
+
import type { CollectionData, LibraryRootResponse, Location, SectionsDirectory } from './library.types.js';
|
|
5
5
|
import { Playlist } from './playlist.js';
|
|
6
|
-
import { Agent, SEARCHTYPES } from './search.js';
|
|
7
|
-
import { SearchResult } from './search.types.js';
|
|
6
|
+
import { type Agent, type SEARCHTYPES } from './search.js';
|
|
7
|
+
import type { SearchResult } from './search.types.js';
|
|
8
8
|
import type { PlexServer } from './server.js';
|
|
9
|
-
import { Movie, Show, VideoType } from './video.js';
|
|
9
|
+
import { Movie, Show, type VideoType } from './video.js';
|
|
10
10
|
export type Section = MovieSection | ShowSection;
|
|
11
11
|
export declare class Library {
|
|
12
12
|
private readonly server;
|
|
@@ -364,7 +364,7 @@ export declare abstract class LibrarySection<SectionVideoType = VideoType> exten
|
|
|
364
364
|
folders(): Promise<Folder[]>;
|
|
365
365
|
genres(): Promise<FilterChoice[]>;
|
|
366
366
|
/**
|
|
367
|
-
* Returns a list of available {@link
|
|
367
|
+
* Returns a list of available {@link FilteringField} for a specified libtype.
|
|
368
368
|
* This is the list of options in the custom filter dropdown menu
|
|
369
369
|
*/
|
|
370
370
|
listFields(libtype?: Libtype): Promise<FilteringField[]>;
|
package/dist/src/library.js
CHANGED
|
@@ -483,7 +483,7 @@ export class LibrarySection extends PlexObject {
|
|
|
483
483
|
return fetchItems(this.server, key, undefined, FilterChoice);
|
|
484
484
|
}
|
|
485
485
|
/**
|
|
486
|
-
* Returns a list of available {@link
|
|
486
|
+
* Returns a list of available {@link FilteringField} for a specified libtype.
|
|
487
487
|
* This is the list of options in the custom filter dropdown menu
|
|
488
488
|
*/
|
|
489
489
|
async listFields(libtype = this.type) {
|
|
@@ -494,7 +494,7 @@ export class LibrarySection extends PlexObject {
|
|
|
494
494
|
const filter = filterTypes.find(f => f.type === libtype);
|
|
495
495
|
if (!filter) {
|
|
496
496
|
throw new NotFound(`Unknown libtype "${libtype}" for this library.
|
|
497
|
-
Available libtypes: ${filterTypes.join(', ')}`);
|
|
497
|
+
Available libtypes: ${filterTypes.map(f => f.type).join(', ')}`);
|
|
498
498
|
}
|
|
499
499
|
return filter;
|
|
500
500
|
}
|
package/dist/src/media.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PlexObject } from './base/plexObject.js';
|
|
2
|
-
import { ChapterData, MarkerData, MediaData, MediaPartData, MediaPartStreamData } from './video.types.js';
|
|
2
|
+
import type { ChapterData, MarkerData, MediaData, MediaPartData, MediaPartStreamData } from './video.types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Base class for media tags used for filtering and searching your library
|
|
5
5
|
* items or navigating the metadata of media items in your library. Tags are
|
|
@@ -74,6 +74,28 @@ export declare class MediaPart extends PlexObject {
|
|
|
74
74
|
videoProfile: string;
|
|
75
75
|
streams: MediaPartStream[];
|
|
76
76
|
exists?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Set the selected {@link AudioStream} for this MediaPart.
|
|
79
|
+
* @param stream Audio stream or stream ID to set as selected.
|
|
80
|
+
*/
|
|
81
|
+
setSelectedAudioStream(stream: AudioStream | number): Promise<this>;
|
|
82
|
+
/**
|
|
83
|
+
* Set the selected {@link SubtitleStream} for this MediaPart.
|
|
84
|
+
* @param stream Subtitle stream or stream ID to set as selected.
|
|
85
|
+
*/
|
|
86
|
+
setSelectedSubtitleStream(stream: SubtitleStream | number): Promise<this>;
|
|
87
|
+
/**
|
|
88
|
+
* Returns a list of {@link AudioStream} objects in this MediaPart.
|
|
89
|
+
*/
|
|
90
|
+
audioStreams(): AudioStream[];
|
|
91
|
+
/**
|
|
92
|
+
* Returns a list of {@link SubtitleStream} objects in this MediaPart.
|
|
93
|
+
*/
|
|
94
|
+
subtitleStreams(): SubtitleStream[];
|
|
95
|
+
/**
|
|
96
|
+
* Returns a list of {@link LyricStream} objects in this MediaPart.
|
|
97
|
+
*/
|
|
98
|
+
lyricStreams(): LyricStream[];
|
|
77
99
|
protected _loadData(data: MediaPartData): void;
|
|
78
100
|
}
|
|
79
101
|
export declare class MediaPartStream extends PlexObject {
|
|
@@ -87,6 +109,59 @@ export declare class MediaPartStream extends PlexObject {
|
|
|
87
109
|
streamType?: number;
|
|
88
110
|
protected _loadData(data: MediaPartStreamData): void;
|
|
89
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Represents a single Subtitle stream within a {@link MediaPart}.
|
|
114
|
+
*/
|
|
115
|
+
export declare class SubtitleStream extends MediaPartStream {
|
|
116
|
+
static TAG: "Stream";
|
|
117
|
+
static STREAMTYPE: number;
|
|
118
|
+
/** True if the subtitle stream can be auto synced. */
|
|
119
|
+
canAutoSync?: boolean;
|
|
120
|
+
/** The container of the subtitle stream. */
|
|
121
|
+
container?: string;
|
|
122
|
+
/** True if this is a forced subtitle. */
|
|
123
|
+
forced: boolean;
|
|
124
|
+
/** The format of the subtitle stream (ex: srt). */
|
|
125
|
+
format?: string;
|
|
126
|
+
/** The header compression of the subtitle stream. */
|
|
127
|
+
headerCompression?: string;
|
|
128
|
+
/** True if this is a hearing impaired (SDH) subtitle. */
|
|
129
|
+
hearingImpaired: boolean;
|
|
130
|
+
/** True if the on-demand subtitle is a perfect match. */
|
|
131
|
+
perfectMatch?: boolean;
|
|
132
|
+
/** The provider title where the on-demand subtitle is downloaded from. */
|
|
133
|
+
providerTitle?: string;
|
|
134
|
+
/** The match score (download count) of the on-demand subtitle. */
|
|
135
|
+
score?: number;
|
|
136
|
+
/** The source key of the on-demand subtitle. */
|
|
137
|
+
sourceKey?: string;
|
|
138
|
+
/** Unknown. */
|
|
139
|
+
transient?: string;
|
|
140
|
+
/** The user id of the user that downloaded the on-demand subtitle. */
|
|
141
|
+
userID?: number;
|
|
142
|
+
/**
|
|
143
|
+
* Sets this subtitle stream as the selected subtitle stream.
|
|
144
|
+
* Alias for `MediaPart.setSelectedSubtitleStream`.
|
|
145
|
+
*/
|
|
146
|
+
setSelected(): Promise<void>;
|
|
147
|
+
protected _loadData(data: any): void;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Represents a single Lyric stream within a {@link MediaPart}.
|
|
151
|
+
*/
|
|
152
|
+
export declare class LyricStream extends MediaPartStream {
|
|
153
|
+
static TAG: "Stream";
|
|
154
|
+
static STREAMTYPE: number;
|
|
155
|
+
/** The format of the lyric stream (ex: lrc). */
|
|
156
|
+
format?: string;
|
|
157
|
+
/** The minimum number of lines in the (timed) lyric stream. */
|
|
158
|
+
minLines?: number;
|
|
159
|
+
/** The provider of the lyric stream (ex: com.plexapp.agents.lyricfind). */
|
|
160
|
+
provider?: string;
|
|
161
|
+
/** True if the lyrics are timed to the track. */
|
|
162
|
+
timed: boolean;
|
|
163
|
+
protected _loadData(data: any): void;
|
|
164
|
+
}
|
|
90
165
|
/**
|
|
91
166
|
* Represents a single Role (actor/actress) media tag.
|
|
92
167
|
*/
|
|
@@ -164,6 +239,20 @@ export declare class Optimized extends PlexObject {
|
|
|
164
239
|
type: any;
|
|
165
240
|
target: any;
|
|
166
241
|
targetTagID: any;
|
|
242
|
+
/**
|
|
243
|
+
* Remove this Optimized item.
|
|
244
|
+
*/
|
|
245
|
+
remove(): Promise<void>;
|
|
246
|
+
/**
|
|
247
|
+
* Rename this Optimized item.
|
|
248
|
+
* @param title New title for the item.
|
|
249
|
+
*/
|
|
250
|
+
rename(title: string): Promise<void>;
|
|
251
|
+
/**
|
|
252
|
+
* Reprocess a removed Conversion item that is still a listed Optimize item.
|
|
253
|
+
* @param ratingKey The rating key of the item to reprocess.
|
|
254
|
+
*/
|
|
255
|
+
reprocess(ratingKey: string | number): Promise<void>;
|
|
167
256
|
protected _loadData(data: any): void;
|
|
168
257
|
}
|
|
169
258
|
/**
|
|
@@ -242,4 +331,53 @@ export declare class Poster extends BaseResource {
|
|
|
242
331
|
export declare class Theme extends BaseResource {
|
|
243
332
|
static TAG: string;
|
|
244
333
|
}
|
|
334
|
+
/**
|
|
335
|
+
* Represents a single Audio stream within a {@link MediaPart}.
|
|
336
|
+
*/
|
|
337
|
+
export declare class AudioStream extends MediaPartStream {
|
|
338
|
+
static TAG: "Stream";
|
|
339
|
+
static STREAMTYPE: number;
|
|
340
|
+
/** The audio channel layout of the audio stream (ex: 5.1(side)). */
|
|
341
|
+
audioChannelLayout?: string;
|
|
342
|
+
/** The bit depth of the audio stream (ex: 16). */
|
|
343
|
+
bitDepth?: number;
|
|
344
|
+
/** The bitrate mode of the audio stream (ex: cbr). */
|
|
345
|
+
bitrateMode?: string;
|
|
346
|
+
/** The number of audio channels of the audio stream (ex: 6). */
|
|
347
|
+
channels?: number;
|
|
348
|
+
/** The duration of audio stream in milliseconds. */
|
|
349
|
+
duration?: number;
|
|
350
|
+
/** The profile of the audio stream. */
|
|
351
|
+
profile?: string;
|
|
352
|
+
/** The sampling rate of the audio stream (ex: 48000) */
|
|
353
|
+
samplingRate?: number;
|
|
354
|
+
/** The stream identifier of the audio stream. */
|
|
355
|
+
streamIdentifier?: number;
|
|
356
|
+
/** True if this is a visually impaired (AD) audio stream. */
|
|
357
|
+
visualImpaired: boolean;
|
|
358
|
+
/** The gain for the album. */
|
|
359
|
+
albumGain?: number;
|
|
360
|
+
/** The peak for the album. */
|
|
361
|
+
albumPeak?: number;
|
|
362
|
+
/** The range for the album. */
|
|
363
|
+
albumRange?: number;
|
|
364
|
+
/** The end ramp for the track. */
|
|
365
|
+
endRamp?: string;
|
|
366
|
+
/** The gain for the track. */
|
|
367
|
+
gain?: number;
|
|
368
|
+
/** The loudness for the track. */
|
|
369
|
+
loudness?: number;
|
|
370
|
+
/** The lra for the track. */
|
|
371
|
+
lra?: number;
|
|
372
|
+
/** The peak for the track. */
|
|
373
|
+
peak?: number;
|
|
374
|
+
/** The start ramp for the track. */
|
|
375
|
+
startRamp?: string;
|
|
376
|
+
/**
|
|
377
|
+
* Sets this audio stream as the selected audio stream.
|
|
378
|
+
* Alias for {@link MediaPart.setSelectedAudioStream}.
|
|
379
|
+
*/
|
|
380
|
+
setSelected(): Promise<void>;
|
|
381
|
+
protected _loadData(data: any): void;
|
|
382
|
+
}
|
|
245
383
|
export {};
|
package/dist/src/media.js
CHANGED
|
@@ -40,6 +40,48 @@ export class Media extends PlexObject {
|
|
|
40
40
|
}
|
|
41
41
|
export class MediaPart extends PlexObject {
|
|
42
42
|
static { this.TAG = 'Part'; }
|
|
43
|
+
/**
|
|
44
|
+
* Set the selected {@link AudioStream} for this MediaPart.
|
|
45
|
+
* @param stream Audio stream or stream ID to set as selected.
|
|
46
|
+
*/
|
|
47
|
+
async setSelectedAudioStream(stream) {
|
|
48
|
+
const key = `/library/parts/${this.id}`;
|
|
49
|
+
const params = new URLSearchParams({ allParts: '1' });
|
|
50
|
+
const streamId = typeof stream === 'number' ? stream : stream.id;
|
|
51
|
+
params.set('audioStreamID', streamId.toString());
|
|
52
|
+
await this.server.query(key + '?' + params.toString(), 'put');
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Set the selected {@link SubtitleStream} for this MediaPart.
|
|
57
|
+
* @param stream Subtitle stream or stream ID to set as selected.
|
|
58
|
+
*/
|
|
59
|
+
async setSelectedSubtitleStream(stream) {
|
|
60
|
+
const key = `/library/parts/${this.id}`;
|
|
61
|
+
const params = new URLSearchParams({ allParts: '1' });
|
|
62
|
+
const streamId = typeof stream === 'number' ? stream : stream.id;
|
|
63
|
+
params.set('subtitleStreamID', streamId.toString());
|
|
64
|
+
await this.server.query(key + '?' + params.toString(), 'put');
|
|
65
|
+
return this;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Returns a list of {@link AudioStream} objects in this MediaPart.
|
|
69
|
+
*/
|
|
70
|
+
audioStreams() {
|
|
71
|
+
return this.streams.filter((stream) => stream instanceof AudioStream);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Returns a list of {@link SubtitleStream} objects in this MediaPart.
|
|
75
|
+
*/
|
|
76
|
+
subtitleStreams() {
|
|
77
|
+
return this.streams.filter((stream) => stream instanceof SubtitleStream);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Returns a list of {@link LyricStream} objects in this MediaPart.
|
|
81
|
+
*/
|
|
82
|
+
lyricStreams() {
|
|
83
|
+
return this.streams.filter((stream) => stream instanceof LyricStream);
|
|
84
|
+
}
|
|
43
85
|
_loadData(data) {
|
|
44
86
|
this.container = data.container;
|
|
45
87
|
this.duration = data.duration;
|
|
@@ -66,6 +108,53 @@ export class MediaPartStream extends PlexObject {
|
|
|
66
108
|
this.streamType = data.streamType;
|
|
67
109
|
}
|
|
68
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* Represents a single Subtitle stream within a {@link MediaPart}.
|
|
113
|
+
*/
|
|
114
|
+
export class SubtitleStream extends MediaPartStream {
|
|
115
|
+
static { this.TAG = 'Stream'; }
|
|
116
|
+
static { this.STREAMTYPE = 3; }
|
|
117
|
+
/**
|
|
118
|
+
* Sets this subtitle stream as the selected subtitle stream.
|
|
119
|
+
* Alias for `MediaPart.setSelectedSubtitleStream`.
|
|
120
|
+
*/
|
|
121
|
+
async setSelected() {
|
|
122
|
+
const parent = this.parent?.deref();
|
|
123
|
+
if (!parent) {
|
|
124
|
+
throw new Error('SubtitleStream must have a parent MediaPart');
|
|
125
|
+
}
|
|
126
|
+
await parent.setSelectedSubtitleStream(this);
|
|
127
|
+
}
|
|
128
|
+
_loadData(data) {
|
|
129
|
+
super._loadData(data);
|
|
130
|
+
this.canAutoSync = Boolean(data.canAutoSync); // Use !! for boolean casting from potential string/number
|
|
131
|
+
this.container = data.container;
|
|
132
|
+
this.forced = Boolean(parseInt(data.forced ?? '0', 10));
|
|
133
|
+
this.format = data.format;
|
|
134
|
+
this.headerCompression = data.headerCompression;
|
|
135
|
+
this.hearingImpaired = Boolean(parseInt(data.hearingImpaired ?? '0', 10));
|
|
136
|
+
this.perfectMatch = Boolean(data.perfectMatch);
|
|
137
|
+
this.providerTitle = data.providerTitle;
|
|
138
|
+
this.score = data.score ? parseInt(data.score, 10) : undefined;
|
|
139
|
+
this.sourceKey = data.sourceKey;
|
|
140
|
+
this.transient = data.transient;
|
|
141
|
+
this.userID = data.userID ? parseInt(data.userID, 10) : undefined;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Represents a single Lyric stream within a {@link MediaPart}.
|
|
146
|
+
*/
|
|
147
|
+
export class LyricStream extends MediaPartStream {
|
|
148
|
+
static { this.TAG = 'Stream'; }
|
|
149
|
+
static { this.STREAMTYPE = 4; }
|
|
150
|
+
_loadData(data) {
|
|
151
|
+
super._loadData(data);
|
|
152
|
+
this.format = data.format;
|
|
153
|
+
this.minLines = data.minLines ? parseInt(data.minLines, 10) : undefined;
|
|
154
|
+
this.provider = data.provider;
|
|
155
|
+
this.timed = Boolean(parseInt(data.timed ?? '0', 10));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
69
158
|
/**
|
|
70
159
|
* Represents a single Role (actor/actress) media tag.
|
|
71
160
|
*/
|
|
@@ -169,6 +258,30 @@ export class Collection extends MediaTag {
|
|
|
169
258
|
}
|
|
170
259
|
export class Optimized extends PlexObject {
|
|
171
260
|
static { this.TAG = 'Item'; }
|
|
261
|
+
// TODO: Implement items()
|
|
262
|
+
/**
|
|
263
|
+
* Remove this Optimized item.
|
|
264
|
+
*/
|
|
265
|
+
async remove() {
|
|
266
|
+
const key = `${this.key}/${this.id}`;
|
|
267
|
+
await this.server.query(key, 'delete');
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Rename this Optimized item.
|
|
271
|
+
* @param title New title for the item.
|
|
272
|
+
*/
|
|
273
|
+
async rename(title) {
|
|
274
|
+
const key = `${this.key}/${this.id}?Item[title]=${encodeURIComponent(title)}`;
|
|
275
|
+
await this.server.query(key, 'put');
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Reprocess a removed Conversion item that is still a listed Optimize item.
|
|
279
|
+
* @param ratingKey The rating key of the item to reprocess.
|
|
280
|
+
*/
|
|
281
|
+
async reprocess(ratingKey) {
|
|
282
|
+
const key = `${this.key}/${this.id}/${ratingKey}/enable`;
|
|
283
|
+
await this.server.query(key, 'put');
|
|
284
|
+
}
|
|
172
285
|
_loadData(data) {
|
|
173
286
|
this.id = data.id;
|
|
174
287
|
this.composite = data.composite;
|
|
@@ -186,7 +299,6 @@ class GuidTag extends PlexObject {
|
|
|
186
299
|
this.id = data.id;
|
|
187
300
|
}
|
|
188
301
|
}
|
|
189
|
-
// biome-ignore lint/complexity/noStaticOnlyClass: <explanation>
|
|
190
302
|
export class Guid extends GuidTag {
|
|
191
303
|
static { this.TAG = 'Guid'; }
|
|
192
304
|
}
|
|
@@ -235,21 +347,58 @@ class BaseResource extends PlexObject {
|
|
|
235
347
|
/**
|
|
236
348
|
* Represents a single Art object.
|
|
237
349
|
*/
|
|
238
|
-
// biome-ignore lint/complexity/noStaticOnlyClass: <explanation>
|
|
239
350
|
export class Art extends BaseResource {
|
|
240
351
|
static { this.TAG = 'Art'; }
|
|
241
352
|
}
|
|
242
353
|
/**
|
|
243
354
|
* Represents a single Poster object.
|
|
244
355
|
*/
|
|
245
|
-
// biome-ignore lint/complexity/noStaticOnlyClass: <explanation>
|
|
246
356
|
export class Poster extends BaseResource {
|
|
247
357
|
static { this.TAG = 'Photo'; }
|
|
248
358
|
}
|
|
249
359
|
/**
|
|
250
360
|
* Represents a single Theme object.
|
|
251
361
|
*/
|
|
252
|
-
// biome-ignore lint/complexity/noStaticOnlyClass: <explanation>
|
|
253
362
|
export class Theme extends BaseResource {
|
|
254
363
|
static { this.TAG = 'Theme'; }
|
|
255
364
|
}
|
|
365
|
+
/**
|
|
366
|
+
* Represents a single Audio stream within a {@link MediaPart}.
|
|
367
|
+
*/
|
|
368
|
+
export class AudioStream extends MediaPartStream {
|
|
369
|
+
static { this.TAG = 'Stream'; }
|
|
370
|
+
static { this.STREAMTYPE = 2; }
|
|
371
|
+
/**
|
|
372
|
+
* Sets this audio stream as the selected audio stream.
|
|
373
|
+
* Alias for {@link MediaPart.setSelectedAudioStream}.
|
|
374
|
+
*/
|
|
375
|
+
async setSelected() {
|
|
376
|
+
const parent = this.parent?.deref();
|
|
377
|
+
if (!parent) {
|
|
378
|
+
throw new Error('AudioStream must have a parent MediaPart');
|
|
379
|
+
}
|
|
380
|
+
await parent.setSelectedAudioStream(this);
|
|
381
|
+
}
|
|
382
|
+
_loadData(data) {
|
|
383
|
+
super._loadData(data);
|
|
384
|
+
this.audioChannelLayout = data.audioChannelLayout;
|
|
385
|
+
this.bitDepth = data.bitDepth ? parseInt(data.bitDepth, 10) : undefined;
|
|
386
|
+
this.bitrateMode = data.bitrateMode;
|
|
387
|
+
this.channels = data.channels ? parseInt(data.channels, 10) : undefined;
|
|
388
|
+
this.duration = data.duration ? parseInt(data.duration, 10) : undefined;
|
|
389
|
+
this.profile = data.profile;
|
|
390
|
+
this.samplingRate = data.samplingRate ? parseInt(data.samplingRate, 10) : undefined;
|
|
391
|
+
this.streamIdentifier = data.streamIdentifier ? parseInt(data.streamIdentifier, 10) : undefined;
|
|
392
|
+
this.visualImpaired = Boolean(parseInt(data.visualImpaired ?? '0', 10));
|
|
393
|
+
// Track only attributes
|
|
394
|
+
this.albumGain = data.albumGain ? parseFloat(data.albumGain) : undefined;
|
|
395
|
+
this.albumPeak = data.albumPeak ? parseFloat(data.albumPeak) : undefined;
|
|
396
|
+
this.albumRange = data.albumRange ? parseFloat(data.albumRange) : undefined;
|
|
397
|
+
this.endRamp = data.endRamp;
|
|
398
|
+
this.gain = data.gain ? parseFloat(data.gain) : undefined;
|
|
399
|
+
this.loudness = data.loudness ? parseFloat(data.loudness) : undefined;
|
|
400
|
+
this.lra = data.lra ? parseFloat(data.lra) : undefined;
|
|
401
|
+
this.peak = data.peak ? parseFloat(data.peak) : undefined;
|
|
402
|
+
this.startRamp = data.startRamp;
|
|
403
|
+
}
|
|
404
|
+
}
|
package/dist/src/myplex.js
CHANGED
package/dist/src/playlist.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Playable } from './base/playable.js';
|
|
2
2
|
import type { Section } from './library.js';
|
|
3
|
-
import { PlaylistResponse } from './playlist.types.js';
|
|
3
|
+
import type { PlaylistResponse } from './playlist.types.js';
|
|
4
4
|
import type { PlexServer } from './server.js';
|
|
5
|
-
import { Episode, Movie, VideoType } from './video.js';
|
|
5
|
+
import { Episode, Movie, type VideoType } from './video.js';
|
|
6
6
|
interface CreateRegularPlaylistOptions {
|
|
7
7
|
/** True to create a smart playlist */
|
|
8
8
|
smart?: false;
|
package/dist/src/search.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ValueOf } from 'type-fest';
|
|
1
|
+
import type { ValueOf } from 'type-fest';
|
|
2
2
|
import { PlexObject } from './base/plexObject.js';
|
|
3
|
-
import { MatchSearchResult } from './search.types.js';
|
|
3
|
+
import type { MatchSearchResult } from './search.types.js';
|
|
4
4
|
export declare class SearchResult extends PlexObject {
|
|
5
5
|
static TAG: string;
|
|
6
6
|
guid: string;
|
package/dist/src/server.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { Hub, Library } from './library.js';
|
|
|
4
4
|
import { Optimized } from './media.js';
|
|
5
5
|
import { MyPlexAccount } from './myplex.js';
|
|
6
6
|
import { Agent, SEARCHTYPES } from './search.js';
|
|
7
|
-
import { HistoryMetadatum } from './server.types.js';
|
|
7
|
+
import type { HistoryMetadatum } from './server.types.js';
|
|
8
8
|
import { Settings } from './settings.js';
|
|
9
9
|
/**
|
|
10
10
|
* This is the main entry point to interacting with a Plex server. It allows you to
|
package/dist/src/video.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { URL } from 'url';
|
|
1
|
+
import type { URL } from 'url';
|
|
2
2
|
import { Playable } from './base/playable.js';
|
|
3
|
-
import { ExtrasData, FullShowData, MovieData, ShowData } from './library.types.js';
|
|
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';
|
|
5
|
-
import { ChapterSource, EpisodeMetadata, FullMovieResponse } from './video.types.js';
|
|
5
|
+
import type { ChapterSource, EpisodeMetadata, FullMovieResponse } from './video.types.js';
|
|
6
6
|
export type VideoType = Movie | Show;
|
|
7
7
|
declare abstract class Video extends Playable {
|
|
8
8
|
/** Datetime this item was added to the library. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ctrl/plex",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"description": "plex api client in typescript",
|
|
5
5
|
"author": "Scott Cooper <scttcper@gmail.com>",
|
|
6
6
|
"publishConfig": {
|
|
@@ -37,32 +37,32 @@
|
|
|
37
37
|
"test-cleanup": "node --loader ts-node/esm scripts/test-cleanup.ts"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@ctrl/mac-address": "^3.0
|
|
41
|
-
"ofetch": "^1.
|
|
40
|
+
"@ctrl/mac-address": "^3.1.0",
|
|
41
|
+
"ofetch": "^1.4.1",
|
|
42
42
|
"p-any": "^4.0.0",
|
|
43
|
-
"type-fest": "^4.
|
|
44
|
-
"ws": "^8.18.
|
|
43
|
+
"type-fest": "^4.40.1",
|
|
44
|
+
"ws": "^8.18.2",
|
|
45
45
|
"xml2js": "^0.6.2"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@biomejs/biome": "1.
|
|
49
|
-
"@ctrl/eslint-config-biome": "4.
|
|
50
|
-
"@sindresorhus/tsconfig": "
|
|
51
|
-
"@types/node": "22.3
|
|
52
|
-
"@types/ws": "8.
|
|
48
|
+
"@biomejs/biome": "1.9.4",
|
|
49
|
+
"@ctrl/eslint-config-biome": "4.4.0",
|
|
50
|
+
"@sindresorhus/tsconfig": "7.0.0",
|
|
51
|
+
"@types/node": "22.15.3",
|
|
52
|
+
"@types/ws": "8.18.1",
|
|
53
53
|
"@types/xml2js": "0.4.14",
|
|
54
54
|
"@types/yargs": "17.0.33",
|
|
55
|
-
"@vitest/coverage-v8": "
|
|
56
|
-
"eslint": "9.
|
|
57
|
-
"execa": "9.
|
|
58
|
-
"globby": "14.0
|
|
55
|
+
"@vitest/coverage-v8": "3.1.2",
|
|
56
|
+
"eslint": "9.26.0",
|
|
57
|
+
"execa": "9.5.2",
|
|
58
|
+
"globby": "14.1.0",
|
|
59
59
|
"make-dir": "5.0.0",
|
|
60
|
-
"ora": "8.0
|
|
61
|
-
"p-retry": "6.2.
|
|
60
|
+
"ora": "8.2.0",
|
|
61
|
+
"p-retry": "6.2.1",
|
|
62
62
|
"ts-node": "10.9.2",
|
|
63
|
-
"typedoc": "0.
|
|
64
|
-
"typescript": "5.
|
|
65
|
-
"vitest": "
|
|
63
|
+
"typedoc": "0.28.3",
|
|
64
|
+
"typescript": "5.8.3",
|
|
65
|
+
"vitest": "3.1.2",
|
|
66
66
|
"yargs": "17.7.2"
|
|
67
67
|
},
|
|
68
68
|
"release": {
|
|
@@ -72,5 +72,6 @@
|
|
|
72
72
|
},
|
|
73
73
|
"engines": {
|
|
74
74
|
"node": ">=18"
|
|
75
|
-
}
|
|
75
|
+
},
|
|
76
|
+
"packageManager": "pnpm@10.10.0"
|
|
76
77
|
}
|