mirror of
https://github.com/aleksilassila/reiverr.git
synced 2026-04-25 10:15:11 +02:00
chore: setup npm workspaces and plugin types as package
This commit is contained in:
210
backend/plugins/reiverr-plugin/src/device-profile.ts
Normal file
210
backend/plugins/reiverr-plugin/src/device-profile.ts
Normal file
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* A MediaBrowser.Model.Dlna.DeviceProfile represents a set of metadata which determines which content a certain device is able to play.
|
||||
* <br />
|
||||
* Specifically, it defines the supported <see cref="P:MediaBrowser.Model.Dlna.DeviceProfile.ContainerProfiles">containers</see> and
|
||||
* <see cref="P:MediaBrowser.Model.Dlna.DeviceProfile.CodecProfiles">codecs</see> (video and/or audio, including codec profiles and levels)
|
||||
* the device is able to direct play (without transcoding or remuxing),
|
||||
* as well as which <see cref="P:MediaBrowser.Model.Dlna.DeviceProfile.TranscodingProfiles">containers/codecs to transcode to</see> in case it isn't.
|
||||
*/
|
||||
export interface DeviceProfile {
|
||||
/** Gets or sets the name of this device profile. User profiles must have a unique name. */
|
||||
Name?: string | null;
|
||||
/**
|
||||
* Gets or sets the unique internal identifier.
|
||||
* @format uuid
|
||||
*/
|
||||
Id?: string | null;
|
||||
/**
|
||||
* Gets or sets the maximum allowed bitrate for all streamed content.
|
||||
* @format int32
|
||||
*/
|
||||
MaxStreamingBitrate?: number | null;
|
||||
/**
|
||||
* Gets or sets the maximum allowed bitrate for statically streamed content (= direct played files).
|
||||
* @format int32
|
||||
*/
|
||||
MaxStaticBitrate?: number | null;
|
||||
/**
|
||||
* Gets or sets the maximum allowed bitrate for transcoded music streams.
|
||||
* @format int32
|
||||
*/
|
||||
MusicStreamingTranscodingBitrate?: number | null;
|
||||
/**
|
||||
* Gets or sets the maximum allowed bitrate for statically streamed (= direct played) music files.
|
||||
* @format int32
|
||||
*/
|
||||
MaxStaticMusicBitrate?: number | null;
|
||||
/** Gets or sets the direct play profiles. */
|
||||
DirectPlayProfiles?: DirectPlayProfile[];
|
||||
/** Gets or sets the transcoding profiles. */
|
||||
TranscodingProfiles?: TranscodingProfile[];
|
||||
/** Gets or sets the container profiles. Failing to meet these optional conditions causes transcoding to occur. */
|
||||
ContainerProfiles?: ContainerProfile[];
|
||||
/** Gets or sets the codec profiles. */
|
||||
CodecProfiles?: CodecProfile[];
|
||||
/** Gets or sets the subtitle profiles. */
|
||||
SubtitleProfiles?: SubtitleProfile[];
|
||||
}
|
||||
|
||||
/** Defines the MediaBrowser.Model.Dlna.DirectPlayProfile. */
|
||||
export interface DirectPlayProfile {
|
||||
/** Gets or sets the container. */
|
||||
Container?: string;
|
||||
/** Gets or sets the audio codec. */
|
||||
AudioCodec?: string | null;
|
||||
/** Gets or sets the video codec. */
|
||||
VideoCodec?: string | null;
|
||||
/** Gets or sets the Dlna profile type. */
|
||||
Type?: 'Audio' | 'Video' | 'Photo' | 'Subtitle' | 'Lyric';
|
||||
}
|
||||
|
||||
/** A class for transcoding profile information. */
|
||||
export interface TranscodingProfile {
|
||||
/** Gets or sets the container. */
|
||||
Container?: string;
|
||||
/** Gets or sets the DLNA profile type. */
|
||||
Type?: 'Audio' | 'Video' | 'Photo' | 'Subtitle' | 'Lyric';
|
||||
/** Gets or sets the video codec. */
|
||||
VideoCodec?: string;
|
||||
/** Gets or sets the audio codec. */
|
||||
AudioCodec?: string;
|
||||
/**
|
||||
* Media streaming protocol.
|
||||
* Lowercase for backwards compatibility.
|
||||
*/
|
||||
Protocol?: 'http' | 'hls';
|
||||
/**
|
||||
* Gets or sets a value indicating whether the content length should be estimated.
|
||||
* @default false
|
||||
*/
|
||||
EstimateContentLength?: boolean;
|
||||
/**
|
||||
* Gets or sets a value indicating whether M2TS mode is enabled.
|
||||
* @default false
|
||||
*/
|
||||
EnableMpegtsM2TsMode?: boolean;
|
||||
/**
|
||||
* Gets or sets the transcoding seek info mode.
|
||||
* @default "Auto"
|
||||
*/
|
||||
TranscodeSeekInfo?: 'Auto' | 'Bytes';
|
||||
/**
|
||||
* Gets or sets a value indicating whether timestamps should be copied.
|
||||
* @default false
|
||||
*/
|
||||
CopyTimestamps?: boolean;
|
||||
/**
|
||||
* Gets or sets the encoding context.
|
||||
* @default "Streaming"
|
||||
*/
|
||||
Context?: 'Streaming' | 'Static';
|
||||
/**
|
||||
* Gets or sets a value indicating whether subtitles are allowed in the manifest.
|
||||
* @default false
|
||||
*/
|
||||
EnableSubtitlesInManifest?: boolean;
|
||||
/** Gets or sets the maximum audio channels. */
|
||||
MaxAudioChannels?: string | null;
|
||||
/**
|
||||
* Gets or sets the minimum amount of segments.
|
||||
* @format int32
|
||||
* @default 0
|
||||
*/
|
||||
MinSegments?: number;
|
||||
/**
|
||||
* Gets or sets the segment length.
|
||||
* @format int32
|
||||
* @default 0
|
||||
*/
|
||||
SegmentLength?: number;
|
||||
/**
|
||||
* Gets or sets a value indicating whether breaking the video stream on non-keyframes is supported.
|
||||
* @default false
|
||||
*/
|
||||
BreakOnNonKeyFrames?: boolean;
|
||||
/** Gets or sets the profile conditions. */
|
||||
Conditions?: ProfileCondition[];
|
||||
/**
|
||||
* Gets or sets a value indicating whether variable bitrate encoding is supported.
|
||||
* @default true
|
||||
*/
|
||||
EnableAudioVbrEncoding?: boolean;
|
||||
}
|
||||
|
||||
export interface ProfileCondition {
|
||||
Condition?:
|
||||
| 'Equals'
|
||||
| 'NotEquals'
|
||||
| 'LessThanEqual'
|
||||
| 'GreaterThanEqual'
|
||||
| 'EqualsAny';
|
||||
Property?:
|
||||
| 'AudioChannels'
|
||||
| 'AudioBitrate'
|
||||
| 'AudioProfile'
|
||||
| 'Width'
|
||||
| 'Height'
|
||||
| 'Has64BitOffsets'
|
||||
| 'PacketLength'
|
||||
| 'VideoBitDepth'
|
||||
| 'VideoBitrate'
|
||||
| 'VideoFramerate'
|
||||
| 'VideoLevel'
|
||||
| 'VideoProfile'
|
||||
| 'VideoTimestamp'
|
||||
| 'IsAnamorphic'
|
||||
| 'RefFrames'
|
||||
| 'NumAudioStreams'
|
||||
| 'NumVideoStreams'
|
||||
| 'IsSecondaryAudio'
|
||||
| 'VideoCodecTag'
|
||||
| 'IsAvc'
|
||||
| 'IsInterlaced'
|
||||
| 'AudioSampleRate'
|
||||
| 'AudioBitDepth'
|
||||
| 'VideoRangeType';
|
||||
Value?: string | null;
|
||||
IsRequired?: boolean;
|
||||
}
|
||||
|
||||
/** Defines the MediaBrowser.Model.Dlna.ContainerProfile. */
|
||||
export interface ContainerProfile {
|
||||
/** Gets or sets the MediaBrowser.Model.Dlna.DlnaProfileType which this container must meet. */
|
||||
Type?: 'Audio' | 'Video' | 'Photo' | 'Subtitle' | 'Lyric';
|
||||
/** Gets or sets the list of MediaBrowser.Model.Dlna.ProfileCondition which this container will be applied to. */
|
||||
Conditions?: ProfileCondition[];
|
||||
/** Gets or sets the container(s) which this container must meet. */
|
||||
Container?: string | null;
|
||||
/** Gets or sets the sub container(s) which this container must meet. */
|
||||
SubContainer?: string | null;
|
||||
}
|
||||
|
||||
/** Defines the MediaBrowser.Model.Dlna.CodecProfile. */
|
||||
export interface CodecProfile {
|
||||
/** Gets or sets the MediaBrowser.Model.Dlna.CodecType which this container must meet. */
|
||||
Type?: 'Video' | 'VideoAudio' | 'Audio';
|
||||
/** Gets or sets the list of MediaBrowser.Model.Dlna.ProfileCondition which this profile must meet. */
|
||||
Conditions?: ProfileCondition[];
|
||||
/** Gets or sets the list of MediaBrowser.Model.Dlna.ProfileCondition to apply if this profile is met. */
|
||||
ApplyConditions?: ProfileCondition[];
|
||||
/** Gets or sets the codec(s) that this profile applies to. */
|
||||
Codec?: string | null;
|
||||
/** Gets or sets the container(s) which this profile will be applied to. */
|
||||
Container?: string | null;
|
||||
/** Gets or sets the sub-container(s) which this profile will be applied to. */
|
||||
SubContainer?: string | null;
|
||||
}
|
||||
|
||||
/** A class for subtitle profile information. */
|
||||
export interface SubtitleProfile {
|
||||
/** Gets or sets the format. */
|
||||
Format?: string | null;
|
||||
/** Gets or sets the delivery method. */
|
||||
Method?: 'Encode' | 'Embed' | 'External' | 'Hls' | 'Drop';
|
||||
/** Gets or sets the DIDL mode. */
|
||||
DidlMode?: string | null;
|
||||
/** Gets or sets the language. */
|
||||
Language?: string | null;
|
||||
/** Gets or sets the container. */
|
||||
Container?: string | null;
|
||||
}
|
||||
3
backend/plugins/reiverr-plugin/src/index.ts
Normal file
3
backend/plugins/reiverr-plugin/src/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from './types';
|
||||
export * from './plugin';
|
||||
export * from './device-profile';
|
||||
83
backend/plugins/reiverr-plugin/src/plugin.ts
Normal file
83
backend/plugins/reiverr-plugin/src/plugin.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import {
|
||||
EpisodeMetadata,
|
||||
IndexItem,
|
||||
MovieMetadata,
|
||||
PaginatedResponse,
|
||||
PaginationParams,
|
||||
PlaybackConfig,
|
||||
SourceProviderSettingsTemplate,
|
||||
UserContext,
|
||||
ValidationResponse,
|
||||
Stream,
|
||||
StreamCandidate,
|
||||
} from './types';
|
||||
|
||||
export class PluginProvider {
|
||||
static getPlugins(): SourceProvider[] {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export class SettingsManager {
|
||||
getSettingsTemplate: () => SourceProviderSettingsTemplate = () => ({});
|
||||
|
||||
validateSettings: (
|
||||
settings: Record<string, any>,
|
||||
) => Promise<ValidationResponse> = async () => ({
|
||||
isValid: true,
|
||||
errors: {},
|
||||
replace: {},
|
||||
});
|
||||
}
|
||||
|
||||
export abstract class SourceProvider {
|
||||
abstract name: string;
|
||||
|
||||
settingsManager: SettingsManager = new SettingsManager();
|
||||
|
||||
getMovieCatalogue?: (
|
||||
context: UserContext,
|
||||
pagination: PaginationParams,
|
||||
) => Promise<PaginatedResponse<IndexItem>>;
|
||||
|
||||
getEpisodeCatalogue?: (
|
||||
context: UserContext,
|
||||
pagination: PaginationParams,
|
||||
) => Promise<PaginatedResponse<IndexItem>>;
|
||||
|
||||
getMovieStreams?: (
|
||||
tmdbId: string,
|
||||
metadata: MovieMetadata,
|
||||
context: UserContext,
|
||||
config?: PlaybackConfig,
|
||||
) => Promise<{ candidates: StreamCandidate[] }>;
|
||||
|
||||
getEpisodeStreams?: (
|
||||
tmdbId: string,
|
||||
metadata: EpisodeMetadata,
|
||||
context: UserContext,
|
||||
config?: PlaybackConfig,
|
||||
) => Promise<{ candidates: StreamCandidate[] }>;
|
||||
|
||||
getMovieStream?: (
|
||||
tmdbId: string,
|
||||
metadata: MovieMetadata,
|
||||
key: string,
|
||||
context: UserContext,
|
||||
config?: PlaybackConfig,
|
||||
) => Promise<Stream | undefined>;
|
||||
|
||||
getEpisodeStream?: (
|
||||
tmdbId: string,
|
||||
metadata: EpisodeMetadata,
|
||||
key: string,
|
||||
context: UserContext,
|
||||
config?: PlaybackConfig,
|
||||
) => Promise<Stream | undefined>;
|
||||
|
||||
proxyHandler?: (
|
||||
req: any,
|
||||
res: any,
|
||||
options: { context: UserContext; uri: string; targetUrl?: string },
|
||||
) => Promise<any>;
|
||||
}
|
||||
125
backend/plugins/reiverr-plugin/src/types.ts
Normal file
125
backend/plugins/reiverr-plugin/src/types.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
import { DeviceProfile } from './device-profile';
|
||||
|
||||
export enum SourceProviderError {
|
||||
StreamNotFound = 'StreamNotFound',
|
||||
}
|
||||
|
||||
export type SourceProviderSettingsLink = {
|
||||
type: 'link';
|
||||
url: string;
|
||||
label: string;
|
||||
};
|
||||
|
||||
export type SourceProviderSettingsInput = {
|
||||
type: 'string' | 'number' | 'boolean' | 'password';
|
||||
label: string;
|
||||
placeholder: string;
|
||||
};
|
||||
|
||||
export type SourceProviderSettingsTemplate = Record<
|
||||
string,
|
||||
SourceProviderSettingsLink | SourceProviderSettingsInput
|
||||
>;
|
||||
|
||||
export type UserContext = {
|
||||
userId: string;
|
||||
token: string;
|
||||
settings: SourceProviderSettings;
|
||||
};
|
||||
|
||||
export type SourceProviderSettings = Record<string, any>;
|
||||
|
||||
export type ValidationResponse = {
|
||||
isValid: boolean;
|
||||
errors: Record<string, string>;
|
||||
replace: Record<string, any>;
|
||||
};
|
||||
|
||||
export type AudioStream = {
|
||||
index: number;
|
||||
label: string;
|
||||
codec: string | undefined;
|
||||
bitrate: number | undefined;
|
||||
};
|
||||
|
||||
export type Quality = {
|
||||
index: number;
|
||||
bitrate: number;
|
||||
label: string;
|
||||
codec: string | undefined;
|
||||
original: boolean;
|
||||
};
|
||||
|
||||
export type Subtitles = {
|
||||
index: number;
|
||||
uri: string;
|
||||
label: string;
|
||||
codec: string | undefined;
|
||||
};
|
||||
|
||||
export type StreamProperty = {
|
||||
label: string;
|
||||
value: string | number;
|
||||
formatted: string | undefined;
|
||||
};
|
||||
|
||||
export type StreamCandidate = {
|
||||
key: string;
|
||||
title: string;
|
||||
properties: StreamProperty[];
|
||||
};
|
||||
|
||||
export type Stream = StreamCandidate & {
|
||||
uri: string;
|
||||
directPlay: boolean;
|
||||
progress: number;
|
||||
duration: number;
|
||||
audioStreams: AudioStream[];
|
||||
audioStreamIndex: number;
|
||||
qualities: Quality[];
|
||||
qualityIndex: number;
|
||||
subtitles: Subtitles[];
|
||||
};
|
||||
|
||||
export type PlaybackConfig = {
|
||||
bitrate: number | undefined;
|
||||
audioStreamIndex: number | undefined;
|
||||
progress: number | undefined;
|
||||
deviceProfile: DeviceProfile | undefined;
|
||||
defaultLanguage: string | undefined;
|
||||
};
|
||||
|
||||
export type IndexItem = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
export type PaginatedResponse<T> = {
|
||||
total: number;
|
||||
page: number;
|
||||
itemsPerPage: number;
|
||||
items: T[];
|
||||
};
|
||||
|
||||
export type PaginationParams = {
|
||||
page: number;
|
||||
itemsPerPage: number;
|
||||
};
|
||||
|
||||
interface Metadata {
|
||||
tmdbId?: string;
|
||||
imdbId?: string;
|
||||
year?: number;
|
||||
}
|
||||
|
||||
export interface MovieMetadata extends Metadata {
|
||||
title: string;
|
||||
runtime?: number;
|
||||
}
|
||||
|
||||
export interface EpisodeMetadata extends Metadata {
|
||||
series: string;
|
||||
season: number;
|
||||
episode: number;
|
||||
episodeRuntime?: number;
|
||||
seasonEpisodes?: number;
|
||||
}
|
||||
Reference in New Issue
Block a user