mirror of
https://github.com/LukeHagar/plexjs.git
synced 2025-12-06 04:20:46 +00:00
Delete src directory
This commit is contained in:
@@ -1,47 +0,0 @@
|
|||||||
import { Environment } from './http/Environment';
|
|
||||||
import HTTPLibrary from './http/HTTPLibrary';
|
|
||||||
import { Headers } from './http/HTTPClient';
|
|
||||||
|
|
||||||
export default class BaseService {
|
|
||||||
public baseUrl: string = Environment.DEFAULT;
|
|
||||||
|
|
||||||
public httpClient = new HTTPLibrary();
|
|
||||||
|
|
||||||
private apiKey: string = '';
|
|
||||||
|
|
||||||
private apiKeyHeader: string = 'X-Plex-Token';
|
|
||||||
|
|
||||||
setApiKey(key: string, header: string = 'X-Plex-Token'): void {
|
|
||||||
this.apiKey = key;
|
|
||||||
this.apiKeyHeader = header;
|
|
||||||
}
|
|
||||||
|
|
||||||
getAuthorizationHeader(): Headers {
|
|
||||||
const apiKeyAuth = { [this.apiKeyHeader]: this.apiKey };
|
|
||||||
|
|
||||||
return { ...apiKeyAuth };
|
|
||||||
}
|
|
||||||
|
|
||||||
setBaseUrl(url: string): void {
|
|
||||||
this.baseUrl = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(apiKey: string = '', apiKeyHeader: string = 'X-Plex-Token') {
|
|
||||||
this.setApiKey(apiKey, apiKeyHeader);
|
|
||||||
}
|
|
||||||
|
|
||||||
static patternMatching(value: string, pattern: string, variableName: string): string {
|
|
||||||
if (!value) {
|
|
||||||
throw new Error(`${variableName} cannot be null or undefined`);
|
|
||||||
}
|
|
||||||
if (!value.match(new RegExp(pattern))) {
|
|
||||||
throw new Error(`Invalid value for ${variableName}: must match ${pattern}`);
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static urlEncode = (input: { [key: string]: any }): string =>
|
|
||||||
Object.keys(input)
|
|
||||||
.map((key) => `${key}=${encodeURIComponent(input[key])}`)
|
|
||||||
.join('&');
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
export interface Request {
|
|
||||||
method: string;
|
|
||||||
url: string;
|
|
||||||
input?: object;
|
|
||||||
headers: object;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Response {
|
|
||||||
data: object;
|
|
||||||
headers: object;
|
|
||||||
status: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Exception extends Error {
|
|
||||||
title: string;
|
|
||||||
type?: string;
|
|
||||||
detail?: string;
|
|
||||||
instance?: string;
|
|
||||||
statusCode: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Hook {
|
|
||||||
beforeRequest(request: Request): Promise<void>;
|
|
||||||
|
|
||||||
afterResponse(request: Request, response: Response): Promise<void>;
|
|
||||||
|
|
||||||
onError(error: Exception): Promise<void>;
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
export enum Environment {
|
|
||||||
DEFAULT = 'http://10.10.10.47:32400',
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
export interface Headers extends Record<string, string> {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines the basic operations for an HTTP client.
|
|
||||||
*/
|
|
||||||
export default interface HTTPClient {
|
|
||||||
get(url: string, input: any, headers: Headers, retry?: boolean): Promise<any>;
|
|
||||||
post(url: string, input: any, headers: Headers, retry?: boolean): Promise<any>;
|
|
||||||
delete(url: string, input: any, headers: Headers, retry?: boolean): Promise<any>;
|
|
||||||
put(url: string, input: any, headers: Headers, retry?: boolean): Promise<any>;
|
|
||||||
patch(url: string, input: any, headers: Headers, retry?: boolean): Promise<any>;
|
|
||||||
}
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
import axios, { AxiosError } from 'axios';
|
|
||||||
|
|
||||||
import HTTPClient, { Headers } from './HTTPClient';
|
|
||||||
import throwHttpError from './httpExceptions';
|
|
||||||
|
|
||||||
export default class HTTPLibrary implements HTTPClient {
|
|
||||||
readonly userAgentHeader: Headers = {
|
|
||||||
'User-Agent': 'liblab/0.1.25 PlexSDK/0.0.1 typescript/5.2.2',
|
|
||||||
};
|
|
||||||
|
|
||||||
readonly retryAttempts: number = 3;
|
|
||||||
|
|
||||||
readonly retryDelayMs: number = 150;
|
|
||||||
|
|
||||||
private static readonly responseMapper: Map<string, string> = new Map<string, string>([
|
|
||||||
['type', 'type_'],
|
|
||||||
['default', 'default_'],
|
|
||||||
]);
|
|
||||||
|
|
||||||
private readonly requestMapper: Map<string, string> = new Map<string, string>([
|
|
||||||
['type_', 'type'],
|
|
||||||
['default_', 'default'],
|
|
||||||
]);
|
|
||||||
|
|
||||||
async get(url: string, input: any, headers: Headers, retry: boolean = false): Promise<any> {
|
|
||||||
const request = () =>
|
|
||||||
axios.get(url, {
|
|
||||||
headers: { ...headers, ...this.getUserAgentHeader() },
|
|
||||||
data:
|
|
||||||
Object.keys(input).length > 0
|
|
||||||
? HTTPLibrary.convertKeysWithMapper(input, this.requestMapper)
|
|
||||||
: undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = retry
|
|
||||||
? await this.retry(this.retryAttempts, request, this.retryDelayMs)
|
|
||||||
: await request();
|
|
||||||
return HTTPLibrary.handleResponse(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
async post(url: string, input: any, headers: Headers, retry: boolean = false): Promise<any> {
|
|
||||||
const request = () =>
|
|
||||||
axios.post(url, HTTPLibrary.convertKeysWithMapper(input, this.requestMapper), {
|
|
||||||
headers: { ...headers, ...this.getUserAgentHeader() },
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = retry
|
|
||||||
? await this.retry(this.retryAttempts, request, this.retryDelayMs)
|
|
||||||
: await request();
|
|
||||||
|
|
||||||
return HTTPLibrary.handleResponse(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
async delete(url: string, input: any, headers: Headers, retry: boolean = false): Promise<any> {
|
|
||||||
const request = () =>
|
|
||||||
axios.delete(url, {
|
|
||||||
headers: { ...headers, ...this.getUserAgentHeader() },
|
|
||||||
data: HTTPLibrary.convertKeysWithMapper(input, this.requestMapper),
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = retry
|
|
||||||
? await this.retry(this.retryAttempts, request, this.retryDelayMs)
|
|
||||||
: await request();
|
|
||||||
|
|
||||||
return HTTPLibrary.handleResponse(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
async put(url: string, input: any, headers: Headers, retry: boolean = false): Promise<any> {
|
|
||||||
const request = () =>
|
|
||||||
axios.put(url, HTTPLibrary.convertKeysWithMapper(input, this.requestMapper), {
|
|
||||||
headers: { ...headers, ...this.getUserAgentHeader() },
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = retry
|
|
||||||
? await this.retry(this.retryAttempts, request, this.retryDelayMs)
|
|
||||||
: await request();
|
|
||||||
|
|
||||||
return HTTPLibrary.handleResponse(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
async patch(url: string, input: any, headers: Headers, retry: boolean = false): Promise<any> {
|
|
||||||
const request = () =>
|
|
||||||
axios.patch(url, HTTPLibrary.convertKeysWithMapper(input, this.requestMapper), {
|
|
||||||
headers: { ...headers, ...this.getUserAgentHeader() },
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = retry
|
|
||||||
? await this.retry(this.retryAttempts, request, this.retryDelayMs)
|
|
||||||
: await request();
|
|
||||||
|
|
||||||
return HTTPLibrary.handleResponse(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
async retry(retries: number, callbackFn: () => any, delay: number): Promise<any> {
|
|
||||||
let result: any;
|
|
||||||
|
|
||||||
try {
|
|
||||||
result = await callbackFn();
|
|
||||||
} catch (e: any) {
|
|
||||||
if ((e as AxiosError).isAxiosError) {
|
|
||||||
if (e.response) {
|
|
||||||
if (![500, 503, 504].includes(e.response.status)) {
|
|
||||||
return e.response;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (retries > 1) {
|
|
||||||
// eslint-disable-next-line no-promise-executor-return
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
||||||
result = await this.retry(retries - 1, callbackFn, delay * 2);
|
|
||||||
} else {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static handleResponse(response: any) {
|
|
||||||
if (response.status >= 400) {
|
|
||||||
throwHttpError(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
response.data = HTTPLibrary.convertKeysWithMapper(response.data, this.responseMapper);
|
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
private getUserAgentHeader(): Headers {
|
|
||||||
if (typeof window !== 'undefined') {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return this.userAgentHeader;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*Converts keys in an object using a provided JSON mapper.
|
|
||||||
* @param {any} obj - The object to convert keys for.
|
|
||||||
* @param {Object} jsonMapper - The JSON mapper containing key mappings.
|
|
||||||
* @returns {any} - The object with converted keys.
|
|
||||||
*/
|
|
||||||
private static convertKeysWithMapper<T>(obj: T, jsonMapper: Map<string, string>): any {
|
|
||||||
if (!obj || typeof obj !== 'object') {
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Array.isArray(obj)) {
|
|
||||||
return obj.map((item) => HTTPLibrary.convertKeysWithMapper(item, jsonMapper));
|
|
||||||
}
|
|
||||||
|
|
||||||
const convertedObj: Record<string, any> = {};
|
|
||||||
Object.entries(obj).forEach(([key, value]) => {
|
|
||||||
if (value !== undefined) {
|
|
||||||
const convertedKey = jsonMapper.get(key) || key;
|
|
||||||
convertedObj[convertedKey] = HTTPLibrary.convertKeysWithMapper(value, jsonMapper);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return convertedObj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
export type Explode = boolean;
|
|
||||||
export type QueryStyles = 'form' | 'spaceDelimited' | 'pipeDelimited' | 'deepObject';
|
|
||||||
export type PathStyles = 'simple' | 'label' | 'matrix';
|
|
||||||
|
|
||||||
const styleMethods: Record<string, Function> = {
|
|
||||||
simple: (value: unknown, explode: boolean) => {
|
|
||||||
// Check if the value is an array
|
|
||||||
if (Array.isArray(value)) {
|
|
||||||
return explode ? value.join(',') : value.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the value is an object
|
|
||||||
if (typeof value === 'object' && value !== null) {
|
|
||||||
if (explode) {
|
|
||||||
// Serialize object with exploded format: "key=value,key2=value2"
|
|
||||||
return Object.entries(value)
|
|
||||||
.map(([parameterName, parameterValue]) => `${parameterName}=${parameterValue}`)
|
|
||||||
.join(',');
|
|
||||||
}
|
|
||||||
// Serialize object with non-exploded format: "key,value,key2,value2"
|
|
||||||
return Object.entries(value)
|
|
||||||
.flatMap(([parameterName, parameterValue]) => [parameterName, parameterValue])
|
|
||||||
.join(',');
|
|
||||||
}
|
|
||||||
|
|
||||||
// For primitive values
|
|
||||||
return String(value);
|
|
||||||
},
|
|
||||||
|
|
||||||
form: (parameterName: string, parameterValue: unknown, explode: boolean) => {
|
|
||||||
// Check if the parameterValue is an array
|
|
||||||
if (Array.isArray(parameterValue)) {
|
|
||||||
return explode
|
|
||||||
? parameterValue.map((value) => `${parameterName}=${value}`).join('&')
|
|
||||||
: `${parameterName}=${parameterValue.join(',')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the parameterValue is an object
|
|
||||||
if (typeof parameterValue === 'object' && parameterValue !== null) {
|
|
||||||
if (explode) {
|
|
||||||
// Serialize object with exploded format: "key1=value1&key2=value2"
|
|
||||||
return Object.entries(parameterValue)
|
|
||||||
.map(([name, value]) => `${name}=${value}`)
|
|
||||||
.join('&');
|
|
||||||
}
|
|
||||||
// Serialize object with non-exploded format: "key=key1,value1,key2,value2"
|
|
||||||
return `${parameterName}=${Object.entries(parameterValue)
|
|
||||||
.flatMap(([name, value]) => [name, value])
|
|
||||||
.join(',')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For primitive values
|
|
||||||
return `${parameterName}=${parameterValue}`;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export function serializeQuery(
|
|
||||||
style: QueryStyles,
|
|
||||||
explode: Explode,
|
|
||||||
key: string,
|
|
||||||
value: unknown,
|
|
||||||
): string {
|
|
||||||
const method = styleMethods[style];
|
|
||||||
if (!method) return '';
|
|
||||||
return method(key, value, explode);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function serializePath(
|
|
||||||
style: PathStyles,
|
|
||||||
explode: Explode,
|
|
||||||
value: unknown,
|
|
||||||
key?: string,
|
|
||||||
): string {
|
|
||||||
const method = styleMethods[style];
|
|
||||||
if (!method) return '';
|
|
||||||
// The `simple` and `label` styles do not require a `key`
|
|
||||||
if (!key) {
|
|
||||||
return method(value, explode);
|
|
||||||
} else {
|
|
||||||
return method(key, value, explode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
export default interface Response<T> {
|
|
||||||
data: T;
|
|
||||||
headers: Record<string, string>;
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class BadGateway extends BaseHTTPError {
|
|
||||||
statusCode = 502;
|
|
||||||
|
|
||||||
title = 'Bad Gateway';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class BadRequest extends BaseHTTPError {
|
|
||||||
statusCode = 400;
|
|
||||||
|
|
||||||
title = 'Bad Request';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class Conflict extends BaseHTTPError {
|
|
||||||
statusCode = 409;
|
|
||||||
|
|
||||||
title = 'Conflict';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class ExpectationFailed extends BaseHTTPError {
|
|
||||||
statusCode = 417;
|
|
||||||
|
|
||||||
title = 'Expectation Failed';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class FailedDependency extends BaseHTTPError {
|
|
||||||
statusCode = 424;
|
|
||||||
|
|
||||||
title = 'Failed Dependency';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class Forbidden extends BaseHTTPError {
|
|
||||||
statusCode = 403;
|
|
||||||
|
|
||||||
title = 'Forbidden';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class GatewayTimeout extends BaseHTTPError {
|
|
||||||
statusCode = 504;
|
|
||||||
|
|
||||||
title = 'Gateway Timeout';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class Gone extends BaseHTTPError {
|
|
||||||
statusCode = 410;
|
|
||||||
|
|
||||||
title = 'Gone';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class HttpVersionNotSupported extends BaseHTTPError {
|
|
||||||
statusCode = 505;
|
|
||||||
|
|
||||||
title = 'HTTP Version Not Supported';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class InternalServerError extends BaseHTTPError {
|
|
||||||
statusCode = 500;
|
|
||||||
|
|
||||||
title = 'Internal Server Error';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class LengthRequired extends BaseHTTPError {
|
|
||||||
statusCode = 411;
|
|
||||||
|
|
||||||
title = 'LengthRequired';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class Locked extends BaseHTTPError {
|
|
||||||
statusCode = 423;
|
|
||||||
|
|
||||||
title = 'Locked';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class LoopDetected extends BaseHTTPError {
|
|
||||||
statusCode = 508;
|
|
||||||
|
|
||||||
title = 'Loop Detected';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class MethodNotAllowed extends BaseHTTPError {
|
|
||||||
statusCode = 405;
|
|
||||||
|
|
||||||
title = 'Method Not Allowed';
|
|
||||||
|
|
||||||
allow?: string[];
|
|
||||||
|
|
||||||
constructor(detail: string = '', allow?: string[]) {
|
|
||||||
super(detail);
|
|
||||||
this.allow = allow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class MisdirectedRequest extends BaseHTTPError {
|
|
||||||
statusCode = 421;
|
|
||||||
|
|
||||||
title = 'Misdirected Request';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class NetworkAuthenticationRequired extends BaseHTTPError {
|
|
||||||
statusCode = 511;
|
|
||||||
|
|
||||||
title = 'Network Authentication Required';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class NotAcceptable extends BaseHTTPError {
|
|
||||||
statusCode = 406;
|
|
||||||
|
|
||||||
title = 'Not Acceptable';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class NotExtended extends BaseHTTPError {
|
|
||||||
statusCode = 510;
|
|
||||||
|
|
||||||
title = 'Not Extended';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class NotFound extends BaseHTTPError {
|
|
||||||
statusCode = 404;
|
|
||||||
|
|
||||||
title = 'Not Found';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class NotImplemented extends BaseHTTPError {
|
|
||||||
statusCode = 501;
|
|
||||||
|
|
||||||
title = 'Not Implemented';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class PayloadTooLarge extends BaseHTTPError {
|
|
||||||
statusCode = 413;
|
|
||||||
|
|
||||||
title = 'Payload Too Large';
|
|
||||||
|
|
||||||
retryAfter: number | null;
|
|
||||||
|
|
||||||
constructor(detail: string = '', retryAfter: number | null = null) {
|
|
||||||
super(detail);
|
|
||||||
this.retryAfter = retryAfter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class PaymentRequired extends BaseHTTPError {
|
|
||||||
statusCode = 402;
|
|
||||||
|
|
||||||
title = 'Payment Required';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class PreconditionFailed extends BaseHTTPError {
|
|
||||||
statusCode = 412;
|
|
||||||
|
|
||||||
title = 'PreconditionFailed';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class PreconditionRequired extends BaseHTTPError {
|
|
||||||
statusCode = 428;
|
|
||||||
|
|
||||||
title = 'Precondition Required';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { AuthenticateChallenge, BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class ProxyAuthenticationRequired extends BaseHTTPError {
|
|
||||||
statusCode = 407;
|
|
||||||
|
|
||||||
title = 'Proxy Authentication Required';
|
|
||||||
|
|
||||||
proxyAuthenticate?: AuthenticateChallenge;
|
|
||||||
|
|
||||||
constructor(detail: string = '', proxyAuthenticate?: AuthenticateChallenge) {
|
|
||||||
super(detail);
|
|
||||||
this.proxyAuthenticate = proxyAuthenticate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class RangeNotSatisfiable extends BaseHTTPError {
|
|
||||||
statusCode = 416;
|
|
||||||
|
|
||||||
title = 'Range Not Satisfiable';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class RequestHeaderFieldsTooLarge extends BaseHTTPError {
|
|
||||||
statusCode = 431;
|
|
||||||
|
|
||||||
title = 'Request Header Fields Too Large';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class RequestTimeout extends BaseHTTPError {
|
|
||||||
statusCode = 408;
|
|
||||||
|
|
||||||
title = 'Request Timeout';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class ServiceUnavailable extends BaseHTTPError {
|
|
||||||
statusCode = 503;
|
|
||||||
|
|
||||||
title = 'Service Unavailable';
|
|
||||||
|
|
||||||
retryAfter: number | null;
|
|
||||||
|
|
||||||
constructor(detail: string = '', retryAfter: number | null = null) {
|
|
||||||
super(detail);
|
|
||||||
this.retryAfter = retryAfter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class TooEarly extends BaseHTTPError {
|
|
||||||
statusCode = 425;
|
|
||||||
|
|
||||||
title = 'Too Early';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class TooManyRequests extends BaseHTTPError {
|
|
||||||
statusCode = 429;
|
|
||||||
|
|
||||||
title = 'Too Many Requests';
|
|
||||||
|
|
||||||
retryAfter: number | null;
|
|
||||||
|
|
||||||
constructor(detail: string = '', retryAfter: number | null = null) {
|
|
||||||
super(detail);
|
|
||||||
this.retryAfter = retryAfter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { AuthenticateChallenge, BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class Unauthorized extends BaseHTTPError {
|
|
||||||
statusCode = 401;
|
|
||||||
|
|
||||||
title = 'Unauthorized';
|
|
||||||
|
|
||||||
wwwAuthenticate?: AuthenticateChallenge;
|
|
||||||
|
|
||||||
constructor(detail: string = '', wwwAuthenticate?: AuthenticateChallenge) {
|
|
||||||
super(detail);
|
|
||||||
this.wwwAuthenticate = wwwAuthenticate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class UnavailableForLegalReasons extends BaseHTTPError {
|
|
||||||
statusCode = 451;
|
|
||||||
|
|
||||||
title = 'Unavailable For Legal Reasons';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class UnprocessableEntity extends BaseHTTPError {
|
|
||||||
statusCode = 422;
|
|
||||||
|
|
||||||
title = 'Unprocessable Entity';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class UnsufficientStorage extends BaseHTTPError {
|
|
||||||
statusCode = 507;
|
|
||||||
|
|
||||||
title = 'Unsufficient Storage';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class UnsupportedMediaType extends BaseHTTPError {
|
|
||||||
statusCode = 415;
|
|
||||||
|
|
||||||
title = 'Unsupported Media Type';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class UpgradeRequired extends BaseHTTPError {
|
|
||||||
statusCode = 426;
|
|
||||||
|
|
||||||
title = 'Upgrade Required';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class UriTooLong extends BaseHTTPError {
|
|
||||||
statusCode = 414;
|
|
||||||
|
|
||||||
title = 'URI Too Long';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export default class VariantAlsoNegotiates extends BaseHTTPError {
|
|
||||||
statusCode = 506;
|
|
||||||
|
|
||||||
title = 'Variant Also Negotiates';
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
export interface IHTTPError extends Error {
|
|
||||||
statusCode: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IHTTPErrorDescription extends IHTTPError {
|
|
||||||
type?: string;
|
|
||||||
title: string;
|
|
||||||
detail?: string;
|
|
||||||
instance?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isHTTPError(error: unknown): error is IHTTPError {
|
|
||||||
if (!error) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return Number.isInteger((error as IHTTPError).statusCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isHTTPIssue(error: unknown): error is IHTTPErrorDescription {
|
|
||||||
if (!error) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return (error as IHTTPErrorDescription).title !== undefined && isHTTPError(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
export class BaseHTTPError extends Error implements IHTTPError {
|
|
||||||
public type?: string;
|
|
||||||
|
|
||||||
public title: string = 'Internal Server Error';
|
|
||||||
|
|
||||||
public detail?: string;
|
|
||||||
|
|
||||||
public instance?: string;
|
|
||||||
|
|
||||||
public statusCode: number = 500;
|
|
||||||
|
|
||||||
constructor(detail: string = '') {
|
|
||||||
super(detail || 'An Unknown HTTP Error Occurred');
|
|
||||||
this.detail = detail;
|
|
||||||
this.stack = (<any>new Error()).stack;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isClientError(error: Error): boolean {
|
|
||||||
return isHTTPError(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isServerError(e: Error): boolean {
|
|
||||||
return isHTTPError(e) && e.statusCode >= 500 && e.statusCode <= 599;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AuthenticateChallenge = string | string[];
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
import BadRequest from './BadRequest';
|
|
||||||
import Unauthorized from './Unauthorized';
|
|
||||||
import PaymentRequired from './PaymentRequired';
|
|
||||||
import Forbidden from './Forbidden';
|
|
||||||
import NotFound from './NotFound';
|
|
||||||
import MethodNotAllowed from './MethodNotAllowed';
|
|
||||||
import NotAcceptable from './NotAcceptable';
|
|
||||||
import ProxyAuthenticationRequired from './ProxyAuthenticationRequired';
|
|
||||||
import RequestTimeout from './RequestTimeout';
|
|
||||||
import Conflict from './Conflict';
|
|
||||||
import Gone from './Gone';
|
|
||||||
import LengthRequired from './LengthRequired';
|
|
||||||
import PreconditionFailed from './PreconditionFailed';
|
|
||||||
import PayloadTooLarge from './PayloadTooLarge';
|
|
||||||
import UriTooLong from './UriTooLong';
|
|
||||||
import UnsupportedMediaType from './UnsupportedMediaType';
|
|
||||||
import RangeNotSatisfiable from './RangeNotSatisfiable';
|
|
||||||
import ExpectationFailed from './ExpectationFailed';
|
|
||||||
import MisdirectedRequest from './MisdirectedRequest';
|
|
||||||
import UnprocessableEntity from './UnprocessableEntity';
|
|
||||||
import Locked from './Locked';
|
|
||||||
import FailedDependency from './FailedDependency';
|
|
||||||
import TooEarly from './TooEarly';
|
|
||||||
import UpgradeRequired from './UpgradeRequired';
|
|
||||||
import PreconditionRequired from './PreconditionRequired';
|
|
||||||
import TooManyRequests from './TooManyRequests';
|
|
||||||
import RequestHeaderFieldsTooLarge from './RequestHeaderFieldsTooLarge';
|
|
||||||
import UnavailableForLegalReasons from './UnavailableForLegalReasons';
|
|
||||||
import InternalServerError from './InternalServerError';
|
|
||||||
import NotImplemented from './NotImplemented';
|
|
||||||
import BadGateway from './BadGateway';
|
|
||||||
import ServiceUnavailable from './ServiceUnavailable';
|
|
||||||
import GatewayTimeout from './GatewayTimeout';
|
|
||||||
import HttpVersionNotSupported from './HttpVersionNotSupported';
|
|
||||||
import VariantAlsoNegotiates from './VariantAlsoNegotiates';
|
|
||||||
import UnsufficientStorage from './UnsufficientStorage';
|
|
||||||
import LoopDetected from './LoopDetected';
|
|
||||||
import NotExtended from './NotExtended';
|
|
||||||
import NetworkAuthenticationRequired from './NetworkAuthenticationRequired';
|
|
||||||
import { BaseHTTPError } from './base';
|
|
||||||
|
|
||||||
export {
|
|
||||||
BaseHTTPError,
|
|
||||||
BadRequest,
|
|
||||||
Unauthorized,
|
|
||||||
PaymentRequired,
|
|
||||||
Forbidden,
|
|
||||||
NotFound,
|
|
||||||
MethodNotAllowed,
|
|
||||||
NotAcceptable,
|
|
||||||
ProxyAuthenticationRequired,
|
|
||||||
RequestTimeout,
|
|
||||||
Conflict,
|
|
||||||
Gone,
|
|
||||||
LengthRequired,
|
|
||||||
PreconditionFailed,
|
|
||||||
PayloadTooLarge,
|
|
||||||
UriTooLong,
|
|
||||||
UnsupportedMediaType,
|
|
||||||
RangeNotSatisfiable,
|
|
||||||
ExpectationFailed,
|
|
||||||
MisdirectedRequest,
|
|
||||||
UnprocessableEntity,
|
|
||||||
Locked,
|
|
||||||
FailedDependency,
|
|
||||||
TooEarly,
|
|
||||||
UpgradeRequired,
|
|
||||||
PreconditionRequired,
|
|
||||||
TooManyRequests,
|
|
||||||
RequestHeaderFieldsTooLarge,
|
|
||||||
UnavailableForLegalReasons,
|
|
||||||
InternalServerError,
|
|
||||||
NotImplemented,
|
|
||||||
BadGateway,
|
|
||||||
ServiceUnavailable,
|
|
||||||
GatewayTimeout,
|
|
||||||
HttpVersionNotSupported,
|
|
||||||
VariantAlsoNegotiates,
|
|
||||||
UnsufficientStorage,
|
|
||||||
LoopDetected,
|
|
||||||
NotExtended,
|
|
||||||
NetworkAuthenticationRequired,
|
|
||||||
};
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
import {
|
|
||||||
BaseHTTPError,
|
|
||||||
BadRequest,
|
|
||||||
Unauthorized,
|
|
||||||
PaymentRequired,
|
|
||||||
Forbidden,
|
|
||||||
NotFound,
|
|
||||||
MethodNotAllowed,
|
|
||||||
NotAcceptable,
|
|
||||||
ProxyAuthenticationRequired,
|
|
||||||
RequestTimeout,
|
|
||||||
Conflict,
|
|
||||||
Gone,
|
|
||||||
LengthRequired,
|
|
||||||
PreconditionFailed,
|
|
||||||
PayloadTooLarge,
|
|
||||||
UriTooLong,
|
|
||||||
UnsupportedMediaType,
|
|
||||||
RangeNotSatisfiable,
|
|
||||||
ExpectationFailed,
|
|
||||||
MisdirectedRequest,
|
|
||||||
UnprocessableEntity,
|
|
||||||
Locked,
|
|
||||||
FailedDependency,
|
|
||||||
TooEarly,
|
|
||||||
UpgradeRequired,
|
|
||||||
PreconditionRequired,
|
|
||||||
TooManyRequests,
|
|
||||||
RequestHeaderFieldsTooLarge,
|
|
||||||
UnavailableForLegalReasons,
|
|
||||||
InternalServerError,
|
|
||||||
NotImplemented,
|
|
||||||
BadGateway,
|
|
||||||
ServiceUnavailable,
|
|
||||||
GatewayTimeout,
|
|
||||||
HttpVersionNotSupported,
|
|
||||||
VariantAlsoNegotiates,
|
|
||||||
UnsufficientStorage,
|
|
||||||
LoopDetected,
|
|
||||||
NotExtended,
|
|
||||||
NetworkAuthenticationRequired,
|
|
||||||
} from './errors';
|
|
||||||
|
|
||||||
interface HttpResponseWithError {
|
|
||||||
status: number;
|
|
||||||
headers: any;
|
|
||||||
data?: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface NumberToClass {
|
|
||||||
[key: number]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
const statusCodeToErrorFunction: NumberToClass = {
|
|
||||||
400: BadRequest,
|
|
||||||
401: Unauthorized,
|
|
||||||
402: PaymentRequired,
|
|
||||||
403: Forbidden,
|
|
||||||
404: NotFound,
|
|
||||||
405: MethodNotAllowed,
|
|
||||||
406: NotAcceptable,
|
|
||||||
407: ProxyAuthenticationRequired,
|
|
||||||
408: RequestTimeout,
|
|
||||||
409: Conflict,
|
|
||||||
410: Gone,
|
|
||||||
411: LengthRequired,
|
|
||||||
412: PreconditionFailed,
|
|
||||||
413: PayloadTooLarge,
|
|
||||||
414: UriTooLong,
|
|
||||||
415: UnsupportedMediaType,
|
|
||||||
416: RangeNotSatisfiable,
|
|
||||||
417: ExpectationFailed,
|
|
||||||
421: MisdirectedRequest,
|
|
||||||
422: UnprocessableEntity,
|
|
||||||
423: Locked,
|
|
||||||
424: FailedDependency,
|
|
||||||
425: TooEarly,
|
|
||||||
426: UpgradeRequired,
|
|
||||||
428: PreconditionRequired,
|
|
||||||
429: TooManyRequests,
|
|
||||||
431: RequestHeaderFieldsTooLarge,
|
|
||||||
451: UnavailableForLegalReasons,
|
|
||||||
500: InternalServerError,
|
|
||||||
501: NotImplemented,
|
|
||||||
502: BadGateway,
|
|
||||||
503: ServiceUnavailable,
|
|
||||||
504: GatewayTimeout,
|
|
||||||
505: HttpVersionNotSupported,
|
|
||||||
506: VariantAlsoNegotiates,
|
|
||||||
507: UnsufficientStorage,
|
|
||||||
508: LoopDetected,
|
|
||||||
510: NotExtended,
|
|
||||||
511: NetworkAuthenticationRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary This function will throw an error.
|
|
||||||
*
|
|
||||||
* @param {HttpResponseWithError} response - the response from a request, must contain a status and data fields
|
|
||||||
* @throws {Error} - an http error
|
|
||||||
*/
|
|
||||||
export default function throwHttpError(response: HttpResponseWithError): never {
|
|
||||||
let error: BaseHTTPError = new BaseHTTPError(response.data);
|
|
||||||
switch (response.status) {
|
|
||||||
case 401:
|
|
||||||
error = new Unauthorized(response.data, response.headers['WWW-Authenticate']);
|
|
||||||
case 405:
|
|
||||||
// this indicates a bug in the spec if it allows a method that the server rejects
|
|
||||||
error = new MethodNotAllowed(response.data, response.headers.allowed);
|
|
||||||
case 407:
|
|
||||||
error = new ProxyAuthenticationRequired(
|
|
||||||
response.data,
|
|
||||||
response.headers['Proxy-Authenticate'],
|
|
||||||
);
|
|
||||||
case 413:
|
|
||||||
error = new PayloadTooLarge(response.data, response.headers['Retry-After']);
|
|
||||||
case 429:
|
|
||||||
error = new TooManyRequests(response.data, response.headers['Retry-After']);
|
|
||||||
case 503:
|
|
||||||
error = new ServiceUnavailable(response.data, response.headers['Retry-After']);
|
|
||||||
default:
|
|
||||||
if (response.status in statusCodeToErrorFunction) {
|
|
||||||
error = new statusCodeToErrorFunction[response.status](response.data);
|
|
||||||
} else {
|
|
||||||
const error = new BaseHTTPError(response.data);
|
|
||||||
error.statusCode = response.status;
|
|
||||||
error.title = 'unknown error';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
99
src/index.ts
99
src/index.ts
@@ -1,99 +0,0 @@
|
|||||||
import { ActivitiesService } from './services/activities/Activities';
|
|
||||||
import { ButlerService } from './services/butler/Butler';
|
|
||||||
import { HubsService } from './services/hubs/Hubs';
|
|
||||||
import { LibraryService } from './services/library/Library';
|
|
||||||
import { LogService } from './services/log/Log';
|
|
||||||
import { MediaService } from './services/media/Media';
|
|
||||||
import { PlaylistsService } from './services/playlists/Playlists';
|
|
||||||
import { SearchService } from './services/search/Search';
|
|
||||||
import { SecurityService } from './services/security/Security';
|
|
||||||
import { ServerService } from './services/server/Server';
|
|
||||||
import { SessionsService } from './services/sessions/Sessions';
|
|
||||||
import { UpdaterService } from './services/updater/Updater';
|
|
||||||
import { VideoService } from './services/video/Video';
|
|
||||||
|
|
||||||
export * from './models';
|
|
||||||
|
|
||||||
export * as ActivitiesModels from './services/activities';
|
|
||||||
export * as ButlerModels from './services/butler';
|
|
||||||
export * as HubsModels from './services/hubs';
|
|
||||||
export * as LibraryModels from './services/library';
|
|
||||||
export * as LogModels from './services/log';
|
|
||||||
export * as PlaylistsModels from './services/playlists';
|
|
||||||
export * as SearchModels from './services/search';
|
|
||||||
export * as SecurityModels from './services/security';
|
|
||||||
export * as ServerModels from './services/server';
|
|
||||||
export * as SessionsModels from './services/sessions';
|
|
||||||
export * as UpdaterModels from './services/updater';
|
|
||||||
export * as VideoModels from './services/video';
|
|
||||||
|
|
||||||
type Config = {
|
|
||||||
apiKey?: string;
|
|
||||||
apiKeyHeader?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export * from './http/errors';
|
|
||||||
|
|
||||||
export class PlexSDK {
|
|
||||||
public activities: ActivitiesService;
|
|
||||||
public butler: ButlerService;
|
|
||||||
public hubs: HubsService;
|
|
||||||
public library: LibraryService;
|
|
||||||
public log: LogService;
|
|
||||||
public media: MediaService;
|
|
||||||
public playlists: PlaylistsService;
|
|
||||||
public search: SearchService;
|
|
||||||
public security: SecurityService;
|
|
||||||
public server: ServerService;
|
|
||||||
public sessions: SessionsService;
|
|
||||||
public updater: UpdaterService;
|
|
||||||
public video: VideoService;
|
|
||||||
|
|
||||||
constructor({ apiKey = '', apiKeyHeader = 'X-Plex-Token' }: Config) {
|
|
||||||
this.activities = new ActivitiesService(apiKey, apiKeyHeader);
|
|
||||||
this.butler = new ButlerService(apiKey, apiKeyHeader);
|
|
||||||
this.hubs = new HubsService(apiKey, apiKeyHeader);
|
|
||||||
this.library = new LibraryService(apiKey, apiKeyHeader);
|
|
||||||
this.log = new LogService(apiKey, apiKeyHeader);
|
|
||||||
this.media = new MediaService(apiKey, apiKeyHeader);
|
|
||||||
this.playlists = new PlaylistsService(apiKey, apiKeyHeader);
|
|
||||||
this.search = new SearchService(apiKey, apiKeyHeader);
|
|
||||||
this.security = new SecurityService(apiKey, apiKeyHeader);
|
|
||||||
this.server = new ServerService(apiKey, apiKeyHeader);
|
|
||||||
this.sessions = new SessionsService(apiKey, apiKeyHeader);
|
|
||||||
this.updater = new UpdaterService(apiKey, apiKeyHeader);
|
|
||||||
this.video = new VideoService(apiKey, apiKeyHeader);
|
|
||||||
}
|
|
||||||
|
|
||||||
setBaseUrl(url: string): void {
|
|
||||||
this.activities.setBaseUrl(url);
|
|
||||||
this.butler.setBaseUrl(url);
|
|
||||||
this.hubs.setBaseUrl(url);
|
|
||||||
this.library.setBaseUrl(url);
|
|
||||||
this.log.setBaseUrl(url);
|
|
||||||
this.media.setBaseUrl(url);
|
|
||||||
this.playlists.setBaseUrl(url);
|
|
||||||
this.search.setBaseUrl(url);
|
|
||||||
this.security.setBaseUrl(url);
|
|
||||||
this.server.setBaseUrl(url);
|
|
||||||
this.sessions.setBaseUrl(url);
|
|
||||||
this.updater.setBaseUrl(url);
|
|
||||||
this.video.setBaseUrl(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
setApiKey(key: string, header: string = 'X-Plex-Token') {
|
|
||||||
this.activities.setApiKey(key, header);
|
|
||||||
this.butler.setApiKey(key, header);
|
|
||||||
this.hubs.setApiKey(key, header);
|
|
||||||
this.library.setApiKey(key, header);
|
|
||||||
this.log.setApiKey(key, header);
|
|
||||||
this.media.setApiKey(key, header);
|
|
||||||
this.playlists.setApiKey(key, header);
|
|
||||||
this.search.setApiKey(key, header);
|
|
||||||
this.security.setApiKey(key, header);
|
|
||||||
this.server.setApiKey(key, header);
|
|
||||||
this.sessions.setApiKey(key, header);
|
|
||||||
this.updater.setApiKey(key, header);
|
|
||||||
this.video.setApiKey(key, header);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
export type { Download } from './services/updater/models/Download';
|
|
||||||
export type { Force } from './services/playlists/models/Force';
|
|
||||||
export type { GetAvailableClientsResponse } from './services/server/models/GetAvailableClientsResponse';
|
|
||||||
export type { GetButlerTasksResponse } from './services/butler/models/GetButlerTasksResponse';
|
|
||||||
export type { GetDevicesResponse } from './services/server/models/GetDevicesResponse';
|
|
||||||
export type { GetMyPlexAccountResponse } from './services/server/models/GetMyPlexAccountResponse';
|
|
||||||
export type { GetOnDeckResponse } from './services/library/models/GetOnDeckResponse';
|
|
||||||
export type { GetRecentlyAddedResponse } from './services/library/models/GetRecentlyAddedResponse';
|
|
||||||
export type { GetSearchResultsResponse } from './services/search/models/GetSearchResultsResponse';
|
|
||||||
export type { GetServerActivitiesResponse } from './services/activities/models/GetServerActivitiesResponse';
|
|
||||||
export type { GetServerCapabilitiesResponse } from './services/server/models/GetServerCapabilitiesResponse';
|
|
||||||
export type { GetServerIdentityResponse } from './services/server/models/GetServerIdentityResponse';
|
|
||||||
export type { GetServerListResponse } from './services/server/models/GetServerListResponse';
|
|
||||||
export type { GetTranscodeSessionsResponse } from './services/sessions/models/GetTranscodeSessionsResponse';
|
|
||||||
export type { IncludeDetails } from './services/library/models/IncludeDetails';
|
|
||||||
export type { Level } from './services/log/models/Level';
|
|
||||||
export type { MinSize } from './services/server/models/MinSize';
|
|
||||||
export type { OnlyTransient } from './services/hubs/models/OnlyTransient';
|
|
||||||
export type { PlaylistType } from './services/playlists/models/PlaylistType';
|
|
||||||
export type { Scope } from './services/security/models/Scope';
|
|
||||||
export type { SecurityType } from './services/security/models/SecurityType';
|
|
||||||
export type { Skip } from './services/updater/models/Skip';
|
|
||||||
export type { Smart } from './services/playlists/models/Smart';
|
|
||||||
export type { State } from './services/video/models/State';
|
|
||||||
export type { TaskName } from './services/butler/models/TaskName';
|
|
||||||
export type { Tonight } from './services/updater/models/Tonight';
|
|
||||||
export type { Type } from './services/playlists/models/Type';
|
|
||||||
export type { Upscale } from './services/server/models/Upscale';
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,67 +0,0 @@
|
|||||||
import BaseService from '../../BaseService';
|
|
||||||
|
|
||||||
import Response from '../../http/Response';
|
|
||||||
|
|
||||||
import { GetServerActivitiesResponse } from './models/GetServerActivitiesResponse';
|
|
||||||
|
|
||||||
import { serializePath } from '../../http/QuerySerializer';
|
|
||||||
|
|
||||||
export class ActivitiesService extends BaseService {
|
|
||||||
/**
|
|
||||||
* @summary Get Server Activities
|
|
||||||
* @description Get Server Activities
|
|
||||||
|
|
||||||
* @returns {Promise<Response<GetServerActivitiesResponse>>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getServerActivities(): Promise<Response<GetServerActivitiesResponse>> {
|
|
||||||
const urlEndpoint = '/activities';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Cancel Server Activities
|
|
||||||
* @description Cancel Server Activities
|
|
||||||
|
|
||||||
* @param activityUUID The UUID of the activity to cancel.
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async cancelServerActivities(activityUuid: string): Promise<any> {
|
|
||||||
if (activityUuid === undefined) {
|
|
||||||
throw new Error(
|
|
||||||
'The following parameter is required: activityUuid, cannot be empty or blank',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let urlEndpoint = '/activities/{activityUUID}';
|
|
||||||
urlEndpoint = urlEndpoint.replace(
|
|
||||||
'{activityUUID}',
|
|
||||||
encodeURIComponent(serializePath('simple', false, activityUuid, undefined)),
|
|
||||||
);
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.delete(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export type { GetServerActivitiesResponse } from './models/GetServerActivitiesResponse';
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
export interface GetServerActivitiesResponse {
|
|
||||||
MediaContainer?: MediaContainer;
|
|
||||||
}
|
|
||||||
interface MediaContainer {
|
|
||||||
size?: number;
|
|
||||||
Activity?: {
|
|
||||||
uuid?: string;
|
|
||||||
cancellable?: boolean;
|
|
||||||
userID?: number;
|
|
||||||
title?: string;
|
|
||||||
subtitle?: string;
|
|
||||||
progress?: number;
|
|
||||||
Context?: Context;
|
|
||||||
type_?: string;
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
interface Context {
|
|
||||||
librarySectionID?: string;
|
|
||||||
}
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
import BaseService from '../../BaseService';
|
|
||||||
|
|
||||||
import Response from '../../http/Response';
|
|
||||||
|
|
||||||
import { GetButlerTasksResponse } from './models/GetButlerTasksResponse';
|
|
||||||
import { TaskName } from './models/TaskName';
|
|
||||||
|
|
||||||
import { serializePath } from '../../http/QuerySerializer';
|
|
||||||
|
|
||||||
export class ButlerService extends BaseService {
|
|
||||||
/**
|
|
||||||
* @summary Get Butler tasks
|
|
||||||
* @description Returns a list of butler tasks
|
|
||||||
|
|
||||||
* @returns {Promise<Response<GetButlerTasksResponse>>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getButlerTasks(): Promise<Response<GetButlerTasksResponse>> {
|
|
||||||
const urlEndpoint = '/butler';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Start all Butler tasks
|
|
||||||
* @description This endpoint will attempt to start all Butler tasks that are enabled in the settings. Butler tasks normally run automatically during a time window configured on the server's Settings page but can be manually started using this endpoint. Tasks will run with the following criteria:
|
|
||||||
1. Any tasks not scheduled to run on the current day will be skipped.
|
|
||||||
2. If a task is configured to run at a random time during the configured window and we are outside that window, the task will start immediately.
|
|
||||||
3. If a task is configured to run at a random time during the configured window and we are within that window, the task will be scheduled at a random time within the window.
|
|
||||||
4. If we are outside the configured window, the task will start immediately.
|
|
||||||
|
|
||||||
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async startAllTasks(): Promise<any> {
|
|
||||||
const urlEndpoint = '/butler';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.post(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Stop all Butler tasks
|
|
||||||
* @description This endpoint will stop all currently running tasks and remove any scheduled tasks from the queue.
|
|
||||||
|
|
||||||
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async stopAllTasks(): Promise<any> {
|
|
||||||
const urlEndpoint = '/butler';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.delete(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Start a single Butler task
|
|
||||||
* @description This endpoint will attempt to start a single Butler task that is enabled in the settings. Butler tasks normally run automatically during a time window configured on the server's Settings page but can be manually started using this endpoint. Tasks will run with the following criteria:
|
|
||||||
1. Any tasks not scheduled to run on the current day will be skipped.
|
|
||||||
2. If a task is configured to run at a random time during the configured window and we are outside that window, the task will start immediately.
|
|
||||||
3. If a task is configured to run at a random time during the configured window and we are within that window, the task will be scheduled at a random time within the window.
|
|
||||||
4. If we are outside the configured window, the task will start immediately.
|
|
||||||
|
|
||||||
|
|
||||||
* @param taskName the name of the task to be started.
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async startTask(taskName: TaskName): Promise<any> {
|
|
||||||
if (taskName === undefined) {
|
|
||||||
throw new Error('The following parameter is required: taskName, cannot be empty or blank');
|
|
||||||
}
|
|
||||||
let urlEndpoint = '/butler/{taskName}';
|
|
||||||
urlEndpoint = urlEndpoint.replace(
|
|
||||||
'{taskName}',
|
|
||||||
encodeURIComponent(serializePath('simple', false, taskName, undefined)),
|
|
||||||
);
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.post(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Stop a single Butler task
|
|
||||||
* @description This endpoint will stop a currently running task by name, or remove it from the list of scheduled tasks if it exists. See the section above for a list of task names for this endpoint.
|
|
||||||
|
|
||||||
|
|
||||||
* @param taskName The name of the task to be started.
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async stopTask(taskName: TaskName): Promise<any> {
|
|
||||||
if (taskName === undefined) {
|
|
||||||
throw new Error('The following parameter is required: taskName, cannot be empty or blank');
|
|
||||||
}
|
|
||||||
let urlEndpoint = '/butler/{taskName}';
|
|
||||||
urlEndpoint = urlEndpoint.replace(
|
|
||||||
'{taskName}',
|
|
||||||
encodeURIComponent(serializePath('simple', false, taskName, undefined)),
|
|
||||||
);
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.delete(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export type { GetButlerTasksResponse } from './models/GetButlerTasksResponse';
|
|
||||||
export type { TaskName } from './models/TaskName';
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
export interface GetButlerTasksResponse {
|
|
||||||
ButlerTasks?: ButlerTasks;
|
|
||||||
}
|
|
||||||
interface ButlerTasks {
|
|
||||||
ButlerTask?: {
|
|
||||||
name?: string;
|
|
||||||
interval?: number;
|
|
||||||
scheduleRandomized?: boolean;
|
|
||||||
enabled?: boolean;
|
|
||||||
title?: string;
|
|
||||||
description?: string;
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
export type TaskName =
|
|
||||||
| 'BackupDatabase'
|
|
||||||
| 'BuildGracenoteCollections'
|
|
||||||
| 'CheckForUpdates'
|
|
||||||
| 'CleanOldBundles'
|
|
||||||
| 'CleanOldCacheFiles'
|
|
||||||
| 'DeepMediaAnalysis'
|
|
||||||
| 'GenerateAutoTags'
|
|
||||||
| 'GenerateChapterThumbs'
|
|
||||||
| 'GenerateMediaIndexFiles'
|
|
||||||
| 'OptimizeDatabase'
|
|
||||||
| 'RefreshLibraries'
|
|
||||||
| 'RefreshLocalMedia'
|
|
||||||
| 'RefreshPeriodicMetadata'
|
|
||||||
| 'UpgradeMediaAnalysis';
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
import BaseService from '../../BaseService';
|
|
||||||
|
|
||||||
import Response from '../../http/Response';
|
|
||||||
|
|
||||||
import { OnlyTransient } from './models/OnlyTransient';
|
|
||||||
|
|
||||||
import { serializeQuery, serializePath } from '../../http/QuerySerializer';
|
|
||||||
|
|
||||||
export class HubsService extends BaseService {
|
|
||||||
/**
|
|
||||||
* @summary Get Global Hubs
|
|
||||||
* @description Get Global Hubs filtered by the parameters provided.
|
|
||||||
|
|
||||||
* @param optionalParams - Optional parameters
|
|
||||||
* @param optionalParams.count - The number of items to return with each hub.
|
|
||||||
* @param optionalParams.onlyTransient - Only return hubs which are "transient", meaning those which are prone to changing after media playback or addition (e.g. On Deck, or Recently Added).
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getGlobalHubs(
|
|
||||||
optionalParams: { count?: number; onlyTransient?: OnlyTransient } = {},
|
|
||||||
): Promise<any> {
|
|
||||||
const { count, onlyTransient } = optionalParams;
|
|
||||||
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
if (count) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'count', count));
|
|
||||||
}
|
|
||||||
if (onlyTransient) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'onlyTransient', onlyTransient));
|
|
||||||
}
|
|
||||||
const urlEndpoint = '/hubs';
|
|
||||||
const urlParams = queryParams.length > 0 ? `?${encodeURI(queryParams.join('&'))}` : '';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}${urlParams}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get library specific hubs
|
|
||||||
* @description This endpoint will return a list of library specific hubs
|
|
||||||
|
|
||||||
|
|
||||||
* @param sectionId the Id of the library to query
|
|
||||||
* @param optionalParams - Optional parameters
|
|
||||||
* @param optionalParams.count - The number of items to return with each hub.
|
|
||||||
* @param optionalParams.onlyTransient - Only return hubs which are "transient", meaning those which are prone to changing after media playback or addition (e.g. On Deck, or Recently Added).
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getLibraryHubs(
|
|
||||||
sectionId: number,
|
|
||||||
optionalParams: { count?: number; onlyTransient?: OnlyTransient } = {},
|
|
||||||
): Promise<any> {
|
|
||||||
const { count, onlyTransient } = optionalParams;
|
|
||||||
if (sectionId === undefined) {
|
|
||||||
throw new Error('The following parameter is required: sectionId, cannot be empty or blank');
|
|
||||||
}
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
let urlEndpoint = '/hubs/sections/{sectionId}';
|
|
||||||
urlEndpoint = urlEndpoint.replace(
|
|
||||||
'{sectionId}',
|
|
||||||
encodeURIComponent(serializePath('simple', false, sectionId, undefined)),
|
|
||||||
);
|
|
||||||
if (count) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'count', count));
|
|
||||||
}
|
|
||||||
if (onlyTransient) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'onlyTransient', onlyTransient));
|
|
||||||
}
|
|
||||||
const urlParams = queryParams.length > 0 ? `?${encodeURI(queryParams.join('&'))}` : '';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}${urlParams}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export type { OnlyTransient } from './models/OnlyTransient';
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export type OnlyTransient = 0 | 1;
|
|
||||||
@@ -1,475 +0,0 @@
|
|||||||
import BaseService from '../../BaseService';
|
|
||||||
|
|
||||||
import Response from '../../http/Response';
|
|
||||||
|
|
||||||
import { GetRecentlyAddedResponse } from './models/GetRecentlyAddedResponse';
|
|
||||||
import { IncludeDetails } from './models/IncludeDetails';
|
|
||||||
import { GetOnDeckResponse } from './models/GetOnDeckResponse';
|
|
||||||
|
|
||||||
import { serializeQuery, serializePath } from '../../http/QuerySerializer';
|
|
||||||
|
|
||||||
export class LibraryService extends BaseService {
|
|
||||||
/**
|
|
||||||
* @summary Get Hash Value
|
|
||||||
* @description This resource returns hash values for local files
|
|
||||||
|
|
||||||
* @param url This is the path to the local file, must be prefixed by `file://`
|
|
||||||
* @param optionalParams - Optional parameters
|
|
||||||
* @param optionalParams.type_ - Item type
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getFileHash(url: string, optionalParams: { type?: number } = {}): Promise<any> {
|
|
||||||
const { type } = optionalParams;
|
|
||||||
if (url === undefined) {
|
|
||||||
throw new Error('The following parameter is required: url, cannot be empty or blank');
|
|
||||||
}
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
if (url) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'url', url));
|
|
||||||
}
|
|
||||||
if (type) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'type_', type));
|
|
||||||
}
|
|
||||||
const urlEndpoint = '/library/hashes';
|
|
||||||
const urlParams = queryParams.length > 0 ? `?${encodeURI(queryParams.join('&'))}` : '';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}${urlParams}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get Recently Added
|
|
||||||
* @description This endpoint will return the recently added content.
|
|
||||||
|
|
||||||
|
|
||||||
* @returns {Promise<Response<GetRecentlyAddedResponse>>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getRecentlyAdded(): Promise<Response<GetRecentlyAddedResponse>> {
|
|
||||||
const urlEndpoint = '/library/recentlyAdded';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get All Libraries
|
|
||||||
* @description A library section (commonly referred to as just a library) is a collection of media.
|
|
||||||
Libraries are typed, and depending on their type provide either a flat or a hierarchical view of the media.
|
|
||||||
For example, a music library has an artist > albums > tracks structure, whereas a movie library is flat.
|
|
||||||
|
|
||||||
Libraries have features beyond just being a collection of media; for starters, they include information about supported types, filters and sorts.
|
|
||||||
This allows a client to provide a rich interface around the media (e.g. allow sorting movies by release year).
|
|
||||||
|
|
||||||
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getLibraries(): Promise<any> {
|
|
||||||
const urlEndpoint = '/library/sections';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get Library Details
|
|
||||||
* @description Returns details for the library. This can be thought of as an interstitial endpoint because it contains information about the library, rather than content itself. These details are:
|
|
||||||
|
|
||||||
- A list of `Directory` objects: These used to be used by clients to build a menuing system. There are four flavors of directory found here:
|
|
||||||
- Primary: (e.g. all, On Deck) These are still used in some clients to provide "shortcuts" to subsets of media. However, with the exception of On Deck, all of them can be created by media queries, and the desire is to allow these to be customized by users.
|
|
||||||
- Secondary: These are marked with `secondary="1"` and were used by old clients to provide nested menus allowing for primative (but structured) navigation.
|
|
||||||
- Special: There is a By Folder entry which allows browsing the media by the underlying filesystem structure, and there's a completely obsolete entry marked `search="1"` which used to be used to allow clients to build search dialogs on the fly.
|
|
||||||
- A list of `Type` objects: These represent the types of things found in this library, and for each one, a list of `Filter` and `Sort` objects. These can be used to build rich controls around a grid of media to allow filtering and organizing. Note that these filters and sorts are optional, and without them, the client won't render any filtering controls. The `Type` object contains:
|
|
||||||
- `key`: This provides the root endpoint returning the actual media list for the type.
|
|
||||||
- `type`: This is the metadata type for the type (if a standard Plex type).
|
|
||||||
- `title`: The title for for the content of this type (e.g. "Movies").
|
|
||||||
- Each `Filter` object contains a description of the filter. Note that it is not an exhaustive list of the full media query language, but an inportant subset useful for top-level API.
|
|
||||||
- `filter`: This represents the filter name used for the filter, which can be used to construct complex media queries with.
|
|
||||||
- `filterType`: This is either `string`, `integer`, or `boolean`, and describes the type of values used for the filter.
|
|
||||||
- `key`: This provides the endpoint where the possible range of values for the filter can be retrieved (e.g. for a "Genre" filter, it returns a list of all the genres in the library). This will include a `type` argument that matches the metadata type of the Type element.
|
|
||||||
- `title`: The title for the filter.
|
|
||||||
- Each `Sort` object contains a description of the sort field.
|
|
||||||
- `defaultDirection`: Can be either `asc` or `desc`, and specifies the default direction for the sort field (e.g. titles default to alphabetically ascending).
|
|
||||||
- `descKey` and `key`: Contains the parameters passed to the `sort=...` media query for each direction of the sort.
|
|
||||||
- `title`: The title of the field.
|
|
||||||
|
|
||||||
|
|
||||||
* @param sectionId the Id of the library to query
|
|
||||||
* @param optionalParams - Optional parameters
|
|
||||||
* @param optionalParams.includeDetails - Whether or not to include details for a section (types, filters, and sorts).
|
|
||||||
Only exists for backwards compatibility, media providers other than the server libraries have it on always.
|
|
||||||
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getLibrary(
|
|
||||||
sectionId: number,
|
|
||||||
optionalParams: { includeDetails?: IncludeDetails } = {},
|
|
||||||
): Promise<any> {
|
|
||||||
const { includeDetails } = optionalParams;
|
|
||||||
if (sectionId === undefined) {
|
|
||||||
throw new Error('The following parameter is required: sectionId, cannot be empty or blank');
|
|
||||||
}
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
let urlEndpoint = '/library/sections/{sectionId}';
|
|
||||||
urlEndpoint = urlEndpoint.replace(
|
|
||||||
'{sectionId}',
|
|
||||||
encodeURIComponent(serializePath('simple', false, sectionId, undefined)),
|
|
||||||
);
|
|
||||||
if (includeDetails) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'includeDetails', includeDetails));
|
|
||||||
}
|
|
||||||
const urlParams = queryParams.length > 0 ? `?${encodeURI(queryParams.join('&'))}` : '';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}${urlParams}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Delete Library Section
|
|
||||||
* @description Delate a library using a specific section
|
|
||||||
|
|
||||||
* @param sectionId the Id of the library to query
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async deleteLibrary(sectionId: number): Promise<any> {
|
|
||||||
if (sectionId === undefined) {
|
|
||||||
throw new Error('The following parameter is required: sectionId, cannot be empty or blank');
|
|
||||||
}
|
|
||||||
let urlEndpoint = '/library/sections/{sectionId}';
|
|
||||||
urlEndpoint = urlEndpoint.replace(
|
|
||||||
'{sectionId}',
|
|
||||||
encodeURIComponent(serializePath('simple', false, sectionId, undefined)),
|
|
||||||
);
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.delete(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get Library Items
|
|
||||||
* @description This endpoint will return a list of library items filtered by the filter and type provided
|
|
||||||
|
|
||||||
|
|
||||||
* @param sectionId the Id of the library to query
|
|
||||||
* @param optionalParams - Optional parameters
|
|
||||||
* @param optionalParams.type_ - item type
|
|
||||||
* @param optionalParams.filter - the filter parameter
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getLibraryItems(
|
|
||||||
sectionId: number,
|
|
||||||
optionalParams: { type?: number; filter?: string } = {},
|
|
||||||
): Promise<any> {
|
|
||||||
const { type, filter } = optionalParams;
|
|
||||||
if (sectionId === undefined) {
|
|
||||||
throw new Error('The following parameter is required: sectionId, cannot be empty or blank');
|
|
||||||
}
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
let urlEndpoint = '/library/sections/{sectionId}/all';
|
|
||||||
urlEndpoint = urlEndpoint.replace(
|
|
||||||
'{sectionId}',
|
|
||||||
encodeURIComponent(serializePath('simple', false, sectionId, undefined)),
|
|
||||||
);
|
|
||||||
if (type) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'type_', type));
|
|
||||||
}
|
|
||||||
if (filter) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'filter', filter));
|
|
||||||
}
|
|
||||||
const urlParams = queryParams.length > 0 ? `?${encodeURI(queryParams.join('&'))}` : '';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}${urlParams}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Refresh Library
|
|
||||||
* @description This endpoint Refreshes the library.
|
|
||||||
|
|
||||||
|
|
||||||
* @param sectionId the Id of the library to refresh
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async refreshLibrary(sectionId: number): Promise<any> {
|
|
||||||
if (sectionId === undefined) {
|
|
||||||
throw new Error('The following parameter is required: sectionId, cannot be empty or blank');
|
|
||||||
}
|
|
||||||
let urlEndpoint = '/library/sections/{sectionId}/refresh';
|
|
||||||
urlEndpoint = urlEndpoint.replace(
|
|
||||||
'{sectionId}',
|
|
||||||
encodeURIComponent(serializePath('simple', false, sectionId, undefined)),
|
|
||||||
);
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get Latest Library Items
|
|
||||||
* @description This endpoint will return a list of the latest library items filtered by the filter and type provided
|
|
||||||
|
|
||||||
|
|
||||||
* @param sectionId the Id of the library to query
|
|
||||||
* @param type_ item type
|
|
||||||
* @param optionalParams - Optional parameters
|
|
||||||
* @param optionalParams.filter - the filter parameter
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getLatestLibraryItems(
|
|
||||||
sectionId: number,
|
|
||||||
type: number,
|
|
||||||
optionalParams: { filter?: string } = {},
|
|
||||||
): Promise<any> {
|
|
||||||
const { filter } = optionalParams;
|
|
||||||
if (sectionId === undefined || type === undefined) {
|
|
||||||
throw new Error(
|
|
||||||
'The following are required parameters: sectionId,type, cannot be empty or blank',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
let urlEndpoint = '/library/sections/{sectionId}/latest';
|
|
||||||
urlEndpoint = urlEndpoint.replace(
|
|
||||||
'{sectionId}',
|
|
||||||
encodeURIComponent(serializePath('simple', false, sectionId, undefined)),
|
|
||||||
);
|
|
||||||
if (type) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'type_', type));
|
|
||||||
}
|
|
||||||
if (filter) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'filter', filter));
|
|
||||||
}
|
|
||||||
const urlParams = queryParams.length > 0 ? `?${encodeURI(queryParams.join('&'))}` : '';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}${urlParams}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get Common Library Items
|
|
||||||
* @description Represents a "Common" item. It contains only the common attributes of the items selected by the provided filter
|
|
||||||
|
|
||||||
|
|
||||||
* @param sectionId the Id of the library to query
|
|
||||||
* @param type_ item type
|
|
||||||
* @param optionalParams - Optional parameters
|
|
||||||
* @param optionalParams.filter - the filter parameter
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getCommonLibraryItems(
|
|
||||||
sectionId: number,
|
|
||||||
type: number,
|
|
||||||
optionalParams: { filter?: string } = {},
|
|
||||||
): Promise<any> {
|
|
||||||
const { filter } = optionalParams;
|
|
||||||
if (sectionId === undefined || type === undefined) {
|
|
||||||
throw new Error(
|
|
||||||
'The following are required parameters: sectionId,type, cannot be empty or blank',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
let urlEndpoint = '/library/sections/{sectionId}/common';
|
|
||||||
urlEndpoint = urlEndpoint.replace(
|
|
||||||
'{sectionId}',
|
|
||||||
encodeURIComponent(serializePath('simple', false, sectionId, undefined)),
|
|
||||||
);
|
|
||||||
if (type) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'type_', type));
|
|
||||||
}
|
|
||||||
if (filter) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'filter', filter));
|
|
||||||
}
|
|
||||||
const urlParams = queryParams.length > 0 ? `?${encodeURI(queryParams.join('&'))}` : '';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}${urlParams}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get Items Metadata
|
|
||||||
* @description This endpoint will return the metadata of a library item specified with the ratingKey.
|
|
||||||
|
|
||||||
|
|
||||||
* @param ratingKey the id of the library item to return the children of.
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getMetadata(ratingKey: number): Promise<any> {
|
|
||||||
if (ratingKey === undefined) {
|
|
||||||
throw new Error('The following parameter is required: ratingKey, cannot be empty or blank');
|
|
||||||
}
|
|
||||||
let urlEndpoint = '/library/metadata/{ratingKey}';
|
|
||||||
urlEndpoint = urlEndpoint.replace(
|
|
||||||
'{ratingKey}',
|
|
||||||
encodeURIComponent(serializePath('simple', false, ratingKey, undefined)),
|
|
||||||
);
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get Items Children
|
|
||||||
* @description This endpoint will return the children of of a library item specified with the ratingKey.
|
|
||||||
|
|
||||||
|
|
||||||
* @param ratingKey the id of the library item to return the children of.
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getMetadataChildren(ratingKey: number): Promise<any> {
|
|
||||||
if (ratingKey === undefined) {
|
|
||||||
throw new Error('The following parameter is required: ratingKey, cannot be empty or blank');
|
|
||||||
}
|
|
||||||
let urlEndpoint = '/library/metadata/{ratingKey}/children';
|
|
||||||
urlEndpoint = urlEndpoint.replace(
|
|
||||||
'{ratingKey}',
|
|
||||||
encodeURIComponent(serializePath('simple', false, ratingKey, undefined)),
|
|
||||||
);
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get On Deck
|
|
||||||
* @description This endpoint will return the on deck content.
|
|
||||||
|
|
||||||
|
|
||||||
* @returns {Promise<Response<GetOnDeckResponse>>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getOnDeck(): Promise<Response<GetOnDeckResponse>> {
|
|
||||||
const urlEndpoint = '/library/onDeck';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
export type { GetOnDeckResponse } from './models/GetOnDeckResponse';
|
|
||||||
export type { GetRecentlyAddedResponse } from './models/GetRecentlyAddedResponse';
|
|
||||||
export type { IncludeDetails } from './models/IncludeDetails';
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
export interface GetOnDeckResponse {
|
|
||||||
MediaContainer?: MediaContainer;
|
|
||||||
}
|
|
||||||
interface MediaContainer {
|
|
||||||
size?: number;
|
|
||||||
allowSync?: boolean;
|
|
||||||
identifier?: string;
|
|
||||||
mediaTagPrefix?: string;
|
|
||||||
mediaTagVersion?: number;
|
|
||||||
mixedParents?: boolean;
|
|
||||||
Metadata?: {
|
|
||||||
allowSync?: boolean;
|
|
||||||
librarySectionID?: number;
|
|
||||||
librarySectionTitle?: string;
|
|
||||||
librarySectionUUID?: string;
|
|
||||||
ratingKey?: number;
|
|
||||||
key?: string;
|
|
||||||
parentRatingKey?: number;
|
|
||||||
grandparentRatingKey?: number;
|
|
||||||
guid?: string;
|
|
||||||
parentGuid?: string;
|
|
||||||
grandparentGuid?: string;
|
|
||||||
title?: string;
|
|
||||||
grandparentKey?: string;
|
|
||||||
parentKey?: string;
|
|
||||||
librarySectionKey?: string;
|
|
||||||
grandparentTitle?: string;
|
|
||||||
parentTitle?: string;
|
|
||||||
contentRating?: string;
|
|
||||||
summary?: string;
|
|
||||||
index?: number;
|
|
||||||
parentIndex?: number;
|
|
||||||
lastViewedAt?: number;
|
|
||||||
year?: number;
|
|
||||||
thumb?: string;
|
|
||||||
art?: string;
|
|
||||||
parentThumb?: string;
|
|
||||||
grandparentThumb?: string;
|
|
||||||
grandparentArt?: string;
|
|
||||||
grandparentTheme?: string;
|
|
||||||
duration?: number;
|
|
||||||
originallyAvailableAt?: string;
|
|
||||||
addedAt?: number;
|
|
||||||
updatedAt?: number;
|
|
||||||
Media?: {
|
|
||||||
id?: number;
|
|
||||||
duration?: number;
|
|
||||||
bitrate?: number;
|
|
||||||
width?: number;
|
|
||||||
height?: number;
|
|
||||||
aspectRatio?: number;
|
|
||||||
audioChannels?: number;
|
|
||||||
audioCodec?: string;
|
|
||||||
videoCodec?: string;
|
|
||||||
videoResolution?: string;
|
|
||||||
container?: string;
|
|
||||||
videoFrameRate?: string;
|
|
||||||
audioProfile?: string;
|
|
||||||
videoProfile?: string;
|
|
||||||
Part?: {
|
|
||||||
id?: number;
|
|
||||||
key?: string;
|
|
||||||
duration?: number;
|
|
||||||
file?: string;
|
|
||||||
size?: number;
|
|
||||||
audioProfile?: string;
|
|
||||||
container?: string;
|
|
||||||
videoProfile?: string;
|
|
||||||
Stream?: {
|
|
||||||
id?: number;
|
|
||||||
streamType?: number;
|
|
||||||
codec?: string;
|
|
||||||
index?: number;
|
|
||||||
bitrate?: number;
|
|
||||||
language?: string;
|
|
||||||
languageTag?: string;
|
|
||||||
languageCode?: string;
|
|
||||||
bitDepth?: number;
|
|
||||||
chromaLocation?: string;
|
|
||||||
chromaSubsampling?: string;
|
|
||||||
codedHeight?: number;
|
|
||||||
codedWidth?: number;
|
|
||||||
colorRange?: string;
|
|
||||||
frameRate?: number;
|
|
||||||
height?: number;
|
|
||||||
level?: number;
|
|
||||||
profile?: string;
|
|
||||||
refFrames?: number;
|
|
||||||
width?: number;
|
|
||||||
displayTitle?: string;
|
|
||||||
extendedDisplayTitle?: string;
|
|
||||||
default_?: boolean;
|
|
||||||
}[];
|
|
||||||
}[];
|
|
||||||
}[];
|
|
||||||
Guid?: {
|
|
||||||
id?: string;
|
|
||||||
}[];
|
|
||||||
type_?: string;
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
export interface GetRecentlyAddedResponse {
|
|
||||||
MediaContainer?: MediaContainer;
|
|
||||||
}
|
|
||||||
interface MediaContainer {
|
|
||||||
size?: number;
|
|
||||||
allowSync?: boolean;
|
|
||||||
identifier?: string;
|
|
||||||
mediaTagPrefix?: string;
|
|
||||||
mediaTagVersion?: number;
|
|
||||||
mixedParents?: boolean;
|
|
||||||
Metadata?: {
|
|
||||||
allowSync?: boolean;
|
|
||||||
librarySectionID?: number;
|
|
||||||
librarySectionTitle?: string;
|
|
||||||
librarySectionUUID?: string;
|
|
||||||
ratingKey?: number;
|
|
||||||
key?: string;
|
|
||||||
guid?: string;
|
|
||||||
studio?: string;
|
|
||||||
title?: string;
|
|
||||||
contentRating?: string;
|
|
||||||
summary?: string;
|
|
||||||
rating?: number;
|
|
||||||
audienceRating?: number;
|
|
||||||
year?: number;
|
|
||||||
tagline?: string;
|
|
||||||
thumb?: string;
|
|
||||||
art?: string;
|
|
||||||
duration?: number;
|
|
||||||
originallyAvailableAt?: string;
|
|
||||||
addedAt?: number;
|
|
||||||
updatedAt?: number;
|
|
||||||
audienceRatingImage?: string;
|
|
||||||
chapterSource?: string;
|
|
||||||
primaryExtraKey?: string;
|
|
||||||
ratingImage?: string;
|
|
||||||
Media?: {
|
|
||||||
id?: number;
|
|
||||||
duration?: number;
|
|
||||||
bitrate?: number;
|
|
||||||
width?: number;
|
|
||||||
height?: number;
|
|
||||||
aspectRatio?: number;
|
|
||||||
audioChannels?: number;
|
|
||||||
audioCodec?: string;
|
|
||||||
videoCodec?: string;
|
|
||||||
videoResolution?: number;
|
|
||||||
container?: string;
|
|
||||||
videoFrameRate?: string;
|
|
||||||
optimizedForStreaming?: number;
|
|
||||||
has64bitOffsets?: boolean;
|
|
||||||
videoProfile?: string;
|
|
||||||
Part?: {
|
|
||||||
id?: number;
|
|
||||||
key?: string;
|
|
||||||
duration?: number;
|
|
||||||
file?: string;
|
|
||||||
size?: number;
|
|
||||||
container?: string;
|
|
||||||
has64bitOffsets?: boolean;
|
|
||||||
hasThumbnail?: number;
|
|
||||||
optimizedForStreaming?: boolean;
|
|
||||||
videoProfile?: string;
|
|
||||||
}[];
|
|
||||||
}[];
|
|
||||||
Genre?: {
|
|
||||||
tag?: string;
|
|
||||||
}[];
|
|
||||||
Director?: {
|
|
||||||
tag?: string;
|
|
||||||
}[];
|
|
||||||
Writer?: {
|
|
||||||
tag?: string;
|
|
||||||
}[];
|
|
||||||
Country?: {
|
|
||||||
tag?: string;
|
|
||||||
}[];
|
|
||||||
Role?: {
|
|
||||||
tag?: string;
|
|
||||||
}[];
|
|
||||||
type_?: string;
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export type IncludeDetails = 0 | 1;
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
import BaseService from '../../BaseService';
|
|
||||||
|
|
||||||
import Response from '../../http/Response';
|
|
||||||
|
|
||||||
import { Level } from './models/Level';
|
|
||||||
|
|
||||||
import { serializeQuery } from '../../http/QuerySerializer';
|
|
||||||
|
|
||||||
export class LogService extends BaseService {
|
|
||||||
/**
|
|
||||||
* @summary Logging a single line message.
|
|
||||||
* @description This endpoint will write a single-line log message, including a level and source to the main Plex Media Server log.
|
|
||||||
|
|
||||||
|
|
||||||
* @param level An integer log level to write to the PMS log with.
|
|
||||||
0: Error
|
|
||||||
1: Warning
|
|
||||||
2: Info
|
|
||||||
3: Debug
|
|
||||||
4: Verbose
|
|
||||||
|
|
||||||
* @param message The text of the message to write to the log.
|
|
||||||
* @param source a string indicating the source of the message.
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async logLine(level: Level, message: string, source: string): Promise<any> {
|
|
||||||
if (level === undefined || message === undefined || source === undefined) {
|
|
||||||
throw new Error(
|
|
||||||
'The following are required parameters: level,message,source, cannot be empty or blank',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
if (level) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'level', level));
|
|
||||||
}
|
|
||||||
if (message) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'message', message));
|
|
||||||
}
|
|
||||||
if (source) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'source', source));
|
|
||||||
}
|
|
||||||
const urlEndpoint = '/log';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}?${encodeURI(queryParams.join('&'))}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Logging a multi-line message
|
|
||||||
* @description This endpoint will write multiple lines to the main Plex Media Server log in a single request. It takes a set of query strings as would normally sent to the above GET endpoint as a linefeed-separated block of POST data. The parameters for each query string match as above.
|
|
||||||
|
|
||||||
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async logMultiLine(): Promise<any> {
|
|
||||||
const urlEndpoint = '/log';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.post(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Enabling Papertrail
|
|
||||||
* @description This endpoint will enable all Plex Media Serverlogs to be sent to the Papertrail networked logging site for a period of time.
|
|
||||||
|
|
||||||
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async enablePaperTrail(): Promise<any> {
|
|
||||||
const urlEndpoint = '/log/networked';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export type { Level } from './models/Level';
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export type Level = 0 | 1 | 2 | 3 | 4;
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
import BaseService from '../../BaseService';
|
|
||||||
|
|
||||||
import Response from '../../http/Response';
|
|
||||||
|
|
||||||
import { serializeQuery } from '../../http/QuerySerializer';
|
|
||||||
|
|
||||||
export class MediaService extends BaseService {
|
|
||||||
/**
|
|
||||||
* @summary Mark Media Played
|
|
||||||
* @description This will mark the provided media key as Played.
|
|
||||||
|
|
||||||
* @param key The media key to mark as played
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async markPlayed(key: number): Promise<any> {
|
|
||||||
if (key === undefined) {
|
|
||||||
throw new Error('The following parameter is required: key, cannot be empty or blank');
|
|
||||||
}
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
if (key) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'key', key));
|
|
||||||
}
|
|
||||||
const urlEndpoint = '/:/scrobble';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}?${encodeURI(queryParams.join('&'))}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Mark Media Unplayed
|
|
||||||
* @description This will mark the provided media key as Unplayed.
|
|
||||||
|
|
||||||
* @param key The media key to mark as Unplayed
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async markUnplayed(key: number): Promise<any> {
|
|
||||||
if (key === undefined) {
|
|
||||||
throw new Error('The following parameter is required: key, cannot be empty or blank');
|
|
||||||
}
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
if (key) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'key', key));
|
|
||||||
}
|
|
||||||
const urlEndpoint = '/:/unscrobble';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}?${encodeURI(queryParams.join('&'))}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Update Media Play Progress
|
|
||||||
* @description This API command can be used to update the play progress of a media item.
|
|
||||||
|
|
||||||
|
|
||||||
* @param key the media key
|
|
||||||
* @param time The time, in milliseconds, used to set the media playback progress.
|
|
||||||
* @param state The playback state of the media item.
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async updatePlayProgress(key: string, time: number, state: string): Promise<any> {
|
|
||||||
if (key === undefined || time === undefined || state === undefined) {
|
|
||||||
throw new Error(
|
|
||||||
'The following are required parameters: key,time,state, cannot be empty or blank',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
if (key) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'key', key));
|
|
||||||
}
|
|
||||||
if (time) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'time', time));
|
|
||||||
}
|
|
||||||
if (state) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'state', state));
|
|
||||||
}
|
|
||||||
const urlEndpoint = '/:/progress';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}?${encodeURI(queryParams.join('&'))}`;
|
|
||||||
const response: any = await this.httpClient.post(
|
|
||||||
finalUrl,
|
|
||||||
{ key, time, state },
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,380 +0,0 @@
|
|||||||
import BaseService from '../../BaseService';
|
|
||||||
|
|
||||||
import Response from '../../http/Response';
|
|
||||||
|
|
||||||
import { Type } from './models/Type';
|
|
||||||
import { Smart } from './models/Smart';
|
|
||||||
import { PlaylistType } from './models/PlaylistType';
|
|
||||||
import { Force } from './models/Force';
|
|
||||||
|
|
||||||
import { serializeQuery, serializePath } from '../../http/QuerySerializer';
|
|
||||||
|
|
||||||
export class PlaylistsService extends BaseService {
|
|
||||||
/**
|
|
||||||
* @summary Create a Playlist
|
|
||||||
* @description Create a new playlist. By default the playlist is blank. To create a playlist along with a first item, pass:
|
|
||||||
- `uri` - The content URI for what we're playing (e.g. `library://...`).
|
|
||||||
- `playQueueID` - To create a playlist from an existing play queue.
|
|
||||||
|
|
||||||
|
|
||||||
* @param title name of the playlist
|
|
||||||
* @param type_ type of playlist to create
|
|
||||||
* @param smart whether the playlist is smart or not
|
|
||||||
* @param optionalParams - Optional parameters
|
|
||||||
* @param optionalParams.uri - the content URI for the playlist
|
|
||||||
* @param optionalParams.playQueueID - the play queue to copy to a playlist
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async createPlaylist(
|
|
||||||
title: string,
|
|
||||||
type: Type,
|
|
||||||
smart: Smart,
|
|
||||||
optionalParams: { uri?: string; playQueueId?: number } = {},
|
|
||||||
): Promise<any> {
|
|
||||||
const { uri, playQueueId } = optionalParams;
|
|
||||||
if (title === undefined || type === undefined || smart === undefined) {
|
|
||||||
throw new Error(
|
|
||||||
'The following are required parameters: title,type,smart, cannot be empty or blank',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
if (title) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'title', title));
|
|
||||||
}
|
|
||||||
if (type) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'type_', type));
|
|
||||||
}
|
|
||||||
if (smart) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'smart', smart));
|
|
||||||
}
|
|
||||||
if (uri) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'uri', uri));
|
|
||||||
}
|
|
||||||
if (playQueueId) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'playQueueID', playQueueId));
|
|
||||||
}
|
|
||||||
const urlEndpoint = '/playlists';
|
|
||||||
const urlParams = queryParams.length > 0 ? `?${encodeURI(queryParams.join('&'))}` : '';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}${urlParams}`;
|
|
||||||
const response: any = await this.httpClient.post(
|
|
||||||
finalUrl,
|
|
||||||
{ title, type_: type, smart, uri, playQueueID: playQueueId },
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get All Playlists
|
|
||||||
* @description Get All Playlists given the specified filters.
|
|
||||||
|
|
||||||
* @param optionalParams - Optional parameters
|
|
||||||
* @param optionalParams.playlistType - limit to a type of playlist.
|
|
||||||
* @param optionalParams.smart - type of playlists to return (default is all).
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getPlaylists(
|
|
||||||
optionalParams: { playlistType?: PlaylistType; smart?: Smart } = {},
|
|
||||||
): Promise<any> {
|
|
||||||
const { playlistType, smart } = optionalParams;
|
|
||||||
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
if (playlistType) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'playlistType', playlistType));
|
|
||||||
}
|
|
||||||
if (smart) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'smart', smart));
|
|
||||||
}
|
|
||||||
const urlEndpoint = '/playlists/all';
|
|
||||||
const urlParams = queryParams.length > 0 ? `?${encodeURI(queryParams.join('&'))}` : '';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}${urlParams}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Retrieve Playlist
|
|
||||||
* @description Gets detailed metadata for a playlist. A playlist for many purposes (rating, editing metadata, tagging), can be treated like a regular metadata item:
|
|
||||||
Smart playlist details contain the `content` attribute. This is the content URI for the generator. This can then be parsed by a client to provide smart playlist editing.
|
|
||||||
|
|
||||||
|
|
||||||
* @param playlistID the ID of the playlist
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getPlaylist(playlistId: number): Promise<any> {
|
|
||||||
if (playlistId === undefined) {
|
|
||||||
throw new Error('The following parameter is required: playlistId, cannot be empty or blank');
|
|
||||||
}
|
|
||||||
let urlEndpoint = '/playlists/{playlistID}';
|
|
||||||
urlEndpoint = urlEndpoint.replace(
|
|
||||||
'{playlistID}',
|
|
||||||
encodeURIComponent(serializePath('simple', false, playlistId, undefined)),
|
|
||||||
);
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Update a Playlist
|
|
||||||
* @description From PMS version 1.9.1 clients can also edit playlist metadata using this endpoint as they would via `PUT /library/metadata/{playlistID}`
|
|
||||||
|
|
||||||
|
|
||||||
* @param playlistID the ID of the playlist
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async updatePlaylist(playlistId: number): Promise<any> {
|
|
||||||
if (playlistId === undefined) {
|
|
||||||
throw new Error('The following parameter is required: playlistId, cannot be empty or blank');
|
|
||||||
}
|
|
||||||
let urlEndpoint = '/playlists/{playlistID}';
|
|
||||||
urlEndpoint = urlEndpoint.replace(
|
|
||||||
'{playlistID}',
|
|
||||||
encodeURIComponent(serializePath('simple', false, playlistId, undefined)),
|
|
||||||
);
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.put(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Deletes a Playlist
|
|
||||||
* @description This endpoint will delete a playlist
|
|
||||||
|
|
||||||
|
|
||||||
* @param playlistID the ID of the playlist
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async deletePlaylist(playlistId: number): Promise<any> {
|
|
||||||
if (playlistId === undefined) {
|
|
||||||
throw new Error('The following parameter is required: playlistId, cannot be empty or blank');
|
|
||||||
}
|
|
||||||
let urlEndpoint = '/playlists/{playlistID}';
|
|
||||||
urlEndpoint = urlEndpoint.replace(
|
|
||||||
'{playlistID}',
|
|
||||||
encodeURIComponent(serializePath('simple', false, playlistId, undefined)),
|
|
||||||
);
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.delete(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Retrieve Playlist Contents
|
|
||||||
* @description Gets the contents of a playlist. Should be paged by clients via standard mechanisms.
|
|
||||||
By default leaves are returned (e.g. episodes, movies). In order to return other types you can use the `type` parameter.
|
|
||||||
For example, you could use this to display a list of recently added albums vis a smart playlist.
|
|
||||||
Note that for dumb playlists, items have a `playlistItemID` attribute which is used for deleting or moving items.
|
|
||||||
|
|
||||||
|
|
||||||
* @param playlistID the ID of the playlist
|
|
||||||
* @param type_ the metadata type of the item to return
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getPlaylistContents(playlistId: number, type: number): Promise<any> {
|
|
||||||
if (playlistId === undefined || type === undefined) {
|
|
||||||
throw new Error(
|
|
||||||
'The following are required parameters: playlistId,type, cannot be empty or blank',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
let urlEndpoint = '/playlists/{playlistID}/items';
|
|
||||||
urlEndpoint = urlEndpoint.replace(
|
|
||||||
'{playlistID}',
|
|
||||||
encodeURIComponent(serializePath('simple', false, playlistId, undefined)),
|
|
||||||
);
|
|
||||||
if (type) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'type_', type));
|
|
||||||
}
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}?${encodeURI(queryParams.join('&'))}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Adding to a Playlist
|
|
||||||
* @description Adds a generator to a playlist, same parameters as the POST above. With a dumb playlist, this adds the specified items to the playlist.
|
|
||||||
With a smart playlist, passing a new `uri` parameter replaces the rules for the playlist. Returns the playlist.
|
|
||||||
|
|
||||||
|
|
||||||
* @param playlistID the ID of the playlist
|
|
||||||
* @param uri the content URI for the playlist
|
|
||||||
* @param playQueueID the play queue to add to a playlist
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async addPlaylistContents(playlistId: number, uri: string, playQueueId: number): Promise<any> {
|
|
||||||
if (playlistId === undefined || uri === undefined || playQueueId === undefined) {
|
|
||||||
throw new Error(
|
|
||||||
'The following are required parameters: playlistId,uri,playQueueId, cannot be empty or blank',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
let urlEndpoint = '/playlists/{playlistID}/items';
|
|
||||||
urlEndpoint = urlEndpoint.replace(
|
|
||||||
'{playlistID}',
|
|
||||||
encodeURIComponent(serializePath('simple', false, playlistId, undefined)),
|
|
||||||
);
|
|
||||||
if (uri) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'uri', uri));
|
|
||||||
}
|
|
||||||
if (playQueueId) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'playQueueID', playQueueId));
|
|
||||||
}
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}?${encodeURI(queryParams.join('&'))}`;
|
|
||||||
const response: any = await this.httpClient.put(
|
|
||||||
finalUrl,
|
|
||||||
{ uri, playQueueID: playQueueId },
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Delete Playlist Contents
|
|
||||||
* @description Clears a playlist, only works with dumb playlists. Returns the playlist.
|
|
||||||
|
|
||||||
|
|
||||||
* @param playlistID the ID of the playlist
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async clearPlaylistContents(playlistId: number): Promise<any> {
|
|
||||||
if (playlistId === undefined) {
|
|
||||||
throw new Error('The following parameter is required: playlistId, cannot be empty or blank');
|
|
||||||
}
|
|
||||||
let urlEndpoint = '/playlists/{playlistID}/items';
|
|
||||||
urlEndpoint = urlEndpoint.replace(
|
|
||||||
'{playlistID}',
|
|
||||||
encodeURIComponent(serializePath('simple', false, playlistId, undefined)),
|
|
||||||
);
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.delete(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Upload Playlist
|
|
||||||
* @description Imports m3u playlists by passing a path on the server to scan for m3u-formatted playlist files, or a path to a single playlist file.
|
|
||||||
|
|
||||||
|
|
||||||
* @param path absolute path to a directory on the server where m3u files are stored, or the absolute path to a playlist file on the server.
|
|
||||||
If the `path` argument is a directory, that path will be scanned for playlist files to be processed.
|
|
||||||
Each file in that directory creates a separate playlist, with a name based on the filename of the file that created it.
|
|
||||||
The GUID of each playlist is based on the filename.
|
|
||||||
If the `path` argument is a file, that file will be used to create a new playlist, with the name based on the filename of the file that created it.
|
|
||||||
The GUID of each playlist is based on the filename.
|
|
||||||
|
|
||||||
* @param force force overwriting of duplicate playlists. By default, a playlist file uploaded with the same path will overwrite the existing playlist.
|
|
||||||
The `force` argument is used to disable overwriting. If the `force` argument is set to 0, a new playlist will be created suffixed with the date and time that the duplicate was uploaded.
|
|
||||||
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async uploadPlaylist(path: string, force: Force): Promise<any> {
|
|
||||||
if (path === undefined || force === undefined) {
|
|
||||||
throw new Error(
|
|
||||||
'The following are required parameters: path,force, cannot be empty or blank',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
if (path) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'path', path));
|
|
||||||
}
|
|
||||||
if (force) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'force', force));
|
|
||||||
}
|
|
||||||
const urlEndpoint = '/playlists/upload';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}?${encodeURI(queryParams.join('&'))}`;
|
|
||||||
const response: any = await this.httpClient.post(
|
|
||||||
finalUrl,
|
|
||||||
{ path, force },
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
export type { Force } from './models/Force';
|
|
||||||
export type { PlaylistType } from './models/PlaylistType';
|
|
||||||
export type { Smart } from './models/Smart';
|
|
||||||
export type { Type } from './models/Type';
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export type Force = 0 | 1;
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export type PlaylistType = 'audio' | 'video' | 'photo';
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export type Smart = 0 | 1;
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export type Type = 'audio' | 'video' | 'photo';
|
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
import BaseService from '../../BaseService';
|
|
||||||
|
|
||||||
import Response from '../../http/Response';
|
|
||||||
|
|
||||||
import { GetSearchResultsResponse } from './models/GetSearchResultsResponse';
|
|
||||||
|
|
||||||
import { serializeQuery } from '../../http/QuerySerializer';
|
|
||||||
|
|
||||||
export class SearchService extends BaseService {
|
|
||||||
/**
|
|
||||||
* @summary Perform a search
|
|
||||||
* @description This endpoint performs a search across all library sections, or a single section, and returns matches as hubs, split up by type. It performs spell checking, looks for partial matches, and orders the hubs based on quality of results. In addition, based on matches, it will return other related matches (e.g. for a genre match, it may return movies in that genre, or for an actor match, movies with that actor).
|
|
||||||
|
|
||||||
In the response's items, the following extra attributes are returned to further describe or disambiguate the result:
|
|
||||||
|
|
||||||
- `reason`: The reason for the result, if not because of a direct search term match; can be either:
|
|
||||||
- `section`: There are multiple identical results from different sections.
|
|
||||||
- `originalTitle`: There was a search term match from the original title field (sometimes those can be very different or in a foreign language).
|
|
||||||
- `<hub identifier>`: If the reason for the result is due to a result in another hub, the source hub identifier is returned. For example, if the search is for "dylan" then Bob Dylan may be returned as an artist result, an a few of his albums returned as album results with a reason code of `artist` (the identifier of that particular hub). Or if the search is for "arnold", there might be movie results returned with a reason of `actor`
|
|
||||||
- `reasonTitle`: The string associated with the reason code. For a section reason, it'll be the section name; For a hub identifier, it'll be a string associated with the match (e.g. `Arnold Schwarzenegger` for movies which were returned because the search was for "arnold").
|
|
||||||
- `reasonID`: The ID of the item associated with the reason for the result. This might be a section ID, a tag ID, an artist ID, or a show ID.
|
|
||||||
|
|
||||||
This request is intended to be very fast, and called as the user types.
|
|
||||||
|
|
||||||
|
|
||||||
* @param query The query term
|
|
||||||
* @param optionalParams - Optional parameters
|
|
||||||
* @param optionalParams.sectionId - This gives context to the search, and can result in re-ordering of search result hubs
|
|
||||||
* @param optionalParams.limit - The number of items to return per hub
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async performSearch(
|
|
||||||
query: string,
|
|
||||||
optionalParams: { sectionId?: number; limit?: number } = {},
|
|
||||||
): Promise<any> {
|
|
||||||
const { sectionId, limit } = optionalParams;
|
|
||||||
if (query === undefined) {
|
|
||||||
throw new Error('The following parameter is required: query, cannot be empty or blank');
|
|
||||||
}
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
if (query) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'query', query));
|
|
||||||
}
|
|
||||||
if (sectionId) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'sectionId', sectionId));
|
|
||||||
}
|
|
||||||
if (limit) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'limit', limit));
|
|
||||||
}
|
|
||||||
const urlEndpoint = '/hubs/search';
|
|
||||||
const urlParams = queryParams.length > 0 ? `?${encodeURI(queryParams.join('&'))}` : '';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}${urlParams}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Perform a voice search
|
|
||||||
* @description This endpoint performs a search specifically tailored towards voice or other imprecise input which may work badly with the substring and spell-checking heuristics used by the `/hubs/search` endpoint.
|
|
||||||
It uses a [Levenshtein distance](https://en.wikipedia.org/wiki/Levenshtein_distance) heuristic to search titles, and as such is much slower than the other search endpoint.
|
|
||||||
Whenever possible, clients should limit the search to the appropriate type.
|
|
||||||
Results, as well as their containing per-type hubs, contain a `distance` attribute which can be used to judge result quality.
|
|
||||||
|
|
||||||
|
|
||||||
* @param query The query term
|
|
||||||
* @param optionalParams - Optional parameters
|
|
||||||
* @param optionalParams.sectionId - This gives context to the search, and can result in re-ordering of search result hubs
|
|
||||||
* @param optionalParams.limit - The number of items to return per hub
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async performVoiceSearch(
|
|
||||||
query: string,
|
|
||||||
optionalParams: { sectionId?: number; limit?: number } = {},
|
|
||||||
): Promise<any> {
|
|
||||||
const { sectionId, limit } = optionalParams;
|
|
||||||
if (query === undefined) {
|
|
||||||
throw new Error('The following parameter is required: query, cannot be empty or blank');
|
|
||||||
}
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
if (query) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'query', query));
|
|
||||||
}
|
|
||||||
if (sectionId) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'sectionId', sectionId));
|
|
||||||
}
|
|
||||||
if (limit) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'limit', limit));
|
|
||||||
}
|
|
||||||
const urlEndpoint = '/hubs/search/voice';
|
|
||||||
const urlParams = queryParams.length > 0 ? `?${encodeURI(queryParams.join('&'))}` : '';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}${urlParams}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get Search Results
|
|
||||||
* @description This will search the database for the string provided.
|
|
||||||
|
|
||||||
* @param query The search query string to use
|
|
||||||
* @returns {Promise<Response<GetSearchResultsResponse>>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getSearchResults(query: string): Promise<Response<GetSearchResultsResponse>> {
|
|
||||||
if (query === undefined) {
|
|
||||||
throw new Error('The following parameter is required: query, cannot be empty or blank');
|
|
||||||
}
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
if (query) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'query', query));
|
|
||||||
}
|
|
||||||
const urlEndpoint = '/search';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}?${encodeURI(queryParams.join('&'))}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export type { GetSearchResultsResponse } from './models/GetSearchResultsResponse';
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
export interface GetSearchResultsResponse {
|
|
||||||
MediaContainer?: MediaContainer;
|
|
||||||
}
|
|
||||||
interface MediaContainer {
|
|
||||||
size?: number;
|
|
||||||
identifier?: string;
|
|
||||||
mediaTagPrefix?: string;
|
|
||||||
mediaTagVersion?: number;
|
|
||||||
Metadata?: {
|
|
||||||
allowSync?: boolean;
|
|
||||||
librarySectionID?: number;
|
|
||||||
librarySectionTitle?: string;
|
|
||||||
librarySectionUUID?: string;
|
|
||||||
personal?: boolean;
|
|
||||||
sourceTitle?: string;
|
|
||||||
ratingKey?: number;
|
|
||||||
key?: string;
|
|
||||||
guid?: string;
|
|
||||||
studio?: string;
|
|
||||||
title?: string;
|
|
||||||
contentRating?: string;
|
|
||||||
summary?: string;
|
|
||||||
rating?: number;
|
|
||||||
audienceRating?: number;
|
|
||||||
year?: number;
|
|
||||||
tagline?: string;
|
|
||||||
thumb?: string;
|
|
||||||
art?: string;
|
|
||||||
duration?: number;
|
|
||||||
originallyAvailableAt?: string;
|
|
||||||
addedAt?: number;
|
|
||||||
updatedAt?: number;
|
|
||||||
audienceRatingImage?: string;
|
|
||||||
chapterSource?: string;
|
|
||||||
primaryExtraKey?: string;
|
|
||||||
ratingImage?: string;
|
|
||||||
Media?: {
|
|
||||||
id?: number;
|
|
||||||
duration?: number;
|
|
||||||
bitrate?: number;
|
|
||||||
width?: number;
|
|
||||||
height?: number;
|
|
||||||
aspectRatio?: number;
|
|
||||||
audioChannels?: number;
|
|
||||||
audioCodec?: string;
|
|
||||||
videoCodec?: string;
|
|
||||||
videoResolution?: number;
|
|
||||||
container?: string;
|
|
||||||
videoFrameRate?: string;
|
|
||||||
audioProfile?: string;
|
|
||||||
videoProfile?: string;
|
|
||||||
Part?: {
|
|
||||||
id?: number;
|
|
||||||
key?: string;
|
|
||||||
duration?: number;
|
|
||||||
file?: string;
|
|
||||||
size?: number;
|
|
||||||
audioProfile?: string;
|
|
||||||
container?: string;
|
|
||||||
videoProfile?: string;
|
|
||||||
}[];
|
|
||||||
}[];
|
|
||||||
Genre?: {
|
|
||||||
tag?: string;
|
|
||||||
}[];
|
|
||||||
Director?: {
|
|
||||||
tag?: string;
|
|
||||||
}[];
|
|
||||||
Writer?: {
|
|
||||||
tag?: string;
|
|
||||||
}[];
|
|
||||||
Country?: {
|
|
||||||
tag?: string;
|
|
||||||
}[];
|
|
||||||
Role?: {
|
|
||||||
tag?: string;
|
|
||||||
}[];
|
|
||||||
type_?: string;
|
|
||||||
}[];
|
|
||||||
Provider?: {
|
|
||||||
key?: string;
|
|
||||||
title?: string;
|
|
||||||
type_?: string;
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
import BaseService from '../../BaseService';
|
|
||||||
|
|
||||||
import Response from '../../http/Response';
|
|
||||||
|
|
||||||
import { SecurityType } from './models/SecurityType';
|
|
||||||
import { Scope } from './models/Scope';
|
|
||||||
|
|
||||||
import { serializeQuery } from '../../http/QuerySerializer';
|
|
||||||
|
|
||||||
export class SecurityService extends BaseService {
|
|
||||||
/**
|
|
||||||
* @summary Get a Transient Token.
|
|
||||||
* @description This endpoint provides the caller with a temporary token with the same access level as the caller's token. These tokens are valid for up to 48 hours and are destroyed if the server instance is restarted.
|
|
||||||
|
|
||||||
|
|
||||||
* @param type_ `delegation` - This is the only supported `type` parameter.
|
|
||||||
* @param scope `all` - This is the only supported `scope` parameter.
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getTransientToken(type: SecurityType, scope: Scope): Promise<any> {
|
|
||||||
if (type === undefined || scope === undefined) {
|
|
||||||
throw new Error(
|
|
||||||
'The following are required parameters: type,scope, cannot be empty or blank',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
if (type) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'type_', type));
|
|
||||||
}
|
|
||||||
if (scope) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'scope', scope));
|
|
||||||
}
|
|
||||||
const urlEndpoint = '/security/token';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}?${encodeURI(queryParams.join('&'))}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get Source Connection Information
|
|
||||||
* @description If a caller requires connection details and a transient token for a source that is known to the server, for example a cloud media provider or shared PMS, then this endpoint can be called. This endpoint is only accessible with either an admin token or a valid transient token generated from an admin token.
|
|
||||||
Note: requires Plex Media Server >= 1.15.4.
|
|
||||||
|
|
||||||
|
|
||||||
* @param source The source identifier with an included prefix.
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getSourceConnectionInformation(source: string): Promise<any> {
|
|
||||||
if (source === undefined) {
|
|
||||||
throw new Error('The following parameter is required: source, cannot be empty or blank');
|
|
||||||
}
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
if (source) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'source', source));
|
|
||||||
}
|
|
||||||
const urlEndpoint = '/security/resources';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}?${encodeURI(queryParams.join('&'))}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export type { Scope } from './models/Scope';
|
|
||||||
export type { SecurityType } from './models/SecurityType';
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export type Scope = 'all';
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export type SecurityType = 'delegation';
|
|
||||||
@@ -1,259 +0,0 @@
|
|||||||
import BaseService from '../../BaseService';
|
|
||||||
|
|
||||||
import Response from '../../http/Response';
|
|
||||||
|
|
||||||
import { GetServerCapabilitiesResponse } from './models/GetServerCapabilitiesResponse';
|
|
||||||
import { GetAvailableClientsResponse } from './models/GetAvailableClientsResponse';
|
|
||||||
import { GetDevicesResponse } from './models/GetDevicesResponse';
|
|
||||||
import { GetServerIdentityResponse } from './models/GetServerIdentityResponse';
|
|
||||||
import { GetMyPlexAccountResponse } from './models/GetMyPlexAccountResponse';
|
|
||||||
import { MinSize } from './models/MinSize';
|
|
||||||
import { Upscale } from './models/Upscale';
|
|
||||||
import { GetServerListResponse } from './models/GetServerListResponse';
|
|
||||||
|
|
||||||
import { serializeQuery } from '../../http/QuerySerializer';
|
|
||||||
|
|
||||||
export class ServerService extends BaseService {
|
|
||||||
/**
|
|
||||||
* @summary Server Capabilities
|
|
||||||
* @description Server Capabilities
|
|
||||||
|
|
||||||
* @returns {Promise<Response<GetServerCapabilitiesResponse>>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getServerCapabilities(): Promise<Response<GetServerCapabilitiesResponse>> {
|
|
||||||
const urlEndpoint = '/';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get Server Preferences
|
|
||||||
* @description Get Server Preferences
|
|
||||||
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getServerPreferences(): Promise<any> {
|
|
||||||
const urlEndpoint = '/:/prefs';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get Available Clients
|
|
||||||
* @description Get Available Clients
|
|
||||||
|
|
||||||
* @returns {Promise<Response<GetAvailableClientsResponse>>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getAvailableClients(): Promise<Response<GetAvailableClientsResponse>> {
|
|
||||||
const urlEndpoint = '/clients';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get Devices
|
|
||||||
* @description Get Devices
|
|
||||||
|
|
||||||
* @returns {Promise<Response<GetDevicesResponse>>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getDevices(): Promise<Response<GetDevicesResponse>> {
|
|
||||||
const urlEndpoint = '/devices';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get Server Identity
|
|
||||||
* @description Get Server Identity
|
|
||||||
|
|
||||||
* @returns {Promise<Response<GetServerIdentityResponse>>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getServerIdentity(): Promise<Response<GetServerIdentityResponse>> {
|
|
||||||
const urlEndpoint = '/identity';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get MyPlex Account
|
|
||||||
* @description Returns MyPlex Account Information
|
|
||||||
|
|
||||||
* @returns {Promise<Response<GetMyPlexAccountResponse>>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getMyPlexAccount(): Promise<Response<GetMyPlexAccountResponse>> {
|
|
||||||
const urlEndpoint = '/myplex/account';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get a Resized Photo
|
|
||||||
* @description Plex's Photo transcoder is used throughout the service to serve images at specified sizes.
|
|
||||||
|
|
||||||
|
|
||||||
* @param width The width for the resized photo
|
|
||||||
* @param height The height for the resized photo
|
|
||||||
* @param opacity The opacity for the resized photo
|
|
||||||
* @param blur The width for the resized photo
|
|
||||||
* @param minSize images are always scaled proportionally. A value of '1' in minSize will make the smaller native dimension the dimension resized against.
|
|
||||||
* @param upscale allow images to be resized beyond native dimensions.
|
|
||||||
* @param url path to image within Plex
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getResizedPhoto(
|
|
||||||
width: number,
|
|
||||||
height: number,
|
|
||||||
opacity: number,
|
|
||||||
blur: number,
|
|
||||||
minSize: MinSize,
|
|
||||||
upscale: Upscale,
|
|
||||||
url: string,
|
|
||||||
): Promise<any> {
|
|
||||||
if (
|
|
||||||
width === undefined ||
|
|
||||||
height === undefined ||
|
|
||||||
opacity === undefined ||
|
|
||||||
blur === undefined ||
|
|
||||||
minSize === undefined ||
|
|
||||||
upscale === undefined ||
|
|
||||||
url === undefined
|
|
||||||
) {
|
|
||||||
throw new Error(
|
|
||||||
'The following are required parameters: width,height,opacity,blur,minSize,upscale,url, cannot be empty or blank',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
if (width) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'width', width));
|
|
||||||
}
|
|
||||||
if (height) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'height', height));
|
|
||||||
}
|
|
||||||
if (opacity) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'opacity', opacity));
|
|
||||||
}
|
|
||||||
if (blur) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'blur', blur));
|
|
||||||
}
|
|
||||||
if (minSize) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'minSize', minSize));
|
|
||||||
}
|
|
||||||
if (upscale) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'upscale', upscale));
|
|
||||||
}
|
|
||||||
if (url) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'url', url));
|
|
||||||
}
|
|
||||||
const urlEndpoint = '/photo/:/transcode';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}?${encodeURI(queryParams.join('&'))}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get Server List
|
|
||||||
* @description Get Server List
|
|
||||||
|
|
||||||
* @returns {Promise<Response<GetServerListResponse>>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getServerList(): Promise<Response<GetServerListResponse>> {
|
|
||||||
const urlEndpoint = '/servers';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
export type { GetAvailableClientsResponse } from './models/GetAvailableClientsResponse';
|
|
||||||
export type { GetDevicesResponse } from './models/GetDevicesResponse';
|
|
||||||
export type { GetMyPlexAccountResponse } from './models/GetMyPlexAccountResponse';
|
|
||||||
export type { GetServerCapabilitiesResponse } from './models/GetServerCapabilitiesResponse';
|
|
||||||
export type { GetServerIdentityResponse } from './models/GetServerIdentityResponse';
|
|
||||||
export type { GetServerListResponse } from './models/GetServerListResponse';
|
|
||||||
export type { MinSize } from './models/MinSize';
|
|
||||||
export type { Upscale } from './models/Upscale';
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
export type GetAvailableClientsResponse = {
|
|
||||||
MediaContainer?: MediaContainer;
|
|
||||||
}[];
|
|
||||||
|
|
||||||
interface MediaContainer {
|
|
||||||
size?: number;
|
|
||||||
Server?: {
|
|
||||||
name?: string;
|
|
||||||
host?: string;
|
|
||||||
address?: string;
|
|
||||||
port?: number;
|
|
||||||
machineIdentifier?: string;
|
|
||||||
version?: string;
|
|
||||||
protocol?: string;
|
|
||||||
product?: string;
|
|
||||||
deviceClass?: string;
|
|
||||||
protocolVersion?: number;
|
|
||||||
protocolCapabilities?: string;
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
export interface GetDevicesResponse {
|
|
||||||
MediaContainer?: MediaContainer;
|
|
||||||
}
|
|
||||||
interface MediaContainer {
|
|
||||||
size?: number;
|
|
||||||
identifier?: string;
|
|
||||||
Device?: {
|
|
||||||
id?: number;
|
|
||||||
name?: string;
|
|
||||||
platform?: string;
|
|
||||||
clientIdentifier?: string;
|
|
||||||
createdAt?: number;
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
export interface GetMyPlexAccountResponse {
|
|
||||||
MyPlex?: MyPlex;
|
|
||||||
}
|
|
||||||
interface MyPlex {
|
|
||||||
authToken?: string;
|
|
||||||
username?: string;
|
|
||||||
mappingState?: string;
|
|
||||||
mappingError?: string;
|
|
||||||
signInState?: string;
|
|
||||||
publicAddress?: string;
|
|
||||||
publicPort?: number;
|
|
||||||
privateAddress?: string;
|
|
||||||
privatePort?: number;
|
|
||||||
subscriptionFeatures?: string;
|
|
||||||
subscriptionActive?: boolean;
|
|
||||||
subscriptionState?: string;
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
export interface GetServerCapabilitiesResponse {
|
|
||||||
MediaContainer?: MediaContainer;
|
|
||||||
}
|
|
||||||
interface MediaContainer {
|
|
||||||
size?: number;
|
|
||||||
allowCameraUpload?: boolean;
|
|
||||||
allowChannelAccess?: boolean;
|
|
||||||
allowMediaDeletion?: boolean;
|
|
||||||
allowSharing?: boolean;
|
|
||||||
allowSync?: boolean;
|
|
||||||
allowTuners?: boolean;
|
|
||||||
backgroundProcessing?: boolean;
|
|
||||||
certificate?: boolean;
|
|
||||||
companionProxy?: boolean;
|
|
||||||
countryCode?: string;
|
|
||||||
diagnostics?: string;
|
|
||||||
eventStream?: boolean;
|
|
||||||
friendlyName?: string;
|
|
||||||
hubSearch?: boolean;
|
|
||||||
itemClusters?: boolean;
|
|
||||||
livetv?: number;
|
|
||||||
machineIdentifier?: string;
|
|
||||||
mediaProviders?: boolean;
|
|
||||||
multiuser?: boolean;
|
|
||||||
musicAnalysis?: number;
|
|
||||||
myPlex?: boolean;
|
|
||||||
myPlexMappingState?: string;
|
|
||||||
myPlexSigninState?: string;
|
|
||||||
myPlexSubscription?: boolean;
|
|
||||||
myPlexUsername?: string;
|
|
||||||
offlineTranscode?: number;
|
|
||||||
ownerFeatures?: string;
|
|
||||||
photoAutoTag?: boolean;
|
|
||||||
platform?: string;
|
|
||||||
platformVersion?: string;
|
|
||||||
pluginHost?: boolean;
|
|
||||||
pushNotifications?: boolean;
|
|
||||||
readOnlyLibraries?: boolean;
|
|
||||||
streamingBrainABRVersion?: number;
|
|
||||||
streamingBrainVersion?: number;
|
|
||||||
sync?: boolean;
|
|
||||||
transcoderActiveVideoSessions?: number;
|
|
||||||
transcoderAudio?: boolean;
|
|
||||||
transcoderLyrics?: boolean;
|
|
||||||
transcoderPhoto?: boolean;
|
|
||||||
transcoderSubtitles?: boolean;
|
|
||||||
transcoderVideo?: boolean;
|
|
||||||
transcoderVideoBitrates?: string;
|
|
||||||
transcoderVideoQualities?: string;
|
|
||||||
transcoderVideoResolutions?: string;
|
|
||||||
updatedAt?: number;
|
|
||||||
updater?: boolean;
|
|
||||||
version?: string;
|
|
||||||
voiceSearch?: boolean;
|
|
||||||
Directory?: {
|
|
||||||
count?: number;
|
|
||||||
key?: string;
|
|
||||||
title?: string;
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
export interface GetServerIdentityResponse {
|
|
||||||
MediaContainer?: MediaContainer;
|
|
||||||
}
|
|
||||||
interface MediaContainer {
|
|
||||||
size?: number;
|
|
||||||
claimed?: boolean;
|
|
||||||
machineIdentifier?: string;
|
|
||||||
version?: string;
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
export interface GetServerListResponse {
|
|
||||||
MediaContainer?: MediaContainer;
|
|
||||||
}
|
|
||||||
interface MediaContainer {
|
|
||||||
size?: number;
|
|
||||||
Server?: {
|
|
||||||
name?: string;
|
|
||||||
host?: string;
|
|
||||||
address?: string;
|
|
||||||
port?: number;
|
|
||||||
machineIdentifier?: string;
|
|
||||||
version?: string;
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export type MinSize = 0 | 1;
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export type Upscale = 0 | 1;
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
import BaseService from '../../BaseService';
|
|
||||||
|
|
||||||
import Response from '../../http/Response';
|
|
||||||
|
|
||||||
import { GetTranscodeSessionsResponse } from './models/GetTranscodeSessionsResponse';
|
|
||||||
|
|
||||||
import { serializePath } from '../../http/QuerySerializer';
|
|
||||||
|
|
||||||
export class SessionsService extends BaseService {
|
|
||||||
/**
|
|
||||||
* @summary Get Active Sessions
|
|
||||||
* @description This will retrieve the "Now Playing" Information of the PMS.
|
|
||||||
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getSessions(): Promise<any> {
|
|
||||||
const urlEndpoint = '/status/sessions';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get Session History
|
|
||||||
* @description This will Retrieve a listing of all history views.
|
|
||||||
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getSessionHistory(): Promise<any> {
|
|
||||||
const urlEndpoint = '/status/sessions/history/all';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get Transcode Sessions
|
|
||||||
* @description Get Transcode Sessions
|
|
||||||
|
|
||||||
* @returns {Promise<Response<GetTranscodeSessionsResponse>>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getTranscodeSessions(): Promise<Response<GetTranscodeSessionsResponse>> {
|
|
||||||
const urlEndpoint = '/transcode/sessions';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Stop a Transcode Session
|
|
||||||
* @description Stop a Transcode Session
|
|
||||||
|
|
||||||
* @param sessionKey the Key of the transcode session to stop
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async stopTranscodeSession(sessionKey: string): Promise<any> {
|
|
||||||
if (sessionKey === undefined) {
|
|
||||||
throw new Error('The following parameter is required: sessionKey, cannot be empty or blank');
|
|
||||||
}
|
|
||||||
let urlEndpoint = '/transcode/sessions/{sessionKey}';
|
|
||||||
urlEndpoint = urlEndpoint.replace(
|
|
||||||
'{sessionKey}',
|
|
||||||
encodeURIComponent(serializePath('simple', false, sessionKey, undefined)),
|
|
||||||
);
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.delete(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export type { GetTranscodeSessionsResponse } from './models/GetTranscodeSessionsResponse';
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
export interface GetTranscodeSessionsResponse {
|
|
||||||
MediaContainer?: MediaContainer;
|
|
||||||
}
|
|
||||||
interface MediaContainer {
|
|
||||||
size?: number;
|
|
||||||
TranscodeSession?: {
|
|
||||||
key?: string;
|
|
||||||
throttled?: boolean;
|
|
||||||
complete?: boolean;
|
|
||||||
progress?: number;
|
|
||||||
size?: number;
|
|
||||||
speed?: number;
|
|
||||||
error?: boolean;
|
|
||||||
duration?: number;
|
|
||||||
context?: string;
|
|
||||||
sourceVideoCodec?: string;
|
|
||||||
sourceAudioCodec?: string;
|
|
||||||
videoDecision?: string;
|
|
||||||
audioDecision?: string;
|
|
||||||
protocol?: string;
|
|
||||||
container?: string;
|
|
||||||
videoCodec?: string;
|
|
||||||
audioCodec?: string;
|
|
||||||
audioChannels?: number;
|
|
||||||
transcodeHwRequested?: boolean;
|
|
||||||
timeStamp?: number;
|
|
||||||
maxOffsetAvailable?: number;
|
|
||||||
minOffsetAvailable?: number;
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
import BaseService from '../../BaseService';
|
|
||||||
|
|
||||||
import Response from '../../http/Response';
|
|
||||||
|
|
||||||
import { Download } from './models/Download';
|
|
||||||
import { Tonight } from './models/Tonight';
|
|
||||||
import { Skip } from './models/Skip';
|
|
||||||
|
|
||||||
import { serializeQuery } from '../../http/QuerySerializer';
|
|
||||||
|
|
||||||
export class UpdaterService extends BaseService {
|
|
||||||
/**
|
|
||||||
* @summary Querying status of updates
|
|
||||||
* @description Querying status of updates
|
|
||||||
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async getUpdateStatus(): Promise<any> {
|
|
||||||
const urlEndpoint = '/updater/status';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}`;
|
|
||||||
const response: any = await this.httpClient.get(
|
|
||||||
finalUrl,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Checking for updates
|
|
||||||
* @description Checking for updates
|
|
||||||
|
|
||||||
* @param optionalParams - Optional parameters
|
|
||||||
* @param optionalParams.download - Indicate that you want to start download any updates found.
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async checkForUpdates(optionalParams: { download?: Download } = {}): Promise<any> {
|
|
||||||
const { download } = optionalParams;
|
|
||||||
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
if (download) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'download', download));
|
|
||||||
}
|
|
||||||
const urlEndpoint = '/updater/check';
|
|
||||||
const urlParams = queryParams.length > 0 ? `?${encodeURI(queryParams.join('&'))}` : '';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}${urlParams}`;
|
|
||||||
const response: any = await this.httpClient.put(
|
|
||||||
finalUrl,
|
|
||||||
{ download },
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Apply Updates
|
|
||||||
* @description Note that these two parameters are effectively mutually exclusive. The `tonight` parameter takes precedence and `skip` will be ignored if `tonight` is also passed
|
|
||||||
|
|
||||||
|
|
||||||
* @param optionalParams - Optional parameters
|
|
||||||
* @param optionalParams.tonight - Indicate that you want the update to run during the next Butler execution. Omitting this or setting it to false indicates that the update should install
|
|
||||||
* @param optionalParams.skip - Indicate that the latest version should be marked as skipped. The <Release> entry for this version will have the `state` set to `skipped`.
|
|
||||||
* @returns {Promise<any>} - The promise with the result
|
|
||||||
*/
|
|
||||||
async applyUpdates(optionalParams: { tonight?: Tonight; skip?: Skip } = {}): Promise<any> {
|
|
||||||
const { tonight, skip } = optionalParams;
|
|
||||||
|
|
||||||
const queryParams: string[] = [];
|
|
||||||
if (tonight) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'tonight', tonight));
|
|
||||||
}
|
|
||||||
if (skip) {
|
|
||||||
queryParams.push(serializeQuery('form', true, 'skip', skip));
|
|
||||||
}
|
|
||||||
const urlEndpoint = '/updater/apply';
|
|
||||||
const urlParams = queryParams.length > 0 ? `?${encodeURI(queryParams.join('&'))}` : '';
|
|
||||||
const finalUrl = `${this.baseUrl + urlEndpoint}${urlParams}`;
|
|
||||||
const response: any = await this.httpClient.put(
|
|
||||||
finalUrl,
|
|
||||||
{ tonight, skip },
|
|
||||||
{
|
|
||||||
...this.getAuthorizationHeader(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const responseModel = {
|
|
||||||
data: response.data,
|
|
||||||
headers: response.headers,
|
|
||||||
};
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
export type { Download } from './models/Download';
|
|
||||||
export type { Skip } from './models/Skip';
|
|
||||||
export type { Tonight } from './models/Tonight';
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export type Download = 0 | 1;
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user