@redseat/api 0.3.7 → 0.3.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.ts CHANGED
@@ -2,7 +2,7 @@ import { Method, AxiosRequestConfig } from 'axios';
2
2
  import { Observable } from 'rxjs';
3
3
  import { IToken } from './auth.js';
4
4
  import { IServer } from './interfaces.js';
5
- import { SSEConnectionState, SSEConnectionOptions, SSEConnectionError, SSELibraryEvent, SSELibraryStatusEvent, SSEMediasEvent, SSEUploadProgressEvent, SSEConvertProgressEvent, SSEEpisodesEvent, SSESeriesEvent, SSEMoviesEvent, SSEPeopleEvent, SSETagsEvent, SSEBackupsEvent, SSEBackupFilesEvent, SSEMediaRatingEvent, SSEMediaProgressEvent, SSEPlayersListEvent, SSEWatchedEvent, SSEUnwatchedEvent } from './sse-types.js';
5
+ import { SSEConnectionState, SSEConnectionOptions, SSEConnectionError, SSELibraryEvent, SSELibraryStatusEvent, SSEMediasEvent, SSEUploadProgressEvent, SSEConvertProgressEvent, SSEEpisodesEvent, SSESeriesEvent, SSEMoviesEvent, SSEPeopleEvent, SSETagsEvent, SSEBackupsEvent, SSEBackupFilesEvent, SSEMediaRatingEvent, SSEMediaProgressEvent, SSEPlayersListEvent, SSEWatchedEvent, SSEUnwatchedEvent, SSERequestProcessingEvent } from './sse-types.js';
6
6
  export interface ClientOptions {
7
7
  server: IServer;
8
8
  getIdToken: () => Promise<string>;
@@ -20,6 +20,8 @@ export declare class RedseatClient {
20
20
  private localServerUrl?;
21
21
  private tokenData?;
22
22
  private tokenRefreshPromise?;
23
+ private localDetectionAbortController?;
24
+ private disposed;
23
25
  private sseAbortController?;
24
26
  private sseReconnectTimeout?;
25
27
  private sseReconnectAttempts;
@@ -47,6 +49,7 @@ export declare class RedseatClient {
47
49
  readonly playersList$: Observable<SSEPlayersListEvent>;
48
50
  readonly watched$: Observable<SSEWatchedEvent>;
49
51
  readonly unwatched$: Observable<SSEUnwatchedEvent>;
52
+ readonly requestProcessing$: Observable<SSERequestProcessingEvent>;
50
53
  /**
51
54
  * Creates a typed observable for a specific SSE event type.
52
55
  * Unwraps the nested data structure from the server (e.g., {uploadProgress: {...}} -> {...})
@@ -102,7 +105,7 @@ export declare class RedseatClient {
102
105
  */
103
106
  disconnectSSE(): void;
104
107
  /**
105
- * Disposes of all SSE resources and completes observables.
108
+ * Disposes of all resources and completes observables.
106
109
  * Call this when the client is no longer needed.
107
110
  */
108
111
  dispose(): void;
package/dist/client.js CHANGED
@@ -17,6 +17,12 @@ export class RedseatClient {
17
17
  'library-status': 'libraryStatus',
18
18
  'backups-files': 'backupsFiles',
19
19
  'players-list': 'Players',
20
+ 'episodes': 'episodes',
21
+ 'series': 'series',
22
+ 'movies': 'movies',
23
+ 'people': 'people',
24
+ 'tags': 'tags',
25
+ 'request_processing': 'requestProcessing',
20
26
  };
21
27
  const wrapperKey = wrapperMap[eventName];
22
28
  return this._sseEvents.pipe(filter((event) => event.event === eventName), map(event => {
@@ -30,6 +36,7 @@ export class RedseatClient {
30
36
  }));
31
37
  }
32
38
  constructor(options) {
39
+ this.disposed = false;
33
40
  this.sseReconnectAttempts = 0;
34
41
  // RxJS subjects for SSE
35
42
  this._sseConnectionState = new BehaviorSubject('disconnected');
@@ -57,6 +64,7 @@ export class RedseatClient {
57
64
  this.playersList$ = this.createEventStream('players-list');
58
65
  this.watched$ = this.createEventStream('watched');
59
66
  this.unwatched$ = this.createEventStream('unwatched');
67
+ this.requestProcessing$ = this.createEventStream('request_processing');
60
68
  this.server = options.server;
61
69
  this.redseatUrl = options.redseatUrl;
62
70
  this.getIdToken = options.getIdToken;
@@ -65,16 +73,19 @@ export class RedseatClient {
65
73
  this.baseUrl = this.getRegularServerUrl();
66
74
  this.axios = axios.create({
67
75
  baseURL: this.baseUrl,
68
- timeout: options.timeout ?? 0
76
+ timeout: options.timeout ?? 30000 // 30 second default
69
77
  });
70
78
  // Detect local URL asynchronously and update axios instance
71
- this.detectLocalUrl().then((url) => {
79
+ this.localDetectionAbortController = new AbortController();
80
+ this.detectLocalUrl(this.localDetectionAbortController.signal).then((url) => {
81
+ if (this.disposed)
82
+ return; // Don't update if disposed
72
83
  if (url !== this.baseUrl) {
73
84
  this.baseUrl = url;
74
85
  this.axios.defaults.baseURL = url;
75
86
  }
76
87
  }).catch(() => {
77
- // If detection fails, use regular URL (already set)
88
+ // If detection fails or aborted, use regular URL (already set)
78
89
  });
79
90
  // Request interceptor: check token expiration and refresh if needed
80
91
  this.axios.interceptors.request.use(async (config) => {
@@ -110,7 +121,7 @@ export class RedseatClient {
110
121
  }
111
122
  return `https://${base}`;
112
123
  }
113
- async detectLocalUrl() {
124
+ async detectLocalUrl(signal) {
114
125
  let localBase = `local.${this.server.url}`;
115
126
  if (this.server.port) {
116
127
  localBase = `${localBase}:${this.server.port}`;
@@ -120,7 +131,8 @@ export class RedseatClient {
120
131
  console.log('trying local server url', localUrl);
121
132
  const response = await axios.get(`${localUrl}/ping`, {
122
133
  timeout: 200,
123
- headers: { "Referrer-Policy": 'origin-when-cross-origin' }
134
+ headers: { "Referrer-Policy": 'origin-when-cross-origin' },
135
+ signal
124
136
  });
125
137
  if (response.status === 200) {
126
138
  console.log('local server detected');
@@ -301,10 +313,13 @@ export class RedseatClient {
301
313
  this._sseConnectionState.next('disconnected');
302
314
  }
303
315
  /**
304
- * Disposes of all SSE resources and completes observables.
316
+ * Disposes of all resources and completes observables.
305
317
  * Call this when the client is no longer needed.
306
318
  */
307
319
  dispose() {
320
+ this.disposed = true;
321
+ this.localDetectionAbortController?.abort();
322
+ this.localDetectionAbortController = undefined;
308
323
  this.disconnectSSE();
309
324
  this._sseConnectionState.complete();
310
325
  this._sseError.complete();
@@ -731,6 +731,8 @@ export interface RsRequest {
731
731
  size?: number;
732
732
  filename?: string;
733
733
  status: RsRequestStatus;
734
+ pluginName?: string;
735
+ pluginId?: string;
734
736
  permanent: boolean;
735
737
  instant?: boolean;
736
738
  jsonBody?: any;
@@ -768,3 +770,89 @@ export interface RsGroupDownload {
768
770
  groupMime?: string;
769
771
  requests: RsRequest[];
770
772
  }
773
+ /**
774
+ * Request processing status from plugin-based download/processing.
775
+ * Tracks progress of downloads, file processing, etc.
776
+ */
777
+ export interface IRsRequestProcessing {
778
+ /** Internal nanoid */
779
+ id: string;
780
+ /** Plugin's processing ID */
781
+ processingId: string;
782
+ /** Plugin handling the request */
783
+ pluginId: string;
784
+ /** Progress 0-100 */
785
+ progress: number;
786
+ /** Status: "pending" | "processing" | "paused" | "finished" | "error" */
787
+ status: string;
788
+ /** Error message if status is "error" */
789
+ error?: string;
790
+ /** UTC timestamp (ms) for estimated completion */
791
+ eta?: number;
792
+ /** Reference to media being processed */
793
+ mediaRef?: string;
794
+ /** The original request */
795
+ originalRequest?: RsRequest;
796
+ /** Last modified timestamp */
797
+ modified: number;
798
+ /** Creation timestamp */
799
+ added: number;
800
+ }
801
+ export declare enum VideoOverlayPosition {
802
+ topLeft = "topLeft",
803
+ topRight = "topRight",
804
+ topCenter = "topCenter",
805
+ bottomLeft = "bottomLeft",
806
+ bottomRight = "bottomRight",
807
+ bottomCenter = "bottomCenter",
808
+ Center = "center"
809
+ }
810
+ export declare enum VideoOverlayType {
811
+ watermark = "watermark",
812
+ file = "file"
813
+ }
814
+ export interface VideoOverlay {
815
+ type: VideoOverlayType;
816
+ path: string;
817
+ position?: VideoOverlayPosition;
818
+ margin?: number;
819
+ ratio: number;
820
+ opacity: number;
821
+ }
822
+ export interface VideoTextOverlay {
823
+ text: string;
824
+ fontColor: string;
825
+ font?: string;
826
+ position: VideoOverlayPosition;
827
+ marginHorizontal?: number;
828
+ marginVertical?: number;
829
+ fontSize: number;
830
+ opacity?: number;
831
+ shadowColor: string;
832
+ shadowOpacity?: number;
833
+ start?: number;
834
+ end?: number;
835
+ }
836
+ export interface VideoConvertInterval {
837
+ start: number;
838
+ duration: number;
839
+ /** Defaults to current input */
840
+ input?: string;
841
+ }
842
+ export interface VideoConvertRequest {
843
+ id: string;
844
+ format: string;
845
+ codec?: string;
846
+ crf?: number;
847
+ noAudio?: boolean;
848
+ width?: string;
849
+ height?: string;
850
+ framerate?: number;
851
+ cropWidth?: number;
852
+ cropHeight?: number;
853
+ aspectRatio?: string;
854
+ aspectRatioAlignment?: 'center' | 'left' | 'right';
855
+ overlay?: VideoOverlay;
856
+ texts?: VideoTextOverlay[];
857
+ intervals?: VideoConvertInterval[];
858
+ }
@@ -88,3 +88,19 @@ export var RsRequestMethod;
88
88
  RsRequestMethod["Delete"] = "delete";
89
89
  RsRequestMethod["Head"] = "head";
90
90
  })(RsRequestMethod || (RsRequestMethod = {}));
91
+ // ========== Video Convert Types ==========
92
+ export var VideoOverlayPosition;
93
+ (function (VideoOverlayPosition) {
94
+ VideoOverlayPosition["topLeft"] = "topLeft";
95
+ VideoOverlayPosition["topRight"] = "topRight";
96
+ VideoOverlayPosition["topCenter"] = "topCenter";
97
+ VideoOverlayPosition["bottomLeft"] = "bottomLeft";
98
+ VideoOverlayPosition["bottomRight"] = "bottomRight";
99
+ VideoOverlayPosition["bottomCenter"] = "bottomCenter";
100
+ VideoOverlayPosition["Center"] = "center";
101
+ })(VideoOverlayPosition || (VideoOverlayPosition = {}));
102
+ export var VideoOverlayType;
103
+ (function (VideoOverlayType) {
104
+ VideoOverlayType["watermark"] = "watermark";
105
+ VideoOverlayType["file"] = "file";
106
+ })(VideoOverlayType || (VideoOverlayType = {}));
package/dist/library.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Observable } from 'rxjs';
2
- import { IFile, ITag, IPerson, ISerie, IMovie, MediaRequest, IEpisode, ExternalImage, IBackupFile, ILibrary, SerieInMedia, DeletedQuery, RsDeleted, MovieSort, RsSort, SqlOrder, RsRequest, DetectedFaceResult, UnassignFaceResponse, RsGroupDownload, IViewProgress, IWatched } from './interfaces.js';
3
- import { SSEMediasEvent, SSEUploadProgressEvent, SSEConvertProgressEvent, SSEEpisodesEvent, SSESeriesEvent, SSEMoviesEvent, SSEPeopleEvent, SSETagsEvent, SSELibraryStatusEvent, SSEMediaRatingEvent, SSEMediaProgressEvent } from './sse-types.js';
2
+ import type { AxiosResponse } from 'axios';
3
+ import { IFile, ITag, IPerson, ISerie, IMovie, MediaRequest, IEpisode, ExternalImage, IBackupFile, ILibrary, SerieInMedia, DeletedQuery, RsDeleted, MovieSort, RsSort, SqlOrder, RsRequest, DetectedFaceResult, UnassignFaceResponse, RsGroupDownload, IViewProgress, IWatched, IRsRequestProcessing } from './interfaces.js';
4
+ import { SSEMediasEvent, SSEUploadProgressEvent, SSEConvertProgressEvent, SSEEpisodesEvent, SSESeriesEvent, SSEMoviesEvent, SSEPeopleEvent, SSETagsEvent, SSELibraryStatusEvent, SSEMediaRatingEvent, SSEMediaProgressEvent, SSERequestProcessingEvent } from './sse-types.js';
4
5
  import { EncryptFileOptions, EncryptedFile } from './encryption.js';
5
6
  export interface MediaForUpdate {
6
7
  name?: string;
@@ -87,6 +88,7 @@ export interface LibraryHttpClient {
87
88
  readonly libraryStatus$?: Observable<SSELibraryStatusEvent>;
88
89
  readonly mediaRating$?: Observable<SSEMediaRatingEvent>;
89
90
  readonly mediaProgress$?: Observable<SSEMediaProgressEvent>;
91
+ readonly requestProcessing$?: Observable<SSERequestProcessingEvent>;
90
92
  }
91
93
  export declare class LibraryApi {
92
94
  private client;
@@ -106,6 +108,7 @@ export declare class LibraryApi {
106
108
  readonly libraryStatus$: Observable<SSELibraryStatusEvent>;
107
109
  readonly mediaRating$: Observable<SSEMediaRatingEvent>;
108
110
  readonly mediaProgress$: Observable<SSEMediaProgressEvent>;
111
+ readonly requestProcessing$: Observable<SSERequestProcessingEvent>;
109
112
  constructor(client: LibraryHttpClient, libraryId: string, library: ILibrary);
110
113
  /**
111
114
  * Creates a library-filtered stream from a client stream.
@@ -253,6 +256,43 @@ export declare class LibraryApi {
253
256
  checkRequestInstant(request: RsRequest): Promise<{
254
257
  instant: boolean;
255
258
  }>;
259
+ /**
260
+ * Process an unprocessed RsRequest and return the processed result.
261
+ * Takes a raw request and runs it through the server's plugin processing pipeline.
262
+ * @param request - The unprocessed request to process
263
+ * @returns The processed request with updated status and metadata
264
+ */
265
+ processRequest(request: RsRequest): Promise<RsRequest>;
266
+ /**
267
+ * Process a request and return the raw HTTP stream response.
268
+ * Use this to stream content directly without processing the full response.
269
+ * @param request - The request to process and stream
270
+ * @returns Raw axios response with stream data - use response.data for the stream
271
+ */
272
+ processRequestStream(request: RsRequest): Promise<AxiosResponse>;
273
+ /**
274
+ * Add a request to the processing queue.
275
+ * @param request - The request to add for processing
276
+ * @param mediaRef - Optional media reference to associate with the processing
277
+ * @returns The created request processing entry
278
+ */
279
+ addRequest(request: RsRequest, mediaRef?: string): Promise<IRsRequestProcessing>;
280
+ /**
281
+ * List all active request processings for this library.
282
+ * @returns Array of request processing entries
283
+ */
284
+ listRequestProcessing(): Promise<IRsRequestProcessing[]>;
285
+ /**
286
+ * Pause a request processing task.
287
+ * @param processingId - The ID of the processing task to pause
288
+ * @returns The updated request processing entry with status "paused"
289
+ */
290
+ pauseRequestProcessing(processingId: string): Promise<IRsRequestProcessing>;
291
+ /**
292
+ * Delete/remove a request processing task.
293
+ * @param processingId - The ID of the processing task to delete
294
+ */
295
+ deleteRequestProcessing(processingId: string): Promise<void>;
256
296
  /**
257
297
  * Get a share token for a request URL.
258
298
  * The token can be used to stream/download the resource without authentication.
package/dist/library.js CHANGED
@@ -19,6 +19,7 @@ export class LibraryApi {
19
19
  this.libraryStatus$ = this.createLibraryFilteredStream(client.libraryStatus$);
20
20
  this.mediaRating$ = this.createLibraryFilteredStream(client.mediaRating$);
21
21
  this.mediaProgress$ = this.createLibraryFilteredStream(client.mediaProgress$);
22
+ this.requestProcessing$ = this.createLibraryFilteredStream(client.requestProcessing$);
22
23
  }
23
24
  /**
24
25
  * Creates a library-filtered stream from a client stream.
@@ -525,6 +526,59 @@ export class LibraryApi {
525
526
  const res = await this.client.post(this.getUrl('/plugins/requests/check-instant'), request);
526
527
  return res.data;
527
528
  }
529
+ /**
530
+ * Process an unprocessed RsRequest and return the processed result.
531
+ * Takes a raw request and runs it through the server's plugin processing pipeline.
532
+ * @param request - The unprocessed request to process
533
+ * @returns The processed request with updated status and metadata
534
+ */
535
+ async processRequest(request) {
536
+ const res = await this.client.post(this.getUrl('/plugins/requests/process'), request);
537
+ return res.data;
538
+ }
539
+ /**
540
+ * Process a request and return the raw HTTP stream response.
541
+ * Use this to stream content directly without processing the full response.
542
+ * @param request - The request to process and stream
543
+ * @returns Raw axios response with stream data - use response.data for the stream
544
+ */
545
+ async processRequestStream(request) {
546
+ return this.client.post(this.getUrl('/plugins/requests/process/stream'), request, { responseType: 'stream' });
547
+ }
548
+ /**
549
+ * Add a request to the processing queue.
550
+ * @param request - The request to add for processing
551
+ * @param mediaRef - Optional media reference to associate with the processing
552
+ * @returns The created request processing entry
553
+ */
554
+ async addRequest(request, mediaRef) {
555
+ const res = await this.client.post(this.getUrl('/plugins/requests/add'), { request, mediaRef });
556
+ return res.data;
557
+ }
558
+ /**
559
+ * List all active request processings for this library.
560
+ * @returns Array of request processing entries
561
+ */
562
+ async listRequestProcessing() {
563
+ const res = await this.client.get(this.getUrl('/plugins/requests/processing'));
564
+ return res.data;
565
+ }
566
+ /**
567
+ * Pause a request processing task.
568
+ * @param processingId - The ID of the processing task to pause
569
+ * @returns The updated request processing entry with status "paused"
570
+ */
571
+ async pauseRequestProcessing(processingId) {
572
+ const res = await this.client.post(this.getUrl(`/plugins/requests/processing/${processingId}/pause`));
573
+ return res.data;
574
+ }
575
+ /**
576
+ * Delete/remove a request processing task.
577
+ * @param processingId - The ID of the processing task to delete
578
+ */
579
+ async deleteRequestProcessing(processingId) {
580
+ await this.client.delete(this.getUrl(`/plugins/requests/processing/${processingId}`));
581
+ }
528
582
  /**
529
583
  * Get a share token for a request URL.
530
584
  * The token can be used to stream/download the resource without authentication.
@@ -1,4 +1,4 @@
1
- import { ILibrary, IFile, IEpisode, ISerie, IMovie, IPerson, ITag, IBackup, IWatched, IUnwatched } from './interfaces.js';
1
+ import { ILibrary, IFile, IEpisode, ISerie, IMovie, IPerson, ITag, IBackup, IWatched, IUnwatched, IRsRequestProcessing, VideoConvertRequest } from './interfaces.js';
2
2
  export type ElementAction = 'Added' | 'Updated' | 'Deleted';
3
3
  export type SSEConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error';
4
4
  export interface SSEConnectionOptions {
@@ -50,12 +50,20 @@ export interface SSEUploadProgressEvent {
50
50
  progress: RsProgress;
51
51
  remainingSecondes?: number;
52
52
  }
53
+ export type RsVideoTranscodeStatus = 'pending' | 'processing' | 'completed' | 'failed' | 'canceled';
54
+ export interface ConvertProgress {
55
+ id: string;
56
+ filename: string;
57
+ convertedId: string | null;
58
+ done: boolean;
59
+ percent: number;
60
+ status: RsVideoTranscodeStatus;
61
+ estimatedRemainingSeconds: number | null;
62
+ request: VideoConvertRequest | null;
63
+ }
53
64
  export interface SSEConvertProgressEvent {
54
65
  library: string;
55
- mediaId: string;
56
- progress: number;
57
- status: string;
58
- message?: string;
66
+ progress: ConvertProgress;
59
67
  }
60
68
  export interface SSEEpisodesEvent {
61
69
  library: string;
@@ -146,6 +154,18 @@ export type SSEWatchedEvent = IWatched;
146
154
  * This is a user-scoped event - not library-scoped.
147
155
  */
148
156
  export type SSEUnwatchedEvent = IUnwatched;
157
+ /**
158
+ * SSE event for request processing status updates.
159
+ * Tracks plugin-based request processing (downloads, file processing, etc.).
160
+ * This is a library-scoped event.
161
+ */
162
+ export interface SSERequestProcessingEvent {
163
+ library: string;
164
+ processings: {
165
+ action: ElementAction;
166
+ processing: IRsRequestProcessing;
167
+ }[];
168
+ }
149
169
  export interface SSEEventMap {
150
170
  'library': SSELibraryEvent;
151
171
  'library-status': SSELibraryStatusEvent;
@@ -164,6 +184,7 @@ export interface SSEEventMap {
164
184
  'players-list': SSEPlayersListEvent;
165
185
  'watched': SSEWatchedEvent;
166
186
  'unwatched': SSEUnwatchedEvent;
187
+ 'request_processing': SSERequestProcessingEvent;
167
188
  }
168
189
  export type SSEEventName = keyof SSEEventMap;
169
190
  export interface SSEEvent<T extends SSEEventName = SSEEventName> {
package/libraries.md CHANGED
@@ -1969,6 +1969,158 @@ await libraryApi.clusterFaces('person-id');
1969
1969
 
1970
1970
  ---
1971
1971
 
1972
+ ## Request Processing
1973
+
1974
+ ### `processRequest(request: RsRequest): Promise<RsRequest>`
1975
+
1976
+ Process an unprocessed RsRequest and return the processed result.
1977
+ Takes a raw request and runs it through the server's plugin processing pipeline.
1978
+
1979
+ **Parameters:**
1980
+
1981
+ - `request`: The unprocessed request to process
1982
+
1983
+ **Returns:** Promise resolving to the processed request with updated status and metadata
1984
+
1985
+ **Example:**
1986
+
1987
+ ```typescript
1988
+ import { RsRequestStatus, RsRequestMethod } from '@redseat/api';
1989
+
1990
+ const unprocessedRequest: RsRequest = {
1991
+ url: 'https://example.com/video.mp4',
1992
+ method: RsRequestMethod.Get,
1993
+ status: RsRequestStatus.Unprocessed,
1994
+ permanent: false,
1995
+ ignoreOriginDuplicate: false
1996
+ };
1997
+ const processed = await libraryApi.processRequest(unprocessedRequest);
1998
+ console.log(processed.status); // RsRequestStatus.Processed
1999
+ ```
2000
+
2001
+ ### `processRequestStream(request: RsRequest): Promise<AxiosResponse>`
2002
+
2003
+ Process a request and return the raw HTTP stream response for direct streaming.
2004
+
2005
+ **Parameters:**
2006
+
2007
+ - `request`: The request to process and stream
2008
+
2009
+ **Returns:** Raw axios response - use `response.data` for the stream
2010
+
2011
+ **Example:**
2012
+
2013
+ ```typescript
2014
+ const request: RsRequest = {
2015
+ url: 'https://example.com/video.mp4',
2016
+ method: RsRequestMethod.Get,
2017
+ status: RsRequestStatus.Processed,
2018
+ permanent: false,
2019
+ ignoreOriginDuplicate: false
2020
+ };
2021
+ const response = await libraryApi.processRequestStream(request);
2022
+ // response.data is the stream that can be piped directly
2023
+ ```
2024
+
2025
+ ### `addRequest(request: RsRequest, mediaRef?: string): Promise<IRsRequestProcessing>`
2026
+
2027
+ Add a request to the processing queue for background download/processing.
2028
+
2029
+ **Parameters:**
2030
+
2031
+ - `request`: The request to add for processing
2032
+ - `mediaRef`: Optional media reference to associate with the processing
2033
+
2034
+ **Returns:** Promise resolving to the created `IRsRequestProcessing` entry
2035
+
2036
+ **Example:**
2037
+
2038
+ ```typescript
2039
+ import { RsRequestStatus, RsRequestMethod } from '@redseat/api';
2040
+
2041
+ const request: RsRequest = {
2042
+ url: 'https://example.com/large-video.mp4',
2043
+ method: RsRequestMethod.Get,
2044
+ status: RsRequestStatus.Unprocessed,
2045
+ permanent: false,
2046
+ ignoreOriginDuplicate: false
2047
+ };
2048
+
2049
+ // Add to processing queue
2050
+ const processing = await libraryApi.addRequest(request);
2051
+ console.log(processing.id); // Processing ID
2052
+ console.log(processing.status); // "pending" | "processing" | "paused" | "finished" | "error"
2053
+ console.log(processing.progress); // 0-100
2054
+
2055
+ // Associate with existing media
2056
+ const processingWithMedia = await libraryApi.addRequest(request, 'media-id');
2057
+ ```
2058
+
2059
+ ### `listRequestProcessing(): Promise<IRsRequestProcessing[]>`
2060
+
2061
+ List all active request processings for this library.
2062
+
2063
+ **Returns:** Promise resolving to an array of `IRsRequestProcessing` entries
2064
+
2065
+ **Example:**
2066
+
2067
+ ```typescript
2068
+ const processings = await libraryApi.listRequestProcessing();
2069
+ for (const p of processings) {
2070
+ console.log(`${p.id}: ${p.status} (${p.progress}%)`);
2071
+ if (p.error) {
2072
+ console.log(` Error: ${p.error}`);
2073
+ }
2074
+ if (p.mediaRef) {
2075
+ console.log(` Media: ${p.mediaRef}`);
2076
+ }
2077
+ }
2078
+ ```
2079
+
2080
+ ### `pauseRequestProcessing(processingId: string): Promise<IRsRequestProcessing>`
2081
+
2082
+ Pause a request processing task. This stops the download/processing temporarily.
2083
+
2084
+ **Parameters:**
2085
+
2086
+ - `processingId`: The ID of the processing task to pause
2087
+
2088
+ **Returns:** Promise resolving to the updated `IRsRequestProcessing` entry with status "paused"
2089
+
2090
+ **Example:**
2091
+
2092
+ ```typescript
2093
+ const processings = await libraryApi.listRequestProcessing();
2094
+ const activeProcessing = processings.find(p => p.status === 'processing');
2095
+
2096
+ if (activeProcessing) {
2097
+ const paused = await libraryApi.pauseRequestProcessing(activeProcessing.id);
2098
+ console.log(`Paused: ${paused.id}, status: ${paused.status}`); // status: "paused"
2099
+ }
2100
+ ```
2101
+
2102
+ ### `deleteRequestProcessing(processingId: string): Promise<void>`
2103
+
2104
+ Delete/remove a request processing task from the queue. This cancels and removes the processing entry.
2105
+
2106
+ **Parameters:**
2107
+
2108
+ - `processingId`: The ID of the processing task to delete
2109
+
2110
+ **Example:**
2111
+
2112
+ ```typescript
2113
+ const processings = await libraryApi.listRequestProcessing();
2114
+ const processingToRemove = processings.find(p => p.status === 'error');
2115
+
2116
+ if (processingToRemove) {
2117
+ await libraryApi.deleteRequestProcessing(processingToRemove.id);
2118
+ console.log(`Removed processing: ${processingToRemove.id}`);
2119
+ }
2120
+ ```
2121
+
2122
+ ---
2123
+
1972
2124
  ## Encryption
1973
2125
 
1974
2126
  These methods are convenience wrappers around the encryption module. For detailed encryption documentation, see [encryption.md](encryption.md).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redseat/api",
3
- "version": "0.3.7",
3
+ "version": "0.3.12",
4
4
  "description": "TypeScript API client library for interacting with Redseat servers",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",