@redseat/api 0.3.5 → 0.3.7
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/CLAUDE.md +1 -1
- package/README.md +137 -132
- package/{AGENTS.md → agents.md} +275 -275
- package/client.md +670 -670
- package/dist/client.d.ts +3 -1
- package/dist/client.js +2 -0
- package/dist/interfaces.d.ts +187 -0
- package/dist/library.d.ts +7 -1
- package/dist/library.js +22 -0
- package/dist/server.d.ts +7 -1
- package/dist/server.js +40 -0
- package/dist/sse-types.d.ts +15 -1
- package/encryption.md +533 -533
- package/firebase.md +602 -602
- package/libraries.md +145 -4
- package/package.json +49 -49
- package/server.md +538 -277
- package/test.md +291 -291
package/server.md
CHANGED
|
@@ -1,277 +1,538 @@
|
|
|
1
|
-
# ServerApi
|
|
2
|
-
|
|
3
|
-
The `ServerApi` class provides server-level operations for managing libraries, settings, plugins, and credentials.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
`ServerApi` handles operations that are not specific to a single library, such as:
|
|
8
|
-
- Listing and creating libraries
|
|
9
|
-
- Getting current user information
|
|
10
|
-
- Managing server settings
|
|
11
|
-
- Listing plugins and credentials
|
|
12
|
-
- Adding credentials to libraries
|
|
13
|
-
|
|
14
|
-
## Constructor
|
|
15
|
-
|
|
16
|
-
```typescript
|
|
17
|
-
new ServerApi(client: RedseatClient)
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
**Parameters:**
|
|
21
|
-
- `client`: An initialized `RedseatClient` instance
|
|
22
|
-
|
|
23
|
-
**Example:**
|
|
24
|
-
```typescript
|
|
25
|
-
import { RedseatClient, ServerApi } from '@redseat/api';
|
|
26
|
-
|
|
27
|
-
const client = new RedseatClient({ /* ... */ });
|
|
28
|
-
const serverApi = new ServerApi(client);
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Methods
|
|
32
|
-
|
|
33
|
-
### `getLibraries(): Promise<ILibrary[]>`
|
|
34
|
-
|
|
35
|
-
Retrieves all libraries available to the current user.
|
|
36
|
-
|
|
37
|
-
**Returns:** Promise resolving to an array of `ILibrary` objects
|
|
38
|
-
|
|
39
|
-
**Example:**
|
|
40
|
-
```typescript
|
|
41
|
-
const libraries = await serverApi.getLibraries();
|
|
42
|
-
libraries.forEach(library => {
|
|
43
|
-
console.log(`Library: ${library.name} (${library.type})`);
|
|
44
|
-
});
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
### `getMe(): Promise<any>`
|
|
48
|
-
|
|
49
|
-
Gets information about the current authenticated user.
|
|
50
|
-
|
|
51
|
-
**Returns:** Promise resolving to user information object
|
|
52
|
-
|
|
53
|
-
**Example:**
|
|
54
|
-
```typescript
|
|
55
|
-
const user = await serverApi.getMe();
|
|
56
|
-
console.log(`Logged in as: ${user.name}`);
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
### `addLibrary(library: Partial<ILibrary>): Promise<ILibrary>`
|
|
60
|
-
|
|
61
|
-
Creates a new library.
|
|
62
|
-
|
|
63
|
-
**Parameters:**
|
|
64
|
-
- `library`: Partial library object with required fields:
|
|
65
|
-
- `name`: Library name (required)
|
|
66
|
-
- `type`: Library type - `'photos'`, `'shows'`, `'movies'`, or `'iptv'` (required)
|
|
67
|
-
- `source`: Optional source type
|
|
68
|
-
- `crypt`: Optional boolean to enable encryption
|
|
69
|
-
- `hidden`: Optional boolean to hide library
|
|
70
|
-
|
|
71
|
-
**Returns:** Promise resolving to the created `ILibrary` object with generated `id`
|
|
72
|
-
|
|
73
|
-
**Example:**
|
|
74
|
-
```typescript
|
|
75
|
-
const newLibrary = await serverApi.addLibrary({
|
|
76
|
-
name: 'My Photos',
|
|
77
|
-
type: 'photos',
|
|
78
|
-
crypt: true // Enable encryption
|
|
79
|
-
});
|
|
80
|
-
console.log(`Created library with ID: ${newLibrary.id}`);
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### `getSetting(key: string): Promise<string>`
|
|
84
|
-
|
|
85
|
-
Retrieves a server setting value by key.
|
|
86
|
-
|
|
87
|
-
**Parameters:**
|
|
88
|
-
- `key`: The setting key to retrieve
|
|
89
|
-
|
|
90
|
-
**Returns:** Promise resolving to the setting value as a string
|
|
91
|
-
|
|
92
|
-
**Example:**
|
|
93
|
-
```typescript
|
|
94
|
-
const maxUploadSize = await serverApi.getSetting('max_upload_size');
|
|
95
|
-
console.log(`Max upload size: ${maxUploadSize}`);
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
### `getPlugins(): Promise<any[]>`
|
|
99
|
-
|
|
100
|
-
Retrieves all available plugins on the server.
|
|
101
|
-
|
|
102
|
-
**Returns:** Promise resolving to an array of plugin objects
|
|
103
|
-
|
|
104
|
-
**Example:**
|
|
105
|
-
```typescript
|
|
106
|
-
const plugins = await serverApi.getPlugins();
|
|
107
|
-
plugins.forEach(plugin => {
|
|
108
|
-
console.log(`Plugin: ${plugin.name} - ${plugin.description}`);
|
|
109
|
-
});
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### `getCredentials(): Promise<ICredential[]>`
|
|
113
|
-
|
|
114
|
-
Retrieves all available credentials configured on the server.
|
|
115
|
-
|
|
116
|
-
**Returns:** Promise resolving to an array of `ICredential` objects
|
|
117
|
-
|
|
118
|
-
**Example:**
|
|
119
|
-
```typescript
|
|
120
|
-
const credentials = await serverApi.getCredentials();
|
|
121
|
-
credentials.forEach(cred => {
|
|
122
|
-
console.log(`Credential: ${cred.name} (${cred.type.type})`);
|
|
123
|
-
});
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
### `saveCredential(credential: ICredential): Promise<ICredential>`
|
|
127
|
-
|
|
128
|
-
Creates a new credential on the server.
|
|
129
|
-
|
|
130
|
-
**Parameters:**
|
|
131
|
-
- `credential`: Credential object with required fields:
|
|
132
|
-
- `name`: Credential name (required)
|
|
133
|
-
- `source`: Plugin/source name (required)
|
|
134
|
-
- `type`: Authentication type object (required)
|
|
135
|
-
- `settings`: Settings record for plugin params (required)
|
|
136
|
-
- `login`: Optional login/username
|
|
137
|
-
- `password`: Optional password/token
|
|
138
|
-
|
|
139
|
-
**Returns:** Promise resolving to the created `ICredential` object with generated `id`
|
|
140
|
-
|
|
141
|
-
**Example:**
|
|
142
|
-
```typescript
|
|
143
|
-
const newCredential = await serverApi.saveCredential({
|
|
144
|
-
name: 'My API Key',
|
|
145
|
-
source: 'jackett',
|
|
146
|
-
type: { type: PluginAuthType.Token },
|
|
147
|
-
settings: { url: 'http://localhost:9117' },
|
|
148
|
-
password: 'my-api-key'
|
|
149
|
-
});
|
|
150
|
-
console.log(`Created credential with ID: ${newCredential.id}`);
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
### `updateCredential(credential: ICredential): Promise<ICredential>`
|
|
154
|
-
|
|
155
|
-
Updates an existing credential.
|
|
156
|
-
|
|
157
|
-
**Parameters:**
|
|
158
|
-
- `credential`: Credential object with `id` and fields to update
|
|
159
|
-
|
|
160
|
-
**Returns:** Promise resolving to the updated `ICredential` object
|
|
161
|
-
|
|
162
|
-
**Example:**
|
|
163
|
-
```typescript
|
|
164
|
-
const updated = await serverApi.updateCredential({
|
|
165
|
-
id: 'cred-123',
|
|
166
|
-
name: 'Updated Name',
|
|
167
|
-
source: 'jackett',
|
|
168
|
-
type: { type: PluginAuthType.Token },
|
|
169
|
-
settings: { url: 'http://localhost:9117' },
|
|
170
|
-
password: 'new-api-key'
|
|
171
|
-
});
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
### `deleteCredential(id: string): Promise<void>`
|
|
175
|
-
|
|
176
|
-
Deletes a credential by ID.
|
|
177
|
-
|
|
178
|
-
**Parameters:**
|
|
179
|
-
- `id`: The credential ID to delete
|
|
180
|
-
|
|
181
|
-
**Returns:** Promise resolving when deletion is complete
|
|
182
|
-
|
|
183
|
-
**Example:**
|
|
184
|
-
```typescript
|
|
185
|
-
await serverApi.deleteCredential('cred-123');
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### `saveOAuthCredentials(pluginId: string, params: Record<string, string>): Promise<void>`
|
|
189
|
-
|
|
190
|
-
Exchanges OAuth tokens and saves credentials for a plugin.
|
|
191
|
-
|
|
192
|
-
**Parameters:**
|
|
193
|
-
- `pluginId`: The plugin ID to save credentials for
|
|
194
|
-
- `params`: OAuth parameters including tokens and name
|
|
195
|
-
|
|
196
|
-
**Returns:** Promise resolving when credentials are saved
|
|
197
|
-
|
|
198
|
-
**Example:**
|
|
199
|
-
```typescript
|
|
200
|
-
await serverApi.saveOAuthCredentials('trakt', {
|
|
201
|
-
name: 'My Trakt Account',
|
|
202
|
-
code: 'oauth-code',
|
|
203
|
-
access_token: 'token123'
|
|
204
|
-
});
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
### `addLibraryCredential(credential: any): Promise<ILibrary>`
|
|
208
|
-
|
|
209
|
-
Adds a credential to a library. This is used to configure external service access for libraries.
|
|
210
|
-
|
|
211
|
-
**Parameters:**
|
|
212
|
-
- `credential`: Credential configuration object (structure depends on credential type)
|
|
213
|
-
|
|
214
|
-
**Returns:** Promise resolving to the updated `ILibrary` object
|
|
215
|
-
|
|
216
|
-
**Example:**
|
|
217
|
-
```typescript
|
|
218
|
-
const library = await serverApi.addLibraryCredential({
|
|
219
|
-
libraryId: 'library-123',
|
|
220
|
-
credentialId: 'credential-456',
|
|
221
|
-
// Additional credential-specific configuration
|
|
222
|
-
});
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
##
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
-
|
|
275
|
-
-
|
|
276
|
-
-
|
|
277
|
-
|
|
1
|
+
# ServerApi
|
|
2
|
+
|
|
3
|
+
The `ServerApi` class provides server-level operations for managing libraries, settings, plugins, and credentials.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`ServerApi` handles operations that are not specific to a single library, such as:
|
|
8
|
+
- Listing and creating libraries
|
|
9
|
+
- Getting current user information
|
|
10
|
+
- Managing server settings
|
|
11
|
+
- Listing plugins and credentials
|
|
12
|
+
- Adding credentials to libraries
|
|
13
|
+
|
|
14
|
+
## Constructor
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
new ServerApi(client: RedseatClient)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Parameters:**
|
|
21
|
+
- `client`: An initialized `RedseatClient` instance
|
|
22
|
+
|
|
23
|
+
**Example:**
|
|
24
|
+
```typescript
|
|
25
|
+
import { RedseatClient, ServerApi } from '@redseat/api';
|
|
26
|
+
|
|
27
|
+
const client = new RedseatClient({ /* ... */ });
|
|
28
|
+
const serverApi = new ServerApi(client);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Methods
|
|
32
|
+
|
|
33
|
+
### `getLibraries(): Promise<ILibrary[]>`
|
|
34
|
+
|
|
35
|
+
Retrieves all libraries available to the current user.
|
|
36
|
+
|
|
37
|
+
**Returns:** Promise resolving to an array of `ILibrary` objects
|
|
38
|
+
|
|
39
|
+
**Example:**
|
|
40
|
+
```typescript
|
|
41
|
+
const libraries = await serverApi.getLibraries();
|
|
42
|
+
libraries.forEach(library => {
|
|
43
|
+
console.log(`Library: ${library.name} (${library.type})`);
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### `getMe(): Promise<any>`
|
|
48
|
+
|
|
49
|
+
Gets information about the current authenticated user.
|
|
50
|
+
|
|
51
|
+
**Returns:** Promise resolving to user information object
|
|
52
|
+
|
|
53
|
+
**Example:**
|
|
54
|
+
```typescript
|
|
55
|
+
const user = await serverApi.getMe();
|
|
56
|
+
console.log(`Logged in as: ${user.name}`);
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### `addLibrary(library: Partial<ILibrary>): Promise<ILibrary>`
|
|
60
|
+
|
|
61
|
+
Creates a new library.
|
|
62
|
+
|
|
63
|
+
**Parameters:**
|
|
64
|
+
- `library`: Partial library object with required fields:
|
|
65
|
+
- `name`: Library name (required)
|
|
66
|
+
- `type`: Library type - `'photos'`, `'shows'`, `'movies'`, or `'iptv'` (required)
|
|
67
|
+
- `source`: Optional source type
|
|
68
|
+
- `crypt`: Optional boolean to enable encryption
|
|
69
|
+
- `hidden`: Optional boolean to hide library
|
|
70
|
+
|
|
71
|
+
**Returns:** Promise resolving to the created `ILibrary` object with generated `id`
|
|
72
|
+
|
|
73
|
+
**Example:**
|
|
74
|
+
```typescript
|
|
75
|
+
const newLibrary = await serverApi.addLibrary({
|
|
76
|
+
name: 'My Photos',
|
|
77
|
+
type: 'photos',
|
|
78
|
+
crypt: true // Enable encryption
|
|
79
|
+
});
|
|
80
|
+
console.log(`Created library with ID: ${newLibrary.id}`);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### `getSetting(key: string): Promise<string>`
|
|
84
|
+
|
|
85
|
+
Retrieves a server setting value by key.
|
|
86
|
+
|
|
87
|
+
**Parameters:**
|
|
88
|
+
- `key`: The setting key to retrieve
|
|
89
|
+
|
|
90
|
+
**Returns:** Promise resolving to the setting value as a string
|
|
91
|
+
|
|
92
|
+
**Example:**
|
|
93
|
+
```typescript
|
|
94
|
+
const maxUploadSize = await serverApi.getSetting('max_upload_size');
|
|
95
|
+
console.log(`Max upload size: ${maxUploadSize}`);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### `getPlugins(): Promise<any[]>`
|
|
99
|
+
|
|
100
|
+
Retrieves all available plugins on the server.
|
|
101
|
+
|
|
102
|
+
**Returns:** Promise resolving to an array of plugin objects
|
|
103
|
+
|
|
104
|
+
**Example:**
|
|
105
|
+
```typescript
|
|
106
|
+
const plugins = await serverApi.getPlugins();
|
|
107
|
+
plugins.forEach(plugin => {
|
|
108
|
+
console.log(`Plugin: ${plugin.name} - ${plugin.description}`);
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### `getCredentials(): Promise<ICredential[]>`
|
|
113
|
+
|
|
114
|
+
Retrieves all available credentials configured on the server.
|
|
115
|
+
|
|
116
|
+
**Returns:** Promise resolving to an array of `ICredential` objects
|
|
117
|
+
|
|
118
|
+
**Example:**
|
|
119
|
+
```typescript
|
|
120
|
+
const credentials = await serverApi.getCredentials();
|
|
121
|
+
credentials.forEach(cred => {
|
|
122
|
+
console.log(`Credential: ${cred.name} (${cred.type.type})`);
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### `saveCredential(credential: ICredential): Promise<ICredential>`
|
|
127
|
+
|
|
128
|
+
Creates a new credential on the server.
|
|
129
|
+
|
|
130
|
+
**Parameters:**
|
|
131
|
+
- `credential`: Credential object with required fields:
|
|
132
|
+
- `name`: Credential name (required)
|
|
133
|
+
- `source`: Plugin/source name (required)
|
|
134
|
+
- `type`: Authentication type object (required)
|
|
135
|
+
- `settings`: Settings record for plugin params (required)
|
|
136
|
+
- `login`: Optional login/username
|
|
137
|
+
- `password`: Optional password/token
|
|
138
|
+
|
|
139
|
+
**Returns:** Promise resolving to the created `ICredential` object with generated `id`
|
|
140
|
+
|
|
141
|
+
**Example:**
|
|
142
|
+
```typescript
|
|
143
|
+
const newCredential = await serverApi.saveCredential({
|
|
144
|
+
name: 'My API Key',
|
|
145
|
+
source: 'jackett',
|
|
146
|
+
type: { type: PluginAuthType.Token },
|
|
147
|
+
settings: { url: 'http://localhost:9117' },
|
|
148
|
+
password: 'my-api-key'
|
|
149
|
+
});
|
|
150
|
+
console.log(`Created credential with ID: ${newCredential.id}`);
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### `updateCredential(credential: ICredential): Promise<ICredential>`
|
|
154
|
+
|
|
155
|
+
Updates an existing credential.
|
|
156
|
+
|
|
157
|
+
**Parameters:**
|
|
158
|
+
- `credential`: Credential object with `id` and fields to update
|
|
159
|
+
|
|
160
|
+
**Returns:** Promise resolving to the updated `ICredential` object
|
|
161
|
+
|
|
162
|
+
**Example:**
|
|
163
|
+
```typescript
|
|
164
|
+
const updated = await serverApi.updateCredential({
|
|
165
|
+
id: 'cred-123',
|
|
166
|
+
name: 'Updated Name',
|
|
167
|
+
source: 'jackett',
|
|
168
|
+
type: { type: PluginAuthType.Token },
|
|
169
|
+
settings: { url: 'http://localhost:9117' },
|
|
170
|
+
password: 'new-api-key'
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### `deleteCredential(id: string): Promise<void>`
|
|
175
|
+
|
|
176
|
+
Deletes a credential by ID.
|
|
177
|
+
|
|
178
|
+
**Parameters:**
|
|
179
|
+
- `id`: The credential ID to delete
|
|
180
|
+
|
|
181
|
+
**Returns:** Promise resolving when deletion is complete
|
|
182
|
+
|
|
183
|
+
**Example:**
|
|
184
|
+
```typescript
|
|
185
|
+
await serverApi.deleteCredential('cred-123');
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### `saveOAuthCredentials(pluginId: string, params: Record<string, string>): Promise<void>`
|
|
189
|
+
|
|
190
|
+
Exchanges OAuth tokens and saves credentials for a plugin.
|
|
191
|
+
|
|
192
|
+
**Parameters:**
|
|
193
|
+
- `pluginId`: The plugin ID to save credentials for
|
|
194
|
+
- `params`: OAuth parameters including tokens and name
|
|
195
|
+
|
|
196
|
+
**Returns:** Promise resolving when credentials are saved
|
|
197
|
+
|
|
198
|
+
**Example:**
|
|
199
|
+
```typescript
|
|
200
|
+
await serverApi.saveOAuthCredentials('trakt', {
|
|
201
|
+
name: 'My Trakt Account',
|
|
202
|
+
code: 'oauth-code',
|
|
203
|
+
access_token: 'token123'
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### `addLibraryCredential(credential: any): Promise<ILibrary>`
|
|
208
|
+
|
|
209
|
+
Adds a credential to a library. This is used to configure external service access for libraries.
|
|
210
|
+
|
|
211
|
+
**Parameters:**
|
|
212
|
+
- `credential`: Credential configuration object (structure depends on credential type)
|
|
213
|
+
|
|
214
|
+
**Returns:** Promise resolving to the updated `ILibrary` object
|
|
215
|
+
|
|
216
|
+
**Example:**
|
|
217
|
+
```typescript
|
|
218
|
+
const library = await serverApi.addLibraryCredential({
|
|
219
|
+
libraryId: 'library-123',
|
|
220
|
+
credentialId: 'credential-456',
|
|
221
|
+
// Additional credential-specific configuration
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Watch History API
|
|
226
|
+
|
|
227
|
+
The Watch History API tracks what content users have watched and their playback progress. This is a **global** system that operates independently of specific libraries or servers.
|
|
228
|
+
|
|
229
|
+
### Key Concepts
|
|
230
|
+
|
|
231
|
+
#### External ID Format
|
|
232
|
+
|
|
233
|
+
Watch history uses **external IDs** (from providers like IMDb, Trakt, TMDb) rather than local database IDs. This design enables:
|
|
234
|
+
|
|
235
|
+
- **Cross-server portability**: Your watch history syncs across different Redseat servers
|
|
236
|
+
- **External service synchronization**: Seamless sync with Trakt, Plex, and other services
|
|
237
|
+
- **Library independence**: History is global, not tied to a specific library
|
|
238
|
+
|
|
239
|
+
**ID Format: `provider:value`**
|
|
240
|
+
|
|
241
|
+
| Provider | Format | Example |
|
|
242
|
+
|----------|--------|---------|
|
|
243
|
+
| IMDb | `imdb:ttXXXXXXX` | `imdb:tt0111161` (The Shawshank Redemption) |
|
|
244
|
+
| Trakt | `trakt:XXXXX` | `trakt:28` |
|
|
245
|
+
| TMDb | `tmdb:XXX` | `tmdb:278` |
|
|
246
|
+
| TVDB | `tvdb:XXXXX` | `tvdb:81189` |
|
|
247
|
+
| Redseat | `redseat:XXXXX` | `redseat:abc123` (local fallback) |
|
|
248
|
+
|
|
249
|
+
#### Library vs Direct History Endpoints
|
|
250
|
+
|
|
251
|
+
There are two ways to mark content as watched:
|
|
252
|
+
|
|
253
|
+
1. **Library endpoints** (recommended for most use cases):
|
|
254
|
+
- `LibraryApi.setMovieWatched(movieId, date)`
|
|
255
|
+
- `LibraryApi.setEpisodeWatched(serieId, season, number, date)`
|
|
256
|
+
- Uses local database IDs
|
|
257
|
+
- Server automatically resolves to external IDs
|
|
258
|
+
|
|
259
|
+
2. **Direct history endpoints** (for external sync):
|
|
260
|
+
- `ServerApi.addToHistory({ type, id, date })`
|
|
261
|
+
- Requires external IDs in `provider:value` format
|
|
262
|
+
- Used for importing from external services
|
|
263
|
+
|
|
264
|
+
### History Methods
|
|
265
|
+
|
|
266
|
+
#### `getHistory(query?: HistoryQuery): Promise<IWatched[]>`
|
|
267
|
+
|
|
268
|
+
Retrieves the current user's watch history.
|
|
269
|
+
|
|
270
|
+
**Parameters:**
|
|
271
|
+
- `query`: Optional query object with filtering parameters:
|
|
272
|
+
- `sort`: Sort key using `RsSort` enum
|
|
273
|
+
- `order`: Sort direction using `SqlOrder` enum (`ASC` or `DESC`)
|
|
274
|
+
- `before`: Filter entries before this timestamp
|
|
275
|
+
- `after`: Filter entries after this timestamp
|
|
276
|
+
- `types`: Array of `MediaType` to filter by (`'episode'`, `'movie'`, `'book'`, `'song'`, `'media'`)
|
|
277
|
+
- `id`: Filter by specific external ID (e.g., `imdb:tt0111161`)
|
|
278
|
+
- `pageKey`: Pagination key
|
|
279
|
+
|
|
280
|
+
**Returns:** Promise resolving to an array of `IWatched` objects
|
|
281
|
+
|
|
282
|
+
**Example:**
|
|
283
|
+
```typescript
|
|
284
|
+
// Get all history
|
|
285
|
+
const history = await serverApi.getHistory();
|
|
286
|
+
|
|
287
|
+
// Get recent movie watch history
|
|
288
|
+
const movieHistory = await serverApi.getHistory({
|
|
289
|
+
types: ['movie'],
|
|
290
|
+
order: SqlOrder.DESC,
|
|
291
|
+
after: Date.now() - 86400000 * 30 // Last 30 days
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
// Check if specific movie was watched (using external ID)
|
|
295
|
+
const shawshank = await serverApi.getHistory({
|
|
296
|
+
id: 'imdb:tt0111161'
|
|
297
|
+
});
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
#### `addToHistory(watched: IWatchedForAdd): Promise<void>`
|
|
301
|
+
|
|
302
|
+
Adds an entry to the user's watch history using external IDs.
|
|
303
|
+
|
|
304
|
+
**Parameters:**
|
|
305
|
+
- `watched`: Object containing:
|
|
306
|
+
- `type`: The `MediaType` (`'episode'`, `'movie'`, `'book'`, `'song'`, `'media'`)
|
|
307
|
+
- `id`: **External ID** in `provider:value` format (e.g., `imdb:tt0111161`)
|
|
308
|
+
- `date`: Timestamp when it was watched (unix milliseconds)
|
|
309
|
+
|
|
310
|
+
**Returns:** Promise resolving when the entry is added
|
|
311
|
+
|
|
312
|
+
**Example:**
|
|
313
|
+
```typescript
|
|
314
|
+
// Mark The Shawshank Redemption as watched using IMDb ID
|
|
315
|
+
await serverApi.addToHistory({
|
|
316
|
+
type: 'movie',
|
|
317
|
+
id: 'imdb:tt0111161',
|
|
318
|
+
date: Date.now()
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
// Mark a Breaking Bad episode as watched using Trakt ID
|
|
322
|
+
await serverApi.addToHistory({
|
|
323
|
+
type: 'episode',
|
|
324
|
+
id: 'trakt:62085', // S01E01
|
|
325
|
+
date: Date.now()
|
|
326
|
+
});
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
**Note:** For easier usage with local content, prefer the library methods which handle ID resolution automatically:
|
|
330
|
+
```typescript
|
|
331
|
+
// This is simpler - uses local ID, server resolves to external
|
|
332
|
+
await libraryApi.setMovieWatched('local-movie-id', Date.now());
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
#### `getProgressById(id: string): Promise<IViewProgress | null>`
|
|
336
|
+
|
|
337
|
+
Gets the view progress for a specific item by external ID.
|
|
338
|
+
|
|
339
|
+
**Parameters:**
|
|
340
|
+
- `id`: External ID in `provider:value` format (e.g., `imdb:tt0111161`)
|
|
341
|
+
|
|
342
|
+
**Returns:** Promise resolving to `IViewProgress` object or `null` if not found
|
|
343
|
+
|
|
344
|
+
**Example:**
|
|
345
|
+
```typescript
|
|
346
|
+
const progress = await serverApi.getProgressById('imdb:tt0111161');
|
|
347
|
+
if (progress) {
|
|
348
|
+
console.log(`Progress: ${progress.progress}ms`);
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
#### `addProgress(progress: IViewProgressForAdd): Promise<void>`
|
|
353
|
+
|
|
354
|
+
Adds or updates view progress for an item using external IDs.
|
|
355
|
+
|
|
356
|
+
**Parameters:**
|
|
357
|
+
- `progress`: Object containing:
|
|
358
|
+
- `type`: The `MediaType`
|
|
359
|
+
- `id`: **External ID** in `provider:value` format
|
|
360
|
+
- `progress`: Progress value in milliseconds
|
|
361
|
+
- `parent`: Optional parent external ID (e.g., series ID for episodes)
|
|
362
|
+
|
|
363
|
+
**Returns:** Promise resolving when progress is saved
|
|
364
|
+
|
|
365
|
+
**Example:**
|
|
366
|
+
```typescript
|
|
367
|
+
// Save playback position at 1 hour
|
|
368
|
+
await serverApi.addProgress({
|
|
369
|
+
type: 'movie',
|
|
370
|
+
id: 'imdb:tt0111161',
|
|
371
|
+
progress: 3600000 // milliseconds
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
// Save episode progress with parent series
|
|
375
|
+
await serverApi.addProgress({
|
|
376
|
+
type: 'episode',
|
|
377
|
+
id: 'imdb:tt0959621', // Breaking Bad S01E01
|
|
378
|
+
parent: 'imdb:tt0903747', // Breaking Bad series
|
|
379
|
+
progress: 1800000 // 30 minutes
|
|
380
|
+
});
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### Admin History Methods
|
|
384
|
+
|
|
385
|
+
#### `getAdminHistory(): Promise<IWatched[]>`
|
|
386
|
+
|
|
387
|
+
**Admin only.** Retrieves watch history for all users.
|
|
388
|
+
|
|
389
|
+
**Returns:** Promise resolving to an array of `IWatched` objects
|
|
390
|
+
|
|
391
|
+
**Example:**
|
|
392
|
+
```typescript
|
|
393
|
+
const allHistory = await serverApi.getAdminHistory();
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
#### `importHistory(watcheds: IWatchedForAdd[]): Promise<void>`
|
|
397
|
+
|
|
398
|
+
**Admin only.** Imports watch history entries in bulk. Useful for migrating from external services.
|
|
399
|
+
|
|
400
|
+
**Parameters:**
|
|
401
|
+
- `watcheds`: Array of `IWatchedForAdd` objects with external IDs
|
|
402
|
+
|
|
403
|
+
**Returns:** Promise resolving when import is complete
|
|
404
|
+
|
|
405
|
+
**Example:**
|
|
406
|
+
```typescript
|
|
407
|
+
// Import watch history from an external service
|
|
408
|
+
await serverApi.importHistory([
|
|
409
|
+
{ type: 'movie', id: 'imdb:tt0111161', date: Date.now() - 86400000 },
|
|
410
|
+
{ type: 'movie', id: 'tmdb:278', date: Date.now() - 172800000 },
|
|
411
|
+
{ type: 'episode', id: 'trakt:62085', date: Date.now() }
|
|
412
|
+
]);
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Complete Example: Syncing with External Service
|
|
416
|
+
|
|
417
|
+
```typescript
|
|
418
|
+
import { RedseatClient, ServerApi, SqlOrder } from '@redseat/api';
|
|
419
|
+
|
|
420
|
+
// Initialize
|
|
421
|
+
const client = new RedseatClient({ /* ... */ });
|
|
422
|
+
const serverApi = new ServerApi(client);
|
|
423
|
+
|
|
424
|
+
// Export: Get all watched movies to sync to external service
|
|
425
|
+
const watchedMovies = await serverApi.getHistory({
|
|
426
|
+
types: ['movie'],
|
|
427
|
+
order: SqlOrder.ASC
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
// The IDs are already in external format for easy sync
|
|
431
|
+
for (const entry of watchedMovies) {
|
|
432
|
+
console.log(`Watched: ${entry.id} on ${new Date(entry.date).toISOString()}`);
|
|
433
|
+
// entry.id is e.g., "imdb:tt0111161"
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// Import: Bring in history from external service
|
|
437
|
+
const externalHistory = [
|
|
438
|
+
{ type: 'movie' as const, id: 'imdb:tt0468569', date: 1609459200000 }, // The Dark Knight
|
|
439
|
+
{ type: 'movie' as const, id: 'trakt:120', date: 1612137600000 }, // LOTR
|
|
440
|
+
];
|
|
441
|
+
await serverApi.importHistory(externalHistory);
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
### SSE Events
|
|
445
|
+
|
|
446
|
+
Real-time watch state changes are broadcast via SSE. These are **user-scoped** events (not library-specific).
|
|
447
|
+
|
|
448
|
+
#### `watched$: Observable<SSEWatchedEvent>`
|
|
449
|
+
|
|
450
|
+
Emitted when content is marked as watched.
|
|
451
|
+
|
|
452
|
+
```typescript
|
|
453
|
+
client.watched$.subscribe(event => {
|
|
454
|
+
console.log(`Watched: ${event.type} ${event.id} at ${new Date(event.date)}`);
|
|
455
|
+
// event.id is external ID, e.g., "imdb:tt0111161"
|
|
456
|
+
});
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
**Event fields:**
|
|
460
|
+
- `type`: Content type ('movie', 'episode')
|
|
461
|
+
- `id`: External ID (e.g., 'imdb:tt0111161')
|
|
462
|
+
- `date`: Timestamp when watched (unix ms)
|
|
463
|
+
- `userRef`: User reference
|
|
464
|
+
- `modified`: Last modified timestamp
|
|
465
|
+
|
|
466
|
+
#### `unwatched$: Observable<SSEUnwatchedEvent>`
|
|
467
|
+
|
|
468
|
+
Emitted when content is removed from watch history. Contains **all possible IDs** so clients can match against any cached external ID.
|
|
469
|
+
|
|
470
|
+
```typescript
|
|
471
|
+
client.unwatched$.subscribe(event => {
|
|
472
|
+
console.log(`Unwatched: ${event.type}`);
|
|
473
|
+
// event.ids contains ALL possible external IDs
|
|
474
|
+
for (const id of event.ids) {
|
|
475
|
+
console.log(` - ${id}`); // e.g., "imdb:tt0111161", "trakt:481"
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
**Event fields:**
|
|
481
|
+
- `type`: Content type ('movie', 'episode')
|
|
482
|
+
- `ids`: Array of all external IDs (e.g., `["imdb:tt0111161", "trakt:481", "tmdb:278"]`)
|
|
483
|
+
- `userRef`: User reference
|
|
484
|
+
- `modified`: Last modified timestamp
|
|
485
|
+
|
|
486
|
+
## Usage Examples
|
|
487
|
+
|
|
488
|
+
### Complete Workflow: Create Library and Get Info
|
|
489
|
+
|
|
490
|
+
```typescript
|
|
491
|
+
import { RedseatClient, ServerApi } from '@redseat/api';
|
|
492
|
+
|
|
493
|
+
// Initialize
|
|
494
|
+
const client = new RedseatClient({ /* ... */ });
|
|
495
|
+
const serverApi = new ServerApi(client);
|
|
496
|
+
|
|
497
|
+
// Get current user
|
|
498
|
+
const user = await serverApi.getMe();
|
|
499
|
+
console.log(`User: ${user.name}`);
|
|
500
|
+
|
|
501
|
+
// List existing libraries
|
|
502
|
+
const libraries = await serverApi.getLibraries();
|
|
503
|
+
console.log(`Found ${libraries.length} libraries`);
|
|
504
|
+
|
|
505
|
+
// Create a new encrypted photo library
|
|
506
|
+
const newLibrary = await serverApi.addLibrary({
|
|
507
|
+
name: 'Encrypted Photos',
|
|
508
|
+
type: 'photos',
|
|
509
|
+
crypt: true
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
// Get server settings
|
|
513
|
+
const maxUpload = await serverApi.getSetting('max_upload_size');
|
|
514
|
+
console.log(`Max upload size: ${maxUpload}`);
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
### Error Handling
|
|
518
|
+
|
|
519
|
+
```typescript
|
|
520
|
+
try {
|
|
521
|
+
const libraries = await serverApi.getLibraries();
|
|
522
|
+
} catch (error) {
|
|
523
|
+
if (error.response?.status === 401) {
|
|
524
|
+
console.error('Authentication failed');
|
|
525
|
+
} else if (error.response?.status === 403) {
|
|
526
|
+
console.error('Insufficient permissions');
|
|
527
|
+
} else {
|
|
528
|
+
console.error('Failed to get libraries:', error.message);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
## Related Documentation
|
|
534
|
+
|
|
535
|
+
- [RedseatClient Documentation](client.md) - HTTP client used by ServerApi
|
|
536
|
+
- [LibraryApi Documentation](libraries.md) - Library-specific operations
|
|
537
|
+
- [README](README.md) - Package overview
|
|
538
|
+
|