@redseat/api 0.3.12 → 0.4.0

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.
@@ -1,4 +1,4 @@
1
- import { ILibrary, IFile, IEpisode, ISerie, IMovie, IPerson, ITag, IBackup, IWatched, IUnwatched, IRsRequestProcessing, VideoConvertRequest } from './interfaces.js';
1
+ import { ILibrary, IFile, IEpisode, ISerie, IMovie, IBook, IPerson, ITag, IBackup, IWatched, IUnwatched, IRsRequestProcessing, VideoConvertRequest, type ItemWithRelations } 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 {
@@ -12,6 +12,18 @@ export interface SSEConnectionOptions {
12
12
  initialReconnectDelay?: number;
13
13
  /** Maximum reconnect delay in ms (default: 30000) */
14
14
  maxReconnectDelay?: number;
15
+ /** Reconnect when tab becomes visible after being hidden for a while (default: true) */
16
+ reconnectOnPageVisible?: boolean;
17
+ /** Minimum hidden time before reconnecting on visible, in ms (default: 30000) */
18
+ reconnectVisibleAfterMs?: number;
19
+ /** Reconnect when browser comes back online (default: true) */
20
+ reconnectOnOnline?: boolean;
21
+ /** Reconnect on window focus when disconnected/error (default: true) */
22
+ reconnectOnFocus?: boolean;
23
+ /** Retry reconnection on auth (401) errors (default: true) */
24
+ reconnectOnAuthError?: boolean;
25
+ /** Maximum auth-error reconnect attempts before giving up (default: 5) */
26
+ maxAuthReconnectAttempts?: number;
15
27
  }
16
28
  export interface SSEConnectionError {
17
29
  type: 'network' | 'auth' | 'server' | 'parse';
@@ -69,21 +81,28 @@ export interface SSEEpisodesEvent {
69
81
  library: string;
70
82
  episodes: {
71
83
  action: ElementAction;
72
- episode: IEpisode;
84
+ episode: ItemWithRelations<IEpisode>;
73
85
  }[];
74
86
  }
75
87
  export interface SSESeriesEvent {
76
88
  library: string;
77
89
  series: {
78
90
  action: ElementAction;
79
- serie: ISerie;
91
+ serie: ItemWithRelations<ISerie>;
80
92
  }[];
81
93
  }
82
94
  export interface SSEMoviesEvent {
83
95
  library: string;
84
96
  movies: {
85
97
  action: ElementAction;
86
- movie: IMovie;
98
+ movie: ItemWithRelations<IMovie>;
99
+ }[];
100
+ }
101
+ export interface SSEBooksEvent {
102
+ library: string;
103
+ books: {
104
+ action: ElementAction;
105
+ book: ItemWithRelations<IBook>;
87
106
  }[];
88
107
  }
89
108
  export interface SSEPeopleEvent {
@@ -175,6 +194,7 @@ export interface SSEEventMap {
175
194
  'episodes': SSEEpisodesEvent;
176
195
  'series': SSESeriesEvent;
177
196
  'movies': SSEMoviesEvent;
197
+ 'books': SSEBooksEvent;
178
198
  'people': SSEPeopleEvent;
179
199
  'tags': SSETagsEvent;
180
200
  'backups': SSEBackupsEvent;
package/libraries.md CHANGED
@@ -678,6 +678,40 @@ const nonSpecialEpisodes = await libraryApi.getEpisodes({
678
678
  });
679
679
  ````
680
680
 
681
+ ### `getSerieBooks(serieId: string): Promise<IBook[]>`
682
+
683
+ Retrieves all books attached to a series.
684
+
685
+ **Parameters:**
686
+
687
+ - `serieId`: The ID of the series
688
+
689
+ **Returns:** Promise resolving to an array of `IBook` objects
690
+
691
+ **Example:**
692
+
693
+ ```typescript
694
+ const serieBooks = await libraryApi.getSerieBooks('serie-id');
695
+ console.log(serieBooks.length);
696
+ ```
697
+
698
+ ### `getBookMedias(bookId: string): Promise<IFile[]>`
699
+
700
+ Retrieves all media files attached to a book.
701
+
702
+ **Parameters:**
703
+
704
+ - `bookId`: The ID of the book
705
+
706
+ **Returns:** Promise resolving to an array of `IFile` objects
707
+
708
+ **Example:**
709
+
710
+ ```typescript
711
+ const medias = await libraryApi.getBookMedias('book-id');
712
+ console.log(medias.map((media) => media.name));
713
+ ```
714
+
681
715
  ### `createSerie(serie: Partial<ISerie>): Promise<ISerie>`
682
716
 
683
717
  Creates a new series.
@@ -879,7 +913,7 @@ Removes an alternative name from a series.
879
913
  await libraryApi.serieRemoveAlt('serie-id', 'alternative-name');
880
914
  ```
881
915
 
882
- ### `searchSeries(name: string): Promise<ISerie[]>`
916
+ ### `searchSeries(name: string): Promise<SerieSearchResult[]>`
883
917
 
884
918
  Searches for series by name.
885
919
 
@@ -887,12 +921,43 @@ Searches for series by name.
887
921
 
888
922
  - `name`: Search query
889
923
 
890
- **Returns:** Promise resolving to an array of matching `ISerie` objects
924
+ **Returns:** Promise resolving to an array of `SerieSearchResult` items (`metadata.serie` + optional `relations.extImages`, `relations.peopleDetails`, `relations.tagsDetails`, `relations.people`, `relations.tags`)
891
925
 
892
926
  **Example:**
893
927
 
894
928
  ```typescript
895
929
  const results = await libraryApi.searchSeries('Breaking');
930
+ const serie = results[0]?.metadata?.serie;
931
+ const images = results[0]?.relations?.extImages;
932
+ ```
933
+
934
+ ### `searchSeriesStream(name: string, callbacks: SearchStreamCallbacks<SerieSearchStreamResult>): () => void`
935
+
936
+ Starts a series search stream and emits grouped incremental results.
937
+
938
+ **Parameters:**
939
+
940
+ - `name`: Search query
941
+ - `callbacks`: Stream callbacks (`onResults`, `onFinished`, `onError`)
942
+
943
+ Each streamed item uses `SerieSearchStreamResult` shape:
944
+ - `metadata.serie` contains the serie payload
945
+ - `relations.extImages` contains external images (replaces old top-level `images`)
946
+ - `relations.peopleDetails`, `relations.tagsDetails`, `relations.people`, `relations.tags` are optional relation fields
947
+
948
+ **Returns:** Cleanup function that closes the stream and removes listeners
949
+
950
+ **Example:**
951
+
952
+ ```typescript
953
+ const stop = libraryApi.searchSeriesStream('Breaking', {
954
+ onResults: (groups) => console.log(groups),
955
+ onFinished: () => console.log('done'),
956
+ onError: (error) => console.error(error)
957
+ });
958
+
959
+ // Later
960
+ stop();
896
961
  ```
897
962
 
898
963
  ### `setEpisodeWatched(serieId: string, season: number, number: number, date: number): Promise<void>`
@@ -1175,7 +1240,7 @@ Sets the view progress for a movie. Progress is stored in the global history sys
1175
1240
  await libraryApi.setMovieProgress('movie-id', 2700000);
1176
1241
  ```
1177
1242
 
1178
- ### `searchMovies(name: string): Promise<IMovie[]>`
1243
+ ### `searchMovies(name: string): Promise<MovieSearchResult[]>`
1179
1244
 
1180
1245
  Searches for movies by name.
1181
1246
 
@@ -1183,12 +1248,86 @@ Searches for movies by name.
1183
1248
 
1184
1249
  - `name`: Search query
1185
1250
 
1186
- **Returns:** Promise resolving to an array of matching `IMovie` objects
1251
+ **Returns:** Promise resolving to an array of `MovieSearchResult` items (`metadata.movie` + optional `relations.extImages`, `relations.peopleDetails`, `relations.tagsDetails`, `relations.people`, `relations.tags`)
1187
1252
 
1188
1253
  **Example:**
1189
1254
 
1190
1255
  ```typescript
1191
1256
  const results = await libraryApi.searchMovies('Matrix');
1257
+ const movie = results[0]?.metadata?.movie;
1258
+ const images = results[0]?.relations?.extImages;
1259
+ ```
1260
+
1261
+ ### `searchMoviesStream(name: string, callbacks: SearchStreamCallbacks<MovieSearchStreamResult>): () => void`
1262
+
1263
+ Starts a movie search stream and emits grouped incremental results.
1264
+
1265
+ **Parameters:**
1266
+
1267
+ - `name`: Search query
1268
+ - `callbacks`: Stream callbacks (`onResults`, `onFinished`, `onError`)
1269
+
1270
+ Each streamed item uses `MovieSearchStreamResult` shape:
1271
+ - `metadata.movie` contains the movie payload
1272
+ - `relations.extImages` contains external images (replaces old top-level `images`)
1273
+ - `relations.peopleDetails`, `relations.tagsDetails`, `relations.people`, `relations.tags` are optional relation fields
1274
+
1275
+ **Returns:** Cleanup function that closes the stream and removes listeners
1276
+
1277
+ **Example:**
1278
+
1279
+ ```typescript
1280
+ const stop = libraryApi.searchMoviesStream('Matrix', {
1281
+ onResults: (groups) => console.log(groups)
1282
+ });
1283
+
1284
+ // Later
1285
+ stop();
1286
+ ```
1287
+
1288
+ ### `searchBooks(name: string): Promise<BookSearchResult[]>`
1289
+
1290
+ Searches for books by name.
1291
+
1292
+ **Parameters:**
1293
+
1294
+ - `name`: Search query
1295
+
1296
+ **Returns:** Promise resolving to an array of `BookSearchResult` items (`metadata.book` + optional `relations.extImages`, `relations.peopleDetails`, `relations.tagsDetails`, `relations.people`, `relations.tags`)
1297
+
1298
+ **Example:**
1299
+
1300
+ ```typescript
1301
+ const results = await libraryApi.searchBooks('Dune');
1302
+ const book = results[0]?.metadata?.book;
1303
+ const images = results[0]?.relations?.extImages;
1304
+ ```
1305
+
1306
+ ### `searchBooksStream(name: string, callbacks: SearchStreamCallbacks<BookSearchStreamResult>): () => void`
1307
+
1308
+ Starts a book search stream and emits grouped incremental results.
1309
+
1310
+ **Parameters:**
1311
+
1312
+ - `name`: Search query
1313
+ - `callbacks`: Stream callbacks (`onResults`, `onFinished`, `onError`)
1314
+
1315
+ Each streamed item uses `BookSearchStreamResult` shape:
1316
+ - `metadata.book` contains the book payload
1317
+ - `relations.extImages` contains external images (replaces old top-level `images`)
1318
+ - `relations.peopleDetails`, `relations.tagsDetails`, `relations.people`, `relations.tags` are optional relation fields
1319
+
1320
+ **Returns:** Cleanup function that closes the stream and removes listeners
1321
+
1322
+ **Example:**
1323
+
1324
+ ```typescript
1325
+ const stop = libraryApi.searchBooksStream('Dune', {
1326
+ onResults: (groups) => console.log(groups)
1327
+ });
1328
+
1329
+ // Later
1330
+ stop();
1192
1331
  ```
1193
1332
 
1194
1333
  ### `movieRename(movieId: string, newName: string): Promise<IMovie>`
@@ -1407,6 +1546,34 @@ if (library.crypt) {
1407
1546
  }
1408
1547
  ```
1409
1548
 
1549
+ ### `uploadMediaMultipart(options: UploadMediaMultipartOptions): Promise<unknown>`
1550
+
1551
+ Uploads media with raw multipart form data.
1552
+
1553
+ `info` is optional. When provided, it is sent as the `info` multipart field.
1554
+
1555
+ **Parameters:**
1556
+
1557
+ - `options.file`: Required file/blob payload
1558
+ - `options.info?`: Optional `MediaForUpdate` payload serialized into `info`
1559
+ - `options.filename?`: Optional multipart filename override
1560
+ - `options.progressCallback?`: Optional upload progress callback `(loaded, total) => void`
1561
+
1562
+ **Example:**
1563
+
1564
+ ```typescript
1565
+ await libraryApi.uploadMediaMultipart({
1566
+ file,
1567
+ info: {
1568
+ name: 'photo.jpg',
1569
+ mimetype: 'image/jpeg'
1570
+ },
1571
+ progressCallback: (loaded, total) => {
1572
+ console.log(loaded, total);
1573
+ }
1574
+ });
1575
+ ```
1576
+
1410
1577
  ### `uploadGroup(download: RsGroupDownload, options?: { spawn?: boolean }): Promise<IFile[] | { downloading: boolean }>`
1411
1578
 
1412
1579
  Uploads a group of media files from URLs.
@@ -1591,14 +1758,14 @@ Removes a tag from a media file.
1591
1758
  await libraryApi.removeTagFromMedia('media-id', 'tag-id');
1592
1759
  ```
1593
1760
 
1594
- ### `mediaUpdate(mediaId: string, update: any): Promise<IFile[]>`
1761
+ ### `mediaUpdate(mediaId: string, update: MediaForUpdate): Promise<IFile[]>`
1595
1762
 
1596
1763
  Updates a media file's metadata.
1597
1764
 
1598
1765
  **Parameters:**
1599
1766
 
1600
1767
  - `mediaId`: The ID of the media
1601
- - `update`: Update object (see `MediaForUpdate` interface)
1768
+ - `update`: Rust-aligned media update object (`MediaForUpdate`, camelCase fields)
1602
1769
 
1603
1770
  **Returns:** Promise resolving to an array of updated `IFile` objects
1604
1771
 
@@ -1611,13 +1778,13 @@ await libraryApi.mediaUpdate('media-id', {
1611
1778
  });
1612
1779
  ```
1613
1780
 
1614
- ### `mediaUpdateMany(update: any, ids: string[]): Promise<IFile[]>`
1781
+ ### `mediaUpdateMany(update: MediaForUpdate, ids: string[]): Promise<IFile[]>`
1615
1782
 
1616
1783
  Updates multiple media files.
1617
1784
 
1618
1785
  **Parameters:**
1619
1786
 
1620
- - `update`: Update object
1787
+ - `update`: Rust-aligned media update object (`MediaForUpdate`, camelCase fields)
1621
1788
  - `ids`: Array of media IDs to update
1622
1789
 
1623
1790
  **Returns:** Promise resolving to an array of updated `IFile` objects
@@ -1645,7 +1812,7 @@ Updates the watch progress for a media file.
1645
1812
  await libraryApi.mediaUpdateProgress('media-id', 50);
1646
1813
  ```
1647
1814
 
1648
- ### `mediaUpdateChannel(mediaId: string, update: any): Promise<IFile[]>`
1815
+ ### `mediaUpdateChannel(mediaId: string, update: IChannelUpdate): Promise<IFile[]>`
1649
1816
 
1650
1817
  Updates channel information for a media file.
1651
1818
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redseat/api",
3
- "version": "0.3.12",
3
+ "version": "0.4.0",
4
4
  "description": "TypeScript API client library for interacting with Redseat servers",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/server.md CHANGED
@@ -6,6 +6,7 @@ The `ServerApi` class provides server-level operations for managing libraries, s
6
6
 
7
7
  `ServerApi` handles operations that are not specific to a single library, such as:
8
8
  - Listing and creating libraries
9
+ - Updating libraries
9
10
  - Getting current user information
10
11
  - Managing server settings
11
12
  - Listing plugins and credentials
@@ -63,9 +64,15 @@ Creates a new library.
63
64
  **Parameters:**
64
65
  - `library`: Partial library object with required fields:
65
66
  - `name`: Library name (required)
66
- - `type`: Library type - `'photos'`, `'shows'`, `'movies'`, or `'iptv'` (required)
67
+ - `type`: Library type - `'photos'`, `'shows'`, `'movies'`, `'books'`, or `'iptv'` (required)
67
68
  - `source`: Optional source type
68
69
  - `crypt`: Optional boolean to enable encryption
70
+ - `settings`: Optional library settings object:
71
+ - `faceThreshold?: number`
72
+ - `ignoreGroups?: boolean`
73
+ - `preductionModel?: string` prediction model to use for tagging
74
+ - `mapProgress?: Record<string, any>[]` allow to map view progress from a user to another user
75
+ - `dataPath?: string` custom path to store library running data like thumnails, cache, portraits...
69
76
  - `hidden`: Optional boolean to hide library
70
77
 
71
78
  **Returns:** Promise resolving to the created `ILibrary` object with generated `id`
@@ -75,24 +82,41 @@ Creates a new library.
75
82
  const newLibrary = await serverApi.addLibrary({
76
83
  name: 'My Photos',
77
84
  type: 'photos',
78
- crypt: true // Enable encryption
85
+ crypt: true, // Enable encryption
86
+ settings: {
87
+ faceThreshold: 0.7
88
+ }
79
89
  });
80
90
  console.log(`Created library with ID: ${newLibrary.id}`);
81
91
  ```
82
92
 
83
- ### `getSetting(key: string): Promise<string>`
93
+ ### `updateLibrary(libraryId: string, library: ServerLibraryForUpdate): Promise<ILibrary>`
84
94
 
85
- Retrieves a server setting value by key.
95
+ Updates an existing library.
86
96
 
87
97
  **Parameters:**
88
- - `key`: The setting key to retrieve
98
+ - `libraryId`: The library ID to update
99
+ - `library`: Partial library update object. Supported fields:
100
+ - `name?: string`
101
+ - `source?: LibrarySources`
102
+ - `root?: string`
103
+ - `settings?: ServerLibrarySettings`
104
+ - `credentials?: string`
105
+ - `plugin?: string`
106
+
107
+ `type` and `crypt` are not updatable through this endpoint.
89
108
 
90
- **Returns:** Promise resolving to the setting value as a string
109
+ **Returns:** Promise resolving to the updated `ILibrary` object
91
110
 
92
111
  **Example:**
93
112
  ```typescript
94
- const maxUploadSize = await serverApi.getSetting('max_upload_size');
95
- console.log(`Max upload size: ${maxUploadSize}`);
113
+ const updatedLibrary = await serverApi.updateLibrary('library-123', {
114
+ name: 'Renamed Library',
115
+ settings: {
116
+ faceThreshold: 0.8
117
+ }
118
+ });
119
+ console.log(`Updated library: ${updatedLibrary.name}`);
96
120
  ```
97
121
 
98
122
  ### `getPlugins(): Promise<any[]>`
@@ -109,6 +133,29 @@ plugins.forEach(plugin => {
109
133
  });
110
134
  ```
111
135
 
136
+ ### `searchLookupStream(query: string, type: string, callbacks: SearchStreamCallbacks<LookupSearchStreamResult>): () => void`
137
+
138
+ Starts a plugin lookup search stream and emits grouped incremental results.
139
+
140
+ **Parameters:**
141
+ - `query`: Search query text
142
+ - `type`: Lookup type (typically library type)
143
+ - `callbacks`: Stream callbacks (`onResults`, `onFinished`, `onError`)
144
+
145
+ **Returns:** Cleanup function that closes the stream and removes listeners
146
+
147
+ **Example:**
148
+ ```typescript
149
+ const stop = serverApi.searchLookupStream('matrix', 'movies', {
150
+ onResults: (groups) => console.log(groups),
151
+ onFinished: () => console.log('lookup done'),
152
+ onError: (error) => console.error(error)
153
+ });
154
+
155
+ // Later
156
+ stop();
157
+ ```
158
+
112
159
  ### `getCredentials(): Promise<ICredential[]>`
113
160
 
114
161
  Retrieves all available credentials configured on the server.
@@ -509,6 +556,11 @@ const newLibrary = await serverApi.addLibrary({
509
556
  crypt: true
510
557
  });
511
558
 
559
+ // Update the library settings
560
+ const updatedLibrary = await serverApi.updateLibrary(newLibrary.id!, {
561
+ name: 'Encrypted Family Photos'
562
+ });
563
+
512
564
  // Get server settings
513
565
  const maxUpload = await serverApi.getSetting('max_upload_size');
514
566
  console.log(`Max upload size: ${maxUpload}`);
@@ -535,4 +587,3 @@ try {
535
587
  - [RedseatClient Documentation](client.md) - HTTP client used by ServerApi
536
588
  - [LibraryApi Documentation](libraries.md) - Library-specific operations
537
589
  - [README](README.md) - Package overview
538
-