@redseat/api 0.3.6 → 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 +151 -0
- package/dist/sse-types.d.ts +15 -1
- package/encryption.md +533 -533
- package/firebase.md +602 -602
- package/libraries.md +55 -20
- package/package.json +49 -49
- package/server.md +538 -398
- package/test.md +291 -291
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 } 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 } from './sse-types.js';
|
|
6
6
|
export interface ClientOptions {
|
|
7
7
|
server: IServer;
|
|
8
8
|
getIdToken: () => Promise<string>;
|
|
@@ -45,6 +45,8 @@ export declare class RedseatClient {
|
|
|
45
45
|
readonly mediaRating$: Observable<SSEMediaRatingEvent>;
|
|
46
46
|
readonly mediaProgress$: Observable<SSEMediaProgressEvent>;
|
|
47
47
|
readonly playersList$: Observable<SSEPlayersListEvent>;
|
|
48
|
+
readonly watched$: Observable<SSEWatchedEvent>;
|
|
49
|
+
readonly unwatched$: Observable<SSEUnwatchedEvent>;
|
|
48
50
|
/**
|
|
49
51
|
* Creates a typed observable for a specific SSE event type.
|
|
50
52
|
* Unwraps the nested data structure from the server (e.g., {uploadProgress: {...}} -> {...})
|
package/dist/client.js
CHANGED
|
@@ -55,6 +55,8 @@ export class RedseatClient {
|
|
|
55
55
|
this.mediaRating$ = this.createEventStream('media_rating');
|
|
56
56
|
this.mediaProgress$ = this.createEventStream('media_progress');
|
|
57
57
|
this.playersList$ = this.createEventStream('players-list');
|
|
58
|
+
this.watched$ = this.createEventStream('watched');
|
|
59
|
+
this.unwatched$ = this.createEventStream('unwatched');
|
|
58
60
|
this.server = options.server;
|
|
59
61
|
this.redseatUrl = options.redseatUrl;
|
|
60
62
|
this.getIdToken = options.getIdToken;
|
package/dist/interfaces.d.ts
CHANGED
|
@@ -483,40 +483,191 @@ export declare enum RsSort {
|
|
|
483
483
|
Name = "name",
|
|
484
484
|
Size = "size"
|
|
485
485
|
}
|
|
486
|
+
/**
|
|
487
|
+
* Media type for history/watched tracking.
|
|
488
|
+
* Used to categorize watched entries and view progress.
|
|
489
|
+
*/
|
|
486
490
|
export type MediaType = 'episode' | 'movie' | 'book' | 'song' | 'media';
|
|
491
|
+
/**
|
|
492
|
+
* Watch history entry - returned from GET /users/me/history.
|
|
493
|
+
*
|
|
494
|
+
* ## External ID Format
|
|
495
|
+
*
|
|
496
|
+
* Watch history uses **external IDs** (from providers like IMDb, Trakt, TMDb) rather than
|
|
497
|
+
* local database IDs. This design enables:
|
|
498
|
+
* - **Cross-server portability**: History syncs across different Redseat servers
|
|
499
|
+
* - **External service synchronization**: Seamless sync with Trakt, Plex, etc.
|
|
500
|
+
* - **Library independence**: History is global, not tied to a specific library
|
|
501
|
+
*
|
|
502
|
+
* ### ID Format: `provider:value`
|
|
503
|
+
*
|
|
504
|
+
* Examples:
|
|
505
|
+
* - `imdb:tt1234567` - IMDb ID for movies/episodes
|
|
506
|
+
* - `trakt:123456` - Trakt ID
|
|
507
|
+
* - `tmdb:550` - TMDb ID
|
|
508
|
+
* - `tvdb:12345` - TVDB ID for series/episodes
|
|
509
|
+
* - `redseat:abc123` - Local fallback when no external ID is available
|
|
510
|
+
*
|
|
511
|
+
* When marking content as watched via library endpoints (e.g., `setMovieWatched`),
|
|
512
|
+
* the server automatically resolves the local ID to an external ID.
|
|
513
|
+
*/
|
|
487
514
|
export interface IWatched {
|
|
515
|
+
/** Content type (episode, movie, etc.) */
|
|
488
516
|
type: MediaType;
|
|
517
|
+
/**
|
|
518
|
+
* External ID in format `provider:value` (e.g., `imdb:tt1234567`).
|
|
519
|
+
* See interface documentation for details on the ID format.
|
|
520
|
+
*/
|
|
489
521
|
id: string;
|
|
522
|
+
/** User reference (for admin queries) */
|
|
490
523
|
userRef?: string;
|
|
524
|
+
/** Timestamp when content was watched (unix milliseconds) */
|
|
491
525
|
date: number;
|
|
526
|
+
/** Timestamp when entry was last modified (unix milliseconds) */
|
|
492
527
|
modified: number;
|
|
493
528
|
}
|
|
529
|
+
/**
|
|
530
|
+
* Unwatched event data - emitted via SSE when content is removed from watch history.
|
|
531
|
+
*
|
|
532
|
+
* Unlike IWatched which has a single `id`, this uses `ids[]` array containing
|
|
533
|
+
* all possible external IDs (imdb, trakt, tmdb, local) so clients can match
|
|
534
|
+
* against any provider they have cached.
|
|
535
|
+
*
|
|
536
|
+
* This is a user-scoped event - not library-scoped.
|
|
537
|
+
*/
|
|
538
|
+
export interface IUnwatched {
|
|
539
|
+
/** Content type (episode, movie, etc.) */
|
|
540
|
+
type: MediaType;
|
|
541
|
+
/**
|
|
542
|
+
* All possible external IDs for this content.
|
|
543
|
+
* Format: `provider:value`
|
|
544
|
+
* Examples: ["imdb:tt0111161", "trakt:481", "tmdb:278"]
|
|
545
|
+
*/
|
|
546
|
+
ids: string[];
|
|
547
|
+
/** User reference */
|
|
548
|
+
userRef?: string;
|
|
549
|
+
/** Timestamp when entry was removed (unix milliseconds) */
|
|
550
|
+
modified: number;
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Request body for adding to watch history via POST /users/me/history.
|
|
554
|
+
*
|
|
555
|
+
* ## External ID Requirement
|
|
556
|
+
*
|
|
557
|
+
* When using the direct history endpoint, you must provide an external ID.
|
|
558
|
+
* The ID format is `provider:value`:
|
|
559
|
+
* - `imdb:tt1234567` - IMDb ID
|
|
560
|
+
* - `trakt:123456` - Trakt ID
|
|
561
|
+
* - `tmdb:550` - TMDb ID
|
|
562
|
+
* - `tvdb:12345` - TVDB ID
|
|
563
|
+
*
|
|
564
|
+
* **Tip**: For easier usage, prefer the library-specific endpoints
|
|
565
|
+
* (`setMovieWatched`, `setEpisodeWatched`) which automatically resolve IDs.
|
|
566
|
+
*
|
|
567
|
+
* @example
|
|
568
|
+
* ```typescript
|
|
569
|
+
* // Direct history endpoint - requires external ID
|
|
570
|
+
* await serverApi.addToHistory({
|
|
571
|
+
* type: 'movie',
|
|
572
|
+
* id: 'imdb:tt0111161', // The Shawshank Redemption
|
|
573
|
+
* date: Date.now()
|
|
574
|
+
* });
|
|
575
|
+
*
|
|
576
|
+
* // Library endpoint - uses local ID, server resolves to external
|
|
577
|
+
* await libraryApi.setMovieWatched('local-movie-id', Date.now());
|
|
578
|
+
* ```
|
|
579
|
+
*/
|
|
494
580
|
export interface IWatchedForAdd {
|
|
581
|
+
/** Content type (episode, movie, etc.) */
|
|
495
582
|
type: MediaType;
|
|
583
|
+
/**
|
|
584
|
+
* External ID in format `provider:value` (e.g., `imdb:tt1234567`).
|
|
585
|
+
* See interface documentation for details on the ID format.
|
|
586
|
+
*/
|
|
496
587
|
id: string;
|
|
588
|
+
/** Timestamp when content was watched (unix milliseconds) */
|
|
497
589
|
date: number;
|
|
498
590
|
}
|
|
591
|
+
/**
|
|
592
|
+
* View progress entry - returned from GET /users/me/history/progress/:id.
|
|
593
|
+
*
|
|
594
|
+
* Tracks playback position for resumable viewing.
|
|
595
|
+
* Uses the same external ID format as watch history.
|
|
596
|
+
*/
|
|
499
597
|
export interface IViewProgress {
|
|
598
|
+
/** Content type (episode, movie, etc.) */
|
|
500
599
|
type: MediaType;
|
|
600
|
+
/**
|
|
601
|
+
* External ID in format `provider:value` (e.g., `imdb:tt1234567`).
|
|
602
|
+
*/
|
|
501
603
|
id: string;
|
|
604
|
+
/** User reference */
|
|
502
605
|
userRef: string;
|
|
606
|
+
/** Playback progress in milliseconds */
|
|
503
607
|
progress: number;
|
|
608
|
+
/** Parent ID for episodes (series external ID) */
|
|
504
609
|
parent?: string;
|
|
610
|
+
/** Timestamp when progress was last modified (unix milliseconds) */
|
|
505
611
|
modified: number;
|
|
506
612
|
}
|
|
613
|
+
/**
|
|
614
|
+
* Request body for updating view progress via POST /users/me/history/progress.
|
|
615
|
+
*
|
|
616
|
+
* Uses external IDs in format `provider:value` (e.g., `imdb:tt1234567`).
|
|
617
|
+
*
|
|
618
|
+
* @example
|
|
619
|
+
* ```typescript
|
|
620
|
+
* await serverApi.addProgress({
|
|
621
|
+
* type: 'movie',
|
|
622
|
+
* id: 'imdb:tt0111161',
|
|
623
|
+
* progress: 3600000 // 1 hour in milliseconds
|
|
624
|
+
* });
|
|
625
|
+
* ```
|
|
626
|
+
*/
|
|
507
627
|
export interface IViewProgressForAdd {
|
|
628
|
+
/** Content type (episode, movie, etc.) */
|
|
508
629
|
type: MediaType;
|
|
630
|
+
/**
|
|
631
|
+
* External ID in format `provider:value` (e.g., `imdb:tt1234567`).
|
|
632
|
+
*/
|
|
509
633
|
id: string;
|
|
634
|
+
/** Parent ID for episodes (series external ID) */
|
|
510
635
|
parent?: string;
|
|
636
|
+
/** Playback progress in milliseconds */
|
|
511
637
|
progress: number;
|
|
512
638
|
}
|
|
639
|
+
/**
|
|
640
|
+
* Query parameters for GET /users/me/history.
|
|
641
|
+
*
|
|
642
|
+
* @example
|
|
643
|
+
* ```typescript
|
|
644
|
+
* // Get recent movie history
|
|
645
|
+
* const history = await serverApi.getHistory({
|
|
646
|
+
* types: ['movie'],
|
|
647
|
+
* order: SqlOrder.DESC,
|
|
648
|
+
* after: Date.now() - 86400000 * 30 // Last 30 days
|
|
649
|
+
* });
|
|
650
|
+
*
|
|
651
|
+
* // Check if specific content was watched
|
|
652
|
+
* const watched = await serverApi.getHistory({
|
|
653
|
+
* id: 'imdb:tt0111161'
|
|
654
|
+
* });
|
|
655
|
+
* ```
|
|
656
|
+
*/
|
|
513
657
|
export interface HistoryQuery {
|
|
658
|
+
/** Sort field */
|
|
514
659
|
sort?: RsSort;
|
|
660
|
+
/** Sort direction */
|
|
515
661
|
order?: SqlOrder;
|
|
662
|
+
/** Filter entries watched before this timestamp (unix ms) */
|
|
516
663
|
before?: number;
|
|
664
|
+
/** Filter entries watched after this timestamp (unix ms) */
|
|
517
665
|
after?: number;
|
|
666
|
+
/** Filter by content types */
|
|
518
667
|
types?: MediaType[];
|
|
668
|
+
/** Filter by specific external ID */
|
|
519
669
|
id?: string;
|
|
670
|
+
/** Pagination key for next page */
|
|
520
671
|
pageKey?: number;
|
|
521
672
|
}
|
|
522
673
|
export type MovieSort = 'modified' | 'added' | 'created' | 'name' | 'digitalairdate';
|
package/dist/sse-types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ILibrary, IFile, IEpisode, ISerie, IMovie, IPerson, ITag, IBackup } from './interfaces.js';
|
|
1
|
+
import { ILibrary, IFile, IEpisode, ISerie, IMovie, IPerson, ITag, IBackup, IWatched, IUnwatched } 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 {
|
|
@@ -134,6 +134,18 @@ export interface SSEPlayersListEvent {
|
|
|
134
134
|
userRef: string;
|
|
135
135
|
players: SSEPlayerEvent[];
|
|
136
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* SSE event emitted when content is marked as watched.
|
|
139
|
+
* This is a user-scoped event - not library-scoped.
|
|
140
|
+
* Uses external IDs (e.g., "imdb:tt0111161").
|
|
141
|
+
*/
|
|
142
|
+
export type SSEWatchedEvent = IWatched;
|
|
143
|
+
/**
|
|
144
|
+
* SSE event emitted when content is removed from watch history.
|
|
145
|
+
* Contains all possible external IDs so clients can match against any cached ID.
|
|
146
|
+
* This is a user-scoped event - not library-scoped.
|
|
147
|
+
*/
|
|
148
|
+
export type SSEUnwatchedEvent = IUnwatched;
|
|
137
149
|
export interface SSEEventMap {
|
|
138
150
|
'library': SSELibraryEvent;
|
|
139
151
|
'library-status': SSELibraryStatusEvent;
|
|
@@ -150,6 +162,8 @@ export interface SSEEventMap {
|
|
|
150
162
|
'media_rating': SSEMediaRatingEvent;
|
|
151
163
|
'media_progress': SSEMediaProgressEvent;
|
|
152
164
|
'players-list': SSEPlayersListEvent;
|
|
165
|
+
'watched': SSEWatchedEvent;
|
|
166
|
+
'unwatched': SSEUnwatchedEvent;
|
|
153
167
|
}
|
|
154
168
|
export type SSEEventName = keyof SSEEventMap;
|
|
155
169
|
export interface SSEEvent<T extends SSEEventName = SSEEventName> {
|