@redseat/api 0.3.11 → 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
@@ -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;
@@ -103,7 +105,7 @@ export declare class RedseatClient {
103
105
  */
104
106
  disconnectSSE(): void;
105
107
  /**
106
- * Disposes of all SSE resources and completes observables.
108
+ * Disposes of all resources and completes observables.
107
109
  * Call this when the client is no longer needed.
108
110
  */
109
111
  dispose(): void;
package/dist/client.js CHANGED
@@ -36,6 +36,7 @@ export class RedseatClient {
36
36
  }));
37
37
  }
38
38
  constructor(options) {
39
+ this.disposed = false;
39
40
  this.sseReconnectAttempts = 0;
40
41
  // RxJS subjects for SSE
41
42
  this._sseConnectionState = new BehaviorSubject('disconnected');
@@ -72,16 +73,19 @@ export class RedseatClient {
72
73
  this.baseUrl = this.getRegularServerUrl();
73
74
  this.axios = axios.create({
74
75
  baseURL: this.baseUrl,
75
- timeout: options.timeout ?? 0
76
+ timeout: options.timeout ?? 30000 // 30 second default
76
77
  });
77
78
  // Detect local URL asynchronously and update axios instance
78
- 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
79
83
  if (url !== this.baseUrl) {
80
84
  this.baseUrl = url;
81
85
  this.axios.defaults.baseURL = url;
82
86
  }
83
87
  }).catch(() => {
84
- // If detection fails, use regular URL (already set)
88
+ // If detection fails or aborted, use regular URL (already set)
85
89
  });
86
90
  // Request interceptor: check token expiration and refresh if needed
87
91
  this.axios.interceptors.request.use(async (config) => {
@@ -117,7 +121,7 @@ export class RedseatClient {
117
121
  }
118
122
  return `https://${base}`;
119
123
  }
120
- async detectLocalUrl() {
124
+ async detectLocalUrl(signal) {
121
125
  let localBase = `local.${this.server.url}`;
122
126
  if (this.server.port) {
123
127
  localBase = `${localBase}:${this.server.port}`;
@@ -127,7 +131,8 @@ export class RedseatClient {
127
131
  console.log('trying local server url', localUrl);
128
132
  const response = await axios.get(`${localUrl}/ping`, {
129
133
  timeout: 200,
130
- headers: { "Referrer-Policy": 'origin-when-cross-origin' }
134
+ headers: { "Referrer-Policy": 'origin-when-cross-origin' },
135
+ signal
131
136
  });
132
137
  if (response.status === 200) {
133
138
  console.log('local server detected');
@@ -308,10 +313,13 @@ export class RedseatClient {
308
313
  this._sseConnectionState.next('disconnected');
309
314
  }
310
315
  /**
311
- * Disposes of all SSE resources and completes observables.
316
+ * Disposes of all resources and completes observables.
312
317
  * Call this when the client is no longer needed.
313
318
  */
314
319
  dispose() {
320
+ this.disposed = true;
321
+ this.localDetectionAbortController?.abort();
322
+ this.localDetectionAbortController = undefined;
315
323
  this.disconnectSSE();
316
324
  this._sseConnectionState.complete();
317
325
  this._sseError.complete();
@@ -798,3 +798,61 @@ export interface IRsRequestProcessing {
798
798
  /** Creation timestamp */
799
799
  added: number;
800
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 = {}));
@@ -1,4 +1,4 @@
1
- import { ILibrary, IFile, IEpisode, ISerie, IMovie, IPerson, ITag, IBackup, IWatched, IUnwatched, IRsRequestProcessing } 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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redseat/api",
3
- "version": "0.3.11",
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",