--- install scripts ---
### prepare
pnpm run build
--- package.json (entry) ---
{
"name": "@ctrl/plex",
"version": "6.0.0",
"description": "Plex api client in typescript using ofetch",
"keywords": [
"plex",
"typescript"
],
"license": "MIT",
"author": "Scott Cooper <scttcper@gmail.com>",
"repository": "scttcper/plex",
"files": [
"dist/src"
],
"type": "module",
"sideEffects": false,
"main": "./dist/src/index.js",
"typings": "./dist/src/index.d.ts",
"publishConfig": {
"access": "public"
},
"scripts": {
"lint": "oxlint . && oxfmt --check",
"lint:fix": "oxlint . --fix && oxfmt",
"prepare": "pnpm run build",
"build": "tsc",
"build:docs": "typedoc",
"test": "vitest run",
"bootstraptest": "node scripts/bootstraptest.ts --create-photos",
"teardowntest": "node scripts/teardowntest.ts",
"add-media": "node scripts/add-media.ts",
"test-cleanup": "node scripts/test-cleanup.ts"
},
"dependencies": {
"@ctrl/mac-address": "^3.2.1",
"ofetch": "^1.5.1",
"type-fest": "^5.6.0",
"ws": "^8.20.1",
"xml2js": "^0.6.2"
},
"devDependencies": {
"@ctrl/oxlint-config": "1.5.0",
"@ctrl/video-filename-parser": "5.4.1",
"@sindresorhus/tsconfig": "8.1.0",
"@types/
--- index.js (entry) ---
export * from "./alert.js";
export * from "./client.js";
export * from "./exceptions.js";
export * from "./library.js";
export * from "./media.js";
export * from "./myplex.js";
export * from "./playlist.js";
export * from "./playqueue.js";
export * from "./photo.js";
export * from "./server.js";
export * from "./serverModels.js";
export { Setting, Settings } from "./settings.js";
export * from "./video.js";
export * from "./audio.js";
export { X_PLEX_IDENTIFIER } from "./config.js";
export { SearchResult, Agent, SEARCHTYPES } from "./search.js";
--- bundled output (OSV-MAL flagged — LLM scope expansion) ---
--- dist/src/alert.d.ts (bundled) ---
import WebSocket from 'ws';
import type { AlertTypes } from './alert.types.ts';
import type { PlexServer } from './server.ts';
export declare class AlertListener {
key: string;
_ws?: WebSocket;
private readonly server;
callback: (data: AlertTypes) => void;
constructor(server: PlexServer, callback: (data: AlertTypes) => void);
run(): Promise<void>;
stop(): void;
}
--- dist/src/alert.js (bundled) ---
import WebSocket from 'ws';
export class AlertListener {
key = '/:/websockets/notifications';
server;
callback;
constructor(server, callback) {
this.server = server;
this.callback = callback;
}
async run() {
const url = this.server.url(this.key, { includeToken: true }).toString().replace('http', 'ws');
this._ws = new WebSocket(url);
this._ws.on('message', message => {
try {
const data = JSON.parse(message.toString());
this.callback(data.NotificationContainer);
}
catch (err) {
console.error(err);
}
});
return new Promise(resolve => {
this._ws.on('open', () => {
resolve();
});
});
}
stop() {
this._ws?.close();
}
}
--- dist/src/alert.types.d.ts (bundled) ---
export interface NotificationContainer<T> {
NotificationContainer: T;
}
export interface ActivityNotification {
type: 'activity';
size: number;
ActivityNotification: Array<{
event: string;
uuid: string;
Activity: {
uuid: string;
type: 'library.update.section';
cancellable: false;
userID: 1;
title: string;
subtitle: string;
progress: 0;
};
}>;
}
export interface StatusNotification {
type: 'status';
size: number;
StatusNotification: Array<{
title: string;
description: string;
notificationName: string;
}>;
}
export interface TimelineNotification {
type: 'timeline';
size: number;
TimelineEntry: Array<{
/** eg com.plexapp.plugins.library */
identifier: string;
sectionID: string;
itemID: string;
type: number;
title: string;
state: number;
updatedAt: number;
}>;
}
export interface ReachabilityNotification {
type: 'reachability';
size: number;
TimelineEntry: Array<{
reachability: false;
}>;
}
export interface BackgroundProcessingQueueEventNotification {
type: 'backgroundProcessingQueue';
size: number;
TimelineEntry: Array<{
queueID: number;
event: 'queueRegenerated';
}>;
}
export type AlertTypes = ActivityNotification | StatusNotification | TimelineNotification | ReachabilityNotification | BackgroundProcessingQueueEventNotification;
--- dist/src/alert.types.js (bundled) ---
export {};
--- dist/src/audio.d.ts (bundled) ---
import type { AlbumData, ArtistData, TrackData } from './audio.types.ts';
import { Playable } from './base/playable.ts';
import { PlexObject } from './base/plexObject.ts';
import { Chapter, Collection, Country, Field, Format, Genre, Guid, Image, Label, Media, Mood, Similar, Style, Subformat } from './media.ts';
import type { PlexServer } from './server.ts';
/**
* Base class for all audio objects including Artist, Album, and Track.
*/
export declare class Audio extends Playable {
/** Default metadata type for audio sync items. */
static METADATA_TYPE: string;
/** Hardcoded list type for filtering. */
get listType(): 'audio';
addedAt?: Date;
art?: string;
artBlurHash?: string;
/** Sonic distance from a seed item, used in sonically similar results. */
distance?: number;
guid?: string;
/** Plex index number (often the track number for tracks). */
index?: number;
lastRatedAt?: Date;
lastViewedAt?: Date;
/** Key of the library section this item belongs to. */
librarySectionKey?: string;
/** Title of the library section this item belongs to. */
librarySectionTitle?: string;
/** Plex music analysis version (1 indicates sonic analysis complete). */
musicAnalysisVersion?: number;
summary?: string;
thumb?: string;
thumbBlurHash?: string;
/** Title used for sorting (defaults to title). */
titleSort?: string;
updatedAt?: Date;
/** User rating (0.0-10.0). */
userRating?: number;
/** Count of times the item was played. */
viewCount?: number;
/** Store the raw data from the Plex API for lazy loading related items. */
protected _data?: any;
/** List of field objects. */
fields?: Field[];
/** List of image objects. */
images?: Image[];
/** List of mood objects. */
moods?: Mood[];
/**
* @protected Should not be called directly. Use `server.fetchItem()`.
* Initializes a new instance of the Audio class.
* @param serv
--- dist/src/audio.js (bundled) ---
import { URLSearchParams } from 'node:url';
import { Playable } from "./base/playable.js";
import { PlexObject } from "./base/plexObject.js";
import { fetchItem, fetchItems } from "./baseFunctionality.js";
import { NotFound } from "./exceptions.js";
import { Chapter, Collection, Country, Field, Format, Genre, Guid, Image, Label, Media, Mood, Similar, Style, Subformat, } from "./media.js";
const hasSonicAdventure = (s) => typeof s.sonicAdventure === 'function';
/**
* Base class for all audio objects including Artist, Album, and Track.
*/
export class Audio extends Playable {
/** Default metadata type for audio sync items. */
static METADATA_TYPE = 'track';
/** Hardcoded list type for filtering. */
get listType() {
return 'audio';
}
/**
* @protected Should not be called directly. Use `server.fetchItem()`.
* Initializes a new instance of the Audio class.
* @param server The PlexServer instance used for communication.
* @param data The raw data object received from the Plex API.
* @param initpath The path used to fetch this item initially.
*/
constructor(server, data, initpath, parent) {
super(server, data, initpath, parent);
this._loadData(data);
}
/**
* Returns the full URL for a given part (like a media stream) relative to the item's key.
* Includes the authentication token.
* @param part The relative path or resource identifier.
* @returns The full URL string including the server address and token, or undefined if part is empty.
*/
url(part) {
// This typically refers to sub-resources like media parts, not the main item URL (which is `key`)
// The python version returns server.url(part), let's keep it consistent,
// assuming `part` is something like `/transcode/universal/start?protocol=...` relative to server root,
// or it might be used for things like `/tree`? The python `url` method seems rarely used directly.
--- dist/src/audio.types.d.ts (bundled) ---
import type { ImageData, UltraBlurColorsData } from './media.types.ts';
import type { MediaTagData } from './video.types.ts';
export interface AlbumData {
key: string;
type: string;
title: string;
ratingKey?: string;
guid?: string;
index?: number | string;
summary?: string;
thumb?: string;
art?: string;
librarySectionID?: number | string;
addedAt?: number;
updatedAt?: number;
lastViewedAt?: number;
viewCount?: number;
audienceRating?: number;
leafCount?: number;
loudnessAnalysisVersion?: number | string;
originallyAvailableAt?: string;
parentGuid?: string;
parentKey?: string;
parentRatingKey?: number | string;
parentTheme?: string;
parentThumb?: string;
parentTitle?: string;
rating?: number;
studio?: string;
viewedLeafCount?: number;
year?: number;
Collection?: MediaTagimport { URLSearchParams } from 'node:url';
import { Playable } from "./base/playable.js";
import { PlexObject } from "./base/plexObject.js";
import { fetchItem, fetchItems } from "./baseFunctionality.js";
import { NotFound } from "./exceptions.js";
import { Chapter, Collection, Country, Field, Format, Genre, Guid, Image, Label, Media, Mood, Similar, Style, Subformat, } from "./media.js";
const hasSonicAdventure = (s) => typeof s.sonicAdventure === 'function';
/**
* Base class for all audio objects including Artist, Album, and Track.
*/
export class Audio extends Playable {
/** Default metadata type for audio sync items. */
static METADATA_TYPE = 'track';
/** Hardcoded list type for filtering. */
get listType() {
return 'audio';
}
/**
* @protected Should not be called directly. Use `server.fetchItem()`.
* Initializes a new instance of the Audio class.
* @param server The PlexServer instance used for communication.
* @param data The raw data object received from the Plex API.
* @param initpath The path used to fetch this item initially.
*/
constructor(server, data, initpath, parent) {
super(server, data, initpath, parent);
this._loadData(data);
}
/**
* Returns the full URL for a given part (like a media stream) relative to the item's key.
* Includes the authentication token.
* @param part The relative path or resource identifier.
* @returns The full URL string including the server address and token, or undefined if part is empty.
*/
url(part) {
// This typically refers to sub-resources like media parts, not the main item URL (which is `key`)
// The python version returns server.url(part), let's keep it consistent,
// assuming `part` is something like `/transcode/universal/start?protocol=...` relative to server root,
// or it might be used for things like `/tree`? The python `url` method seems rarely used directly.
{
"name": "@ctrl/plex",
"version": "6.0.0",
"description": "Plex api client in typescript using ofetch",
"keywords": [
"plex",
"typescript"
],
"license": "MIT",
"author": "Scott Cooper <scttcper@gmail.com>",
"repository": "scttcper/plex",
"files": [
"dist/src"
],
"type": "module",
"sideEffects": false,
"main": "./dist/src/index.js",
"typings": "./dist/src/index.d.ts",
"publishConfig": {
"access": "public"
},
"scripts": {
"lint": "oxlint . && oxfmt --check",
"lint:fix": "oxlint . --fix && oxfmt",
"prepare": "pnpm run build",
"build": "tsc",
"build:docs": "typedoc",
"test": "vitest run",
"bootstraptest": "node scripts/bootstraptest.ts --create-photos",
"teardowntest": "node scripts/teardowntest.ts",
"add-media": "node scripts/add-media.ts",
"test-cleanup": "node scripts/test-cleanup.ts"
},
"dependencies": {
"@ctrl/mac-address": "^3.2.1",
"ofetch": "^1.5.1",
"type-fest": "^5.6.0",
"ws": "^8.20.1",
"xml2js": "^0.6.2"
},
"devDependencies": {
"@ctrl/oxlint-config": "1.5.0",
"@ctrl/video-filename-parser": "5.4.1",
"@sindresorhus/tsconfig": "8.1.0",
"@types/