@francofantomius/jellyfin 0.1.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.
@@ -0,0 +1,1092 @@
1
+ type VideoQualityPresetKey = 'auto' | 'direct' | '4k' | '1080p-high' | '1080p' | '720p-high' | '720p' | '480p' | '360p' | '240p';
2
+ interface VideoQualityOption {
3
+ key: VideoQualityPresetKey;
4
+ label: string;
5
+ bitrate?: number;
6
+ maxWidth?: number;
7
+ maxHeight?: number;
8
+ }
9
+ type AudioQualityPresetKey = 'direct' | '320k' | '256k' | '192k' | '128k' | '64k';
10
+ interface AudioQualityOption {
11
+ key: AudioQualityPresetKey;
12
+ label: string;
13
+ bitrate?: number;
14
+ }
15
+ declare const VIDEO_QUALITY_PRESETS: Record<VideoQualityPresetKey, VideoQualityOption>;
16
+ declare const AUDIO_QUALITY_PRESETS: Record<AudioQualityPresetKey, AudioQualityOption>;
17
+ /**
18
+ * Returns a list of all available video quality presets.
19
+ */
20
+ declare function getVideoQualityList(): VideoQualityOption[];
21
+ /**
22
+ * Returns a list of all available audio quality presets.
23
+ */
24
+ declare function getAudioQualityList(): AudioQualityOption[];
25
+ /**
26
+ * Resolves video quality option into bitrate, maxWidth, and maxHeight constraints.
27
+ */
28
+ declare function resolveVideoQuality(quality?: VideoQualityPresetKey | VideoQualityOption | number | string): {
29
+ maxStreamingBitrate?: number;
30
+ maxWidth?: number;
31
+ maxHeight?: number;
32
+ };
33
+ /**
34
+ * Resolves audio quality option into bitrate constraint.
35
+ */
36
+ declare function resolveAudioQuality(quality?: AudioQualityPresetKey | AudioQualityOption | number | string): {
37
+ maxStreamingBitrate?: number;
38
+ };
39
+ /**
40
+ * Formats a bitrate in bps into a human-readable string (e.g. "10 Mbps", "320 kbps").
41
+ */
42
+ declare function formatBitrate(bitrate?: number): string;
43
+
44
+ /**
45
+ * Client identification info sent in Jellyfin authorization headers.
46
+ */
47
+ interface ClientInfo {
48
+ name: string;
49
+ version: string;
50
+ device: string;
51
+ deviceId: string;
52
+ }
53
+ /**
54
+ * Storage adapter interface for persisting session data.
55
+ */
56
+ interface StorageAdapter {
57
+ getItem(key: string): string | null | Promise<string | null>;
58
+ setItem(key: string, value: string): void | Promise<void>;
59
+ removeItem(key: string): void | Promise<void>;
60
+ }
61
+ /**
62
+ * Options to initialize a JellyfinClient.
63
+ */
64
+ interface JellyfinClientOptions {
65
+ /**
66
+ * Base URL of the Jellyfin server (e.g., https://jellyfin.example.com).
67
+ */
68
+ serverUrl?: string;
69
+ /**
70
+ * Jellyfin access token for authenticated requests.
71
+ */
72
+ accessToken?: string;
73
+ /**
74
+ * Jellyfin User ID.
75
+ */
76
+ userId?: string;
77
+ /**
78
+ * Client identity parameters. Defaults to generic SDK information if omitted.
79
+ */
80
+ clientInfo?: Partial<ClientInfo>;
81
+ /**
82
+ * Custom storage adapter to persist session data (e.g. LocalStorageAdapter or custom).
83
+ * Defaults to MemoryStorage.
84
+ */
85
+ storage?: StorageAdapter;
86
+ /**
87
+ * Custom fetch function (defaults to globalThis.fetch).
88
+ */
89
+ fetch?: typeof fetch;
90
+ /**
91
+ * Callback invoked when a 401 Unauthorized response is received.
92
+ */
93
+ onUnauthorized?: () => void;
94
+ /**
95
+ * Pinned server version or version hint (e.g. "12.0.0" or "10.9.11").
96
+ * If omitted, the client can auto-detect via SystemModule.
97
+ */
98
+ serverVersion?: string;
99
+ /**
100
+ * Compatibility target version: 'auto' (detect automatically), '10' (legacy Jellyfin 10.x), or '12' (Jellyfin 12+).
101
+ * Defaults to 'auto'.
102
+ */
103
+ targetVersion?: 'auto' | '10' | '12';
104
+ }
105
+ /**
106
+ * Authenticated user information.
107
+ */
108
+ interface UserDto {
109
+ Id: string;
110
+ Name: string;
111
+ ServerId?: string;
112
+ PrimaryImageTag?: string;
113
+ ImageTags?: Record<string, string>;
114
+ HasPassword?: boolean;
115
+ LastLoginDate?: string;
116
+ LastActivityDate?: string;
117
+ Configuration?: Record<string, unknown>;
118
+ Policy?: Record<string, unknown>;
119
+ }
120
+ /**
121
+ * Authentication response from Jellyfin.
122
+ */
123
+ interface AuthenticationResult {
124
+ User: UserDto;
125
+ AccessToken: string;
126
+ ServerId: string;
127
+ SessionInfo?: Record<string, unknown>;
128
+ }
129
+ /**
130
+ * Generic Jellyfin items response.
131
+ */
132
+ interface ItemsResponse<T = BaseItemDto> {
133
+ Items: T[];
134
+ TotalRecordCount: number;
135
+ StartIndex?: number;
136
+ }
137
+ /**
138
+ * User data associated with an item (played status, favorites, rating).
139
+ */
140
+ interface UserItemDataDto {
141
+ Rating?: number;
142
+ PlayedPercentage?: number;
143
+ UnplayedItemCount?: number;
144
+ PlaybackPositionTicks?: number;
145
+ PlayCount?: number;
146
+ IsFavorite?: boolean;
147
+ LastPlayedDate?: string;
148
+ Played?: boolean;
149
+ Key?: string;
150
+ }
151
+ /**
152
+ * Common Jellyfin item structure.
153
+ */
154
+ interface BaseItemDto {
155
+ Id: string;
156
+ Name: string;
157
+ ServerId?: string;
158
+ Type?: string;
159
+ CollectionType?: string;
160
+ RunTimeTicks?: number;
161
+ Container?: string;
162
+ MediaType?: string;
163
+ ProductionYear?: number;
164
+ IndexNumber?: number;
165
+ ParentIndexNumber?: number;
166
+ IndexNumberEnd?: number;
167
+ IsFolder?: boolean;
168
+ ParentId?: string;
169
+ Album?: string;
170
+ AlbumId?: string;
171
+ AlbumPrimaryImageTag?: string;
172
+ AlbumArtist?: string;
173
+ Artists?: string[];
174
+ ArtistItems?: Array<{
175
+ Id: string;
176
+ Name: string;
177
+ }>;
178
+ Overview?: string;
179
+ Genres?: string[];
180
+ Taglines?: string[];
181
+ DateCreated?: string;
182
+ DateLastMediaAdded?: string;
183
+ UserData?: UserItemDataDto;
184
+ PrimaryImageAspectRatio?: number;
185
+ ImageTags?: Record<string, string>;
186
+ PrimaryImageTag?: string;
187
+ BackdropImageTags?: string[];
188
+ MediaSources?: MediaSourceInfo[];
189
+ HasLyrics?: boolean;
190
+ /**
191
+ * Unique relational playlist entry ID (Jellyfin 12+).
192
+ * Distinguishes duplicate tracks inside the same playlist.
193
+ */
194
+ PlaylistItemId?: string;
195
+ [key: string]: unknown;
196
+ }
197
+ interface MediaSourceInfo {
198
+ Id?: string;
199
+ Path?: string;
200
+ Protocol?: string;
201
+ MediaStreams?: MediaStreamInfo[];
202
+ Container?: string;
203
+ Size?: number;
204
+ Bitrate?: number;
205
+ }
206
+ interface MediaStreamInfo {
207
+ Codec?: string;
208
+ Type?: string;
209
+ Index?: number;
210
+ BitRate?: number;
211
+ Channels?: number;
212
+ SampleRate?: number;
213
+ Width?: number;
214
+ Height?: number;
215
+ AspectRatio?: string;
216
+ AverageFrameRate?: number;
217
+ RealFrameRate?: number;
218
+ Profile?: string;
219
+ Level?: number;
220
+ PixelFormat?: string;
221
+ IsInterlaced?: boolean;
222
+ Language?: string;
223
+ DisplayTitle?: string;
224
+ DisplayLanguage?: string;
225
+ IsDefault?: boolean;
226
+ IsForced?: boolean;
227
+ IsExternal?: boolean;
228
+ DeliveryMethod?: string;
229
+ DeliveryUrl?: string;
230
+ [key: string]: unknown;
231
+ }
232
+ interface GetAlbumsOptions {
233
+ limit?: number;
234
+ startIndex?: number;
235
+ parentId?: string;
236
+ artistId?: string;
237
+ sortBy?: string;
238
+ sortOrder?: 'Ascending' | 'Descending';
239
+ }
240
+ interface GetArtistsOptions {
241
+ limit?: number;
242
+ startIndex?: number;
243
+ sortBy?: string;
244
+ sortOrder?: 'Ascending' | 'Descending';
245
+ }
246
+ interface GetSongsOptions {
247
+ limit?: number;
248
+ startIndex?: number;
249
+ albumId?: string;
250
+ artistId?: string;
251
+ isFavorite?: boolean;
252
+ sortBy?: string;
253
+ sortOrder?: 'Ascending' | 'Descending';
254
+ }
255
+ interface SearchOptions {
256
+ limit?: number;
257
+ startIndex?: number;
258
+ includeItemTypes?: string;
259
+ }
260
+ interface CreatePlaylistDto {
261
+ Name: string;
262
+ Ids?: string[];
263
+ UserId?: string;
264
+ MediaType?: string;
265
+ Users?: Array<{
266
+ UserId: string;
267
+ CanEdit?: boolean;
268
+ }>;
269
+ IsPublic?: boolean;
270
+ }
271
+ interface CreatePlaylistOptions {
272
+ name: string;
273
+ isPublic?: boolean;
274
+ trackIds?: string[];
275
+ userId?: string;
276
+ mediaType?: string;
277
+ }
278
+ interface UpdatePlaylistOptions {
279
+ name?: string;
280
+ }
281
+ interface AudioStreamOptions {
282
+ maxStreamingBitrate?: string | number;
283
+ quality?: AudioQualityPresetKey | AudioQualityOption | number | string;
284
+ startTimeTicks?: number;
285
+ container?: string;
286
+ transcodingContainer?: string;
287
+ audioCodec?: string;
288
+ /**
289
+ * Whether to include the api_key token in the URL query parameters.
290
+ * Defaults to true for HTML5 <audio> tag compatibility.
291
+ * If false, callers are expected to provide Authorization headers.
292
+ */
293
+ useQueryToken?: boolean;
294
+ }
295
+ interface AudioHlsStreamOptions {
296
+ maxStreamingBitrate?: string | number;
297
+ quality?: AudioQualityPresetKey | AudioQualityOption | number | string;
298
+ startTimeTicks?: number;
299
+ audioCodec?: string;
300
+ segmentLength?: number;
301
+ /**
302
+ * Whether to include the api_key token in the URL query parameters.
303
+ * Defaults to true for legacy compatibility.
304
+ * If false, players (e.g. hls.js) should be configured with Authorization headers via xhrSetup.
305
+ */
306
+ useQueryToken?: boolean;
307
+ }
308
+ interface ArtworkUrlOptions {
309
+ imageType?: 'Primary' | 'Art' | 'Backdrop' | 'Banner' | 'Logo' | 'Thumb' | 'Disc';
310
+ maxWidth?: number;
311
+ maxHeight?: number;
312
+ quality?: number;
313
+ fallbackUrl?: string;
314
+ }
315
+ interface PublicSystemInfo {
316
+ LocalAddress?: string;
317
+ ServerName?: string;
318
+ Version?: string;
319
+ ProductName?: string;
320
+ OperatingSystem?: string;
321
+ Id?: string;
322
+ StartupWizardCompleted?: boolean;
323
+ [key: string]: unknown;
324
+ }
325
+ interface SystemInfo extends PublicSystemInfo {
326
+ SystemArchitecture?: string;
327
+ HasPendingRestart?: boolean;
328
+ IsShuttingDown?: boolean;
329
+ SupportsLibraryMonitor?: boolean;
330
+ WebSocketPortNumber?: number;
331
+ CompletedInstallations?: unknown[];
332
+ CanSelfRestart?: boolean;
333
+ CanLaunchWebBrowser?: boolean;
334
+ ProgramDataPath?: string;
335
+ WebPath?: string;
336
+ ItemsByNamePath?: string;
337
+ CachePath?: string;
338
+ LogPath?: string;
339
+ InternalMetadataPath?: string;
340
+ TranscodingTempPath?: string;
341
+ HasUpdateAvailable?: boolean;
342
+ }
343
+ interface LyricLine {
344
+ Start?: number;
345
+ Text: string;
346
+ }
347
+ interface LyricsDto {
348
+ Lyrics?: LyricLine[];
349
+ [key: string]: unknown;
350
+ }
351
+ interface ClientCapabilities {
352
+ PlayableMediaTypes?: string[];
353
+ SupportedCommands?: string[];
354
+ SupportsMediaControl?: boolean;
355
+ SupportsSync?: boolean;
356
+ SupportsPersistentIdentifier?: boolean;
357
+ IconUrl?: string;
358
+ AppStoreUrl?: string;
359
+ MessageFormat?: string;
360
+ }
361
+ interface GetMoviesOptions {
362
+ limit?: number;
363
+ startIndex?: number;
364
+ parentId?: string;
365
+ isFavorite?: boolean;
366
+ sortBy?: string;
367
+ sortOrder?: 'Ascending' | 'Descending';
368
+ genres?: string[];
369
+ years?: number[];
370
+ searchTerm?: string;
371
+ }
372
+ interface GetSeriesOptions {
373
+ limit?: number;
374
+ startIndex?: number;
375
+ parentId?: string;
376
+ isFavorite?: boolean;
377
+ sortBy?: string;
378
+ sortOrder?: 'Ascending' | 'Descending';
379
+ genres?: string[];
380
+ years?: number[];
381
+ searchTerm?: string;
382
+ }
383
+ interface GetSeasonsOptions {
384
+ userId?: string;
385
+ fields?: string;
386
+ isSpecialSeason?: boolean;
387
+ }
388
+ interface GetEpisodesOptions {
389
+ seasonId?: string;
390
+ seasonNumber?: number;
391
+ startIndex?: number;
392
+ limit?: number;
393
+ isMissing?: boolean;
394
+ sortBy?: string;
395
+ sortOrder?: 'Ascending' | 'Descending';
396
+ }
397
+ interface GetVideosOptions {
398
+ limit?: number;
399
+ startIndex?: number;
400
+ parentId?: string;
401
+ includeItemTypes?: string;
402
+ sortBy?: string;
403
+ sortOrder?: 'Ascending' | 'Descending';
404
+ }
405
+ interface PlaybackInfoOptions {
406
+ userId?: string;
407
+ startTimeTicks?: number;
408
+ audioStreamIndex?: number;
409
+ subtitleStreamIndex?: number;
410
+ maxStreamingBitrate?: number;
411
+ mediaSourceId?: string;
412
+ deviceProfile?: Record<string, unknown>;
413
+ autoOpenLiveStream?: boolean;
414
+ }
415
+ interface PlaybackInfoResponse {
416
+ MediaSources: MediaSourceInfo[];
417
+ PlaySessionId?: string;
418
+ ErrorCode?: string;
419
+ [key: string]: unknown;
420
+ }
421
+ interface VideoStreamOptions {
422
+ mediaSourceId?: string;
423
+ static?: boolean;
424
+ videoCodec?: string;
425
+ audioCodec?: string;
426
+ maxStreamingBitrate?: string | number;
427
+ quality?: VideoQualityPresetKey | VideoQualityOption | number | string;
428
+ maxWidth?: number;
429
+ maxHeight?: number;
430
+ maxFramerate?: number;
431
+ audioStreamIndex?: number;
432
+ subtitleStreamIndex?: number;
433
+ subtitleMethod?: 'Embed' | 'Encode' | 'Hls' | 'External';
434
+ startTimeTicks?: number;
435
+ container?: string;
436
+ transcodingContainer?: string;
437
+ transcodingProtocol?: string;
438
+ useQueryToken?: boolean;
439
+ }
440
+ interface VideoHlsStreamOptions {
441
+ mediaSourceId?: string;
442
+ videoCodec?: string;
443
+ audioCodec?: string;
444
+ maxStreamingBitrate?: string | number;
445
+ quality?: VideoQualityPresetKey | VideoQualityOption | number | string;
446
+ maxWidth?: number;
447
+ maxHeight?: number;
448
+ maxFramerate?: number;
449
+ segmentLength?: number;
450
+ minSegments?: number;
451
+ audioStreamIndex?: number;
452
+ subtitleStreamIndex?: number;
453
+ subtitleMethod?: 'Embed' | 'Encode' | 'Hls' | 'External';
454
+ transcodingContainer?: 'ts' | 'fmp4' | string;
455
+ transcodingProtocol?: 'hls';
456
+ startTimeTicks?: number;
457
+ useQueryToken?: boolean;
458
+ }
459
+ interface SubtitleTrackInfo {
460
+ index: number;
461
+ codec: string;
462
+ language?: string;
463
+ displayTitle: string;
464
+ displayLanguage?: string;
465
+ isDefault: boolean;
466
+ isForced: boolean;
467
+ isExternal: boolean;
468
+ deliveryMethod?: string;
469
+ deliveryUrl?: string;
470
+ url: string;
471
+ }
472
+ interface SubtitleUrlOptions {
473
+ format?: 'vtt' | 'srt' | 'subrip' | string;
474
+ useQueryToken?: boolean;
475
+ startTimeTicks?: number;
476
+ }
477
+ interface DownloadUrlOptions {
478
+ useQueryToken?: boolean;
479
+ filename?: string;
480
+ }
481
+ interface DownloadItemOptions {
482
+ onProgress?: (progressFraction: number) => void;
483
+ group?: {
484
+ id?: string;
485
+ name?: string;
486
+ type?: string;
487
+ artworkUrl?: string;
488
+ owner?: string;
489
+ count?: number;
490
+ } | null;
491
+ index?: number;
492
+ quality?: VideoQualityPresetKey | VideoQualityOption | number | string;
493
+ }
494
+
495
+ interface RequestOptions {
496
+ method?: string;
497
+ params?: Record<string, unknown>;
498
+ body?: unknown;
499
+ contentType?: string;
500
+ headers?: Record<string, string>;
501
+ }
502
+ declare function cleanUrl(url: string): string;
503
+ declare function buildAuthHeader(clientInfo: ClientInfo, token?: string): string;
504
+ declare class HttpTransport {
505
+ private serverUrl;
506
+ private token;
507
+ private clientInfo;
508
+ private fetchFn;
509
+ private onUnauthorized?;
510
+ constructor(options: {
511
+ serverUrl?: string;
512
+ token?: string;
513
+ clientInfo: ClientInfo;
514
+ fetch?: typeof fetch;
515
+ onUnauthorized?: () => void;
516
+ });
517
+ setServerUrl(url: string): void;
518
+ getServerUrl(): string;
519
+ setToken(token: string): void;
520
+ getToken(): string;
521
+ setClientInfo(info: Partial<ClientInfo>): void;
522
+ getClientInfo(): ClientInfo;
523
+ setOnUnauthorized(handler?: () => void): void;
524
+ getAuthHeader(): string;
525
+ requestRaw(endpoint: string, options?: RequestOptions): Promise<Response>;
526
+ request<T = unknown>(endpoint: string, options?: RequestOptions): Promise<T>;
527
+ requestText(endpoint: string, options?: RequestOptions): Promise<string>;
528
+ requestBlob(endpoint: string, options?: RequestOptions): Promise<Blob>;
529
+ }
530
+
531
+ declare class AuthModule {
532
+ private http;
533
+ private currentUser;
534
+ private currentUserId;
535
+ private currentUsername;
536
+ constructor(http: HttpTransport, userId?: string);
537
+ getUserId(): string;
538
+ setUserId(id: string): void;
539
+ getUsername(): string;
540
+ getCurrentUser(): UserDto | null;
541
+ setCurrentUser(user: UserDto | null): void;
542
+ /**
543
+ * Authenticate with the Jellyfin server using username and password.
544
+ */
545
+ authenticateByName(username: string, password?: string): Promise<AuthenticationResult>;
546
+ /**
547
+ * Report client capabilities to the Jellyfin server.
548
+ */
549
+ reportCapabilities(capabilities?: ClientCapabilities): Promise<void>;
550
+ /**
551
+ * Build the user profile avatar image URL.
552
+ */
553
+ getUserImageUrl(userId?: string, tag?: string): string;
554
+ /**
555
+ * Clear active user credentials and token.
556
+ */
557
+ logout(): void;
558
+ }
559
+
560
+ /**
561
+ * Parses a semantic version string (e.g. "10.9.11", "12.0.0", "12.0.0-rc1") into numeric components.
562
+ */
563
+ declare function parseSemVer(version: string): {
564
+ major: number;
565
+ minor: number;
566
+ patch: number;
567
+ } | null;
568
+ /**
569
+ * Checks if currentVersion is greater than or equal to targetVersion.
570
+ */
571
+ declare function isVersionAtLeast(currentVersion: string, targetVersion: string): boolean;
572
+ /**
573
+ * Checks if the given version string represents Jellyfin 12.0.0 or higher.
574
+ */
575
+ declare function isV12OrHigher(version?: string): boolean;
576
+ declare class SystemModule {
577
+ private http;
578
+ private serverVersion;
579
+ private targetVersion;
580
+ constructor(http: HttpTransport, options?: {
581
+ serverVersion?: string;
582
+ targetVersion?: 'auto' | '10' | '12';
583
+ });
584
+ /**
585
+ * Get public system info without requiring authentication.
586
+ */
587
+ getPublicInfo(): Promise<PublicSystemInfo>;
588
+ /**
589
+ * Get full system info (requires authentication).
590
+ */
591
+ getInfo(): Promise<SystemInfo>;
592
+ /**
593
+ * Get the cached or explicitly configured server version string.
594
+ */
595
+ getVersion(): string | null;
596
+ /**
597
+ * Manually set or override the server version.
598
+ */
599
+ setVersion(version: string | null): void;
600
+ /**
601
+ * Get the configured target compatibility mode.
602
+ */
603
+ getTargetVersion(): 'auto' | '10' | '12';
604
+ /**
605
+ * Set target compatibility mode.
606
+ */
607
+ setTargetVersion(target: 'auto' | '10' | '12'): void;
608
+ /**
609
+ * Detects and caches the server version by calling /System/Info/Public.
610
+ */
611
+ detectVersion(): Promise<string | null>;
612
+ /**
613
+ * Checks whether the current server is Jellyfin 12 or higher.
614
+ * If targetVersion is explicitly set to '12' or '10', that preference is honored.
615
+ * If 'auto', resolves against known version or attempts detection.
616
+ */
617
+ isV12(): Promise<boolean>;
618
+ /**
619
+ * Synchronously checks if the server is known to be v12+ based on cached version or target setting.
620
+ * Defaults to true (modern behavior) if unknown.
621
+ */
622
+ isV12Sync(): boolean;
623
+ }
624
+
625
+ declare class LibraryModule {
626
+ private http;
627
+ private getUserId;
628
+ constructor(http: HttpTransport, getUserId: () => string);
629
+ private requireUserId;
630
+ /**
631
+ * Get list of music library views (folders) for the current user.
632
+ */
633
+ getMusicLibraries(): Promise<BaseItemDto[]>;
634
+ /**
635
+ * Get list of video library views (movies, tv shows, home videos) for the current user.
636
+ */
637
+ getVideoLibraries(): Promise<BaseItemDto[]>;
638
+ /**
639
+ * Get music albums.
640
+ */
641
+ getAlbums(options?: GetAlbumsOptions): Promise<ItemsResponse>;
642
+ /**
643
+ * Get music artists.
644
+ */
645
+ getArtists(options?: GetArtistsOptions): Promise<ItemsResponse>;
646
+ /**
647
+ * Get audio songs/tracks.
648
+ */
649
+ getSongs(options?: GetSongsOptions): Promise<ItemsResponse>;
650
+ /**
651
+ * Get favorite songs/tracks for the current user.
652
+ */
653
+ getFavoriteSongs(options?: Omit<GetSongsOptions, 'isFavorite'>): Promise<ItemsResponse>;
654
+ /**
655
+ * Get movies for the current user.
656
+ */
657
+ getMovies(options?: GetMoviesOptions): Promise<ItemsResponse>;
658
+ /**
659
+ * Get TV series for the current user.
660
+ */
661
+ getSeries(options?: GetSeriesOptions): Promise<ItemsResponse>;
662
+ /**
663
+ * Get seasons for a given TV series.
664
+ */
665
+ getSeasons(seriesId: string, options?: GetSeasonsOptions): Promise<ItemsResponse>;
666
+ /**
667
+ * Get episodes for a TV series or specific season.
668
+ */
669
+ getEpisodes(seriesId?: string, seasonId?: string, options?: GetEpisodesOptions): Promise<ItemsResponse>;
670
+ /**
671
+ * General query for video items (movies, episodes, videos).
672
+ */
673
+ getVideos(options?: GetVideosOptions): Promise<ItemsResponse>;
674
+ /**
675
+ * Request media playback information for an item (sources, streams, play session).
676
+ */
677
+ getPlaybackInfo(itemId: string, options?: PlaybackInfoOptions): Promise<PlaybackInfoResponse>;
678
+ /**
679
+ * Get single item details by its Jellyfin ID.
680
+ */
681
+ getItem(itemId: string): Promise<BaseItemDto | null>;
682
+ /**
683
+ * Search Jellyfin library for songs, albums, artists, playlists, movies, or series.
684
+ */
685
+ search(query: string, options?: SearchOptions): Promise<ItemsResponse>;
686
+ }
687
+
688
+ declare class PlaylistsModule {
689
+ private http;
690
+ private getUserId;
691
+ constructor(http: HttpTransport, getUserId: () => string);
692
+ private requireUserId;
693
+ /**
694
+ * Get all playlists for the current user.
695
+ */
696
+ getPlaylists(): Promise<ItemsResponse>;
697
+ /**
698
+ * Get items belonging to a specific playlist.
699
+ */
700
+ getPlaylistItems(playlistId: string): Promise<ItemsResponse>;
701
+ /**
702
+ * Create a new playlist.
703
+ * Jellyfin 12 requires a JSON request body with CreatePlaylistDto.
704
+ * Falls back to legacy query parameters if server returns 400/415.
705
+ */
706
+ createPlaylist(options: CreatePlaylistOptions): Promise<string>;
707
+ /**
708
+ * Update playlist metadata (e.g. name).
709
+ * Jellyfin 12 removed POST /Playlists/{id}; item updates use POST /Items/{id},
710
+ * which is also supported across older Jellyfin versions.
711
+ */
712
+ updatePlaylist(playlistId: string, options: UpdatePlaylistOptions): Promise<void>;
713
+ /**
714
+ * Upload custom cover image for a playlist.
715
+ */
716
+ uploadPlaylistImage(playlistId: string, base64ImageString: string, mimeType?: string): Promise<void>;
717
+ /**
718
+ * Delete a playlist.
719
+ */
720
+ deletePlaylist(playlistId: string): Promise<void>;
721
+ /**
722
+ * Add tracks to an existing playlist.
723
+ */
724
+ addTracks(playlistId: string, trackIds: string | string[]): Promise<void>;
725
+ /**
726
+ * Remove a track from a playlist by playlist entry ID or track ID.
727
+ */
728
+ removeTrack(playlistId: string, entryIdOrTrackId: string): Promise<void>;
729
+ /**
730
+ * Remove a specific playlist item by its unique entry ID (PlaylistItemId).
731
+ * Especially recommended on Jellyfin 12+ when playlists contain duplicate tracks.
732
+ */
733
+ removePlaylistItem(playlistId: string, playlistItemId: string): Promise<void>;
734
+ }
735
+
736
+ declare class PlaybackModule {
737
+ private http;
738
+ constructor(http: HttpTransport);
739
+ /**
740
+ * Report to the Jellyfin server that playback has started for an item.
741
+ */
742
+ reportStart(itemId: string, positionTicks?: number): Promise<void>;
743
+ /**
744
+ * Report current playback progress to the Jellyfin server.
745
+ */
746
+ reportProgress(itemId: string, positionTicks?: number, isPaused?: boolean): Promise<void>;
747
+ /**
748
+ * Report that playback has stopped for an item.
749
+ */
750
+ reportStopped(itemId: string, positionTicks?: number): Promise<void>;
751
+ }
752
+
753
+ declare class MediaModule {
754
+ private http;
755
+ private getUserId;
756
+ constructor(http: HttpTransport, getUserId: () => string);
757
+ /**
758
+ * Constructs the URL for an item's image/artwork.
759
+ * If the item lacks images or server is not set, returns options.fallbackUrl or null.
760
+ */
761
+ getArtworkUrl(itemOrId: BaseItemDto | string | null | undefined, options?: ArtworkUrlOptions): string | null;
762
+ /**
763
+ * Constructs the audio stream URL using Jellyfin's universal audio endpoint.
764
+ * Transparently negotiates codecs (direct play or transcode to MP3/AAC as needed).
765
+ */
766
+ getAudioStreamUrl(itemId: string, options?: AudioStreamOptions): string;
767
+ /**
768
+ * Constructs the HLS master playlist URL for an audio stream.
769
+ */
770
+ getAudioHlsStreamUrl(itemId: string, options?: AudioHlsStreamOptions): string;
771
+ /**
772
+ * Constructs the progressive/universal video stream URL.
773
+ * Supports direct play (static=true) or on-the-fly transcoding with quality, audio, and subtitle options.
774
+ */
775
+ getVideoStreamUrl(itemId: string, options?: VideoStreamOptions): string;
776
+ /**
777
+ * Constructs the HLS master playlist URL for an adaptive video stream.
778
+ */
779
+ getVideoHlsStreamUrl(itemId: string, options?: VideoHlsStreamOptions): string;
780
+ /**
781
+ * Constructs the URL for streaming a specific subtitle track.
782
+ */
783
+ getSubtitleUrl(itemId: string, mediaSourceId: string, subtitleStreamIndex: number, options?: SubtitleUrlOptions): string;
784
+ /**
785
+ * Fetches subtitle content as raw text (e.g. WebVTT or SRT format).
786
+ */
787
+ getSubtitles(itemId: string, mediaSourceId: string, subtitleStreamIndex: number, options?: SubtitleUrlOptions): Promise<string>;
788
+ /**
789
+ * Extracts and normalizes subtitle streams from an item or media source into SubtitleTrackInfo objects with URLs.
790
+ */
791
+ getSubtitleTracks(itemOrMediaSource: BaseItemDto | MediaSourceInfo): SubtitleTrackInfo[];
792
+ /**
793
+ * Constructs the direct download URL for an original, unmodified media file on the Jellyfin server.
794
+ */
795
+ getDownloadUrl(itemId: string, options?: DownloadUrlOptions): string;
796
+ /**
797
+ * Downloads a media file as a Blob with optional progress monitoring.
798
+ */
799
+ downloadFile(itemId: string, options?: {
800
+ onProgress?: (progressFraction: number) => void;
801
+ useQueryToken?: boolean;
802
+ }): Promise<Blob>;
803
+ /**
804
+ * Returns authentication headers for media streaming requests (e.g., configuring hls.js xhrSetup).
805
+ * Crucial for Jellyfin 12+ servers where query-based auth (?api_key=) is disabled.
806
+ */
807
+ getStreamHeaders(): Record<string, string>;
808
+ }
809
+
810
+ declare class LyricsModule {
811
+ private http;
812
+ constructor(http: HttpTransport);
813
+ /**
814
+ * Fetch synced or unsynced lyrics for an audio item.
815
+ */
816
+ getLyrics(itemId: string): Promise<LyricsDto | null>;
817
+ }
818
+
819
+ declare class FavoritesModule {
820
+ private http;
821
+ private getUserId;
822
+ constructor(http: HttpTransport, getUserId: () => string);
823
+ private requireUserId;
824
+ /**
825
+ * Mark an item as favorite.
826
+ */
827
+ markFavorite(itemId: string): Promise<void>;
828
+ /**
829
+ * Unmark an item as favorite.
830
+ */
831
+ unmarkFavorite(itemId: string): Promise<void>;
832
+ }
833
+
834
+ interface DownloadRecord {
835
+ id: string;
836
+ name: string;
837
+ mediaType?: 'Audio' | 'Video' | string;
838
+ type?: string;
839
+ artists?: string;
840
+ album?: string;
841
+ albumId?: string;
842
+ seriesName?: string;
843
+ seriesId?: string;
844
+ seasonName?: string;
845
+ seasonId?: string;
846
+ artworkUrl: string | null;
847
+ size: number;
848
+ savedAt: number;
849
+ hasLyrics?: boolean;
850
+ parentId?: string;
851
+ parentName?: string;
852
+ parentType?: string;
853
+ parentArtworkUrl?: string;
854
+ parentOwner?: string;
855
+ parentCount?: number;
856
+ index?: number;
857
+ blob?: Blob;
858
+ mimeType?: string;
859
+ }
860
+ interface DownloadProgress {
861
+ completed: number;
862
+ total: number;
863
+ item: BaseItemDto;
864
+ track?: BaseItemDto;
865
+ res: {
866
+ ok: boolean;
867
+ size?: number;
868
+ removed?: boolean;
869
+ error?: string;
870
+ };
871
+ }
872
+ declare class OfflineStorageManager {
873
+ private media;
874
+ private dbName;
875
+ private dbVersion;
876
+ private storeName;
877
+ private dbPromise;
878
+ private objectUrlCache;
879
+ private downloadStatusCache;
880
+ constructor(media: MediaModule, dbName?: string, dbVersion?: number, storeName?: string);
881
+ isSupported(): boolean;
882
+ initDB(): Promise<IDBDatabase | null>;
883
+ private getItemKey;
884
+ private dispatchDownloadChanged;
885
+ private revokeObjectUrl;
886
+ getDownloadedRecord(id: string): Promise<DownloadRecord | null>;
887
+ isItemDownloaded(id: string): Promise<boolean>;
888
+ isItemDownloadedSync(id: string): boolean;
889
+ isTrackDownloaded(id: string): Promise<boolean>;
890
+ isTrackDownloadedSync(id: string): boolean;
891
+ getDownloadedBlobUrl(id: string): Promise<string | null>;
892
+ getDownloadedBlobUrlSync(id: string): string | null;
893
+ getAllDownloads(): Promise<DownloadRecord[]>;
894
+ warmOfflineCache(): Promise<void>;
895
+ saveDownloadRecord(record: DownloadRecord, blob: Blob): Promise<boolean>;
896
+ removeDownload(id: string): Promise<boolean>;
897
+ /**
898
+ * Downloads an audio or video item to offline storage.
899
+ * If already downloaded, toggles it off (removes it).
900
+ */
901
+ downloadItem(item: BaseItemDto, onProgress?: (progressFraction: number) => void, group?: {
902
+ id?: string;
903
+ name?: string;
904
+ type?: string;
905
+ artworkUrl?: string;
906
+ owner?: string;
907
+ count?: number;
908
+ } | null, index?: number, options?: DownloadItemOptions): Promise<{
909
+ ok: boolean;
910
+ size?: number;
911
+ removed?: boolean;
912
+ error?: string;
913
+ }>;
914
+ /**
915
+ * Backward-compatible alias for downloadItem.
916
+ */
917
+ downloadTrack(track: BaseItemDto, onProgress?: (progressFraction: number) => void, group?: {
918
+ id?: string;
919
+ name?: string;
920
+ type?: string;
921
+ artworkUrl?: string;
922
+ owner?: string;
923
+ count?: number;
924
+ } | null, index?: number): Promise<{
925
+ ok: boolean;
926
+ size?: number;
927
+ removed?: boolean;
928
+ error?: string;
929
+ }>;
930
+ /**
931
+ * Downloads multiple items with aggregated progress callbacks.
932
+ */
933
+ downloadItems(items: BaseItemDto[], onProgress?: (progress: DownloadProgress) => void, group?: {
934
+ id?: string;
935
+ name?: string;
936
+ type?: string;
937
+ artworkUrl?: string;
938
+ owner?: string;
939
+ count?: number;
940
+ } | null, options?: DownloadItemOptions): Promise<{
941
+ ok: boolean;
942
+ downloaded: number;
943
+ failed: number;
944
+ total: number;
945
+ }>;
946
+ /**
947
+ * Backward-compatible alias for downloadItems.
948
+ */
949
+ downloadTracks(tracks: BaseItemDto[], onProgress?: (progress: DownloadProgress) => void, group?: {
950
+ id?: string;
951
+ name?: string;
952
+ type?: string;
953
+ artworkUrl?: string;
954
+ owner?: string;
955
+ count?: number;
956
+ } | null): Promise<{
957
+ ok: boolean;
958
+ downloaded: number;
959
+ failed: number;
960
+ total: number;
961
+ }>;
962
+ removeDownloads(items: BaseItemDto[]): Promise<{
963
+ ok: boolean;
964
+ removed: number;
965
+ }>;
966
+ formatBytes(bytes: number): string;
967
+ }
968
+
969
+ interface CacheRecord<T = unknown> {
970
+ key: string;
971
+ data: T;
972
+ timestamp: number;
973
+ }
974
+ interface CacheAdapter {
975
+ get<T = unknown>(key: string): Promise<T | null> | T | null;
976
+ set<T = unknown>(key: string, data: T): Promise<void> | void;
977
+ delete(key: string): Promise<void> | void;
978
+ clear(): Promise<void> | void;
979
+ }
980
+ declare class MemoryCacheAdapter implements CacheAdapter {
981
+ private cache;
982
+ get<T = unknown>(key: string): T | null;
983
+ set<T = unknown>(key: string, data: T): void;
984
+ delete(key: string): void;
985
+ clear(): void;
986
+ }
987
+ declare class IndexedDBCacheAdapter implements CacheAdapter {
988
+ private dbName;
989
+ private dbVersion;
990
+ private storeName;
991
+ private dbPromise;
992
+ constructor(dbName?: string, dbVersion?: number, storeName?: string);
993
+ private getDB;
994
+ get<T = unknown>(key: string): Promise<T | null>;
995
+ set<T = unknown>(key: string, data: T): Promise<void>;
996
+ delete(key: string): Promise<void>;
997
+ clear(): Promise<void>;
998
+ }
999
+ /**
1000
+ * Executes a Stale-While-Revalidate pattern using a CacheAdapter.
1001
+ */
1002
+ declare function fetchWithCache<T>(cache: CacheAdapter, cacheKey: string, fetchFn: () => Promise<T>, onFreshData?: (data: T) => void): Promise<T>;
1003
+
1004
+ type ClientEventType = 'unauthorized' | 'authenticated' | 'logout';
1005
+ type ClientEventListener = (...args: unknown[]) => void;
1006
+ declare class JellyfinClient {
1007
+ readonly auth: AuthModule;
1008
+ readonly system: SystemModule;
1009
+ readonly library: LibraryModule;
1010
+ readonly playlists: PlaylistsModule;
1011
+ readonly playback: PlaybackModule;
1012
+ readonly media: MediaModule;
1013
+ readonly lyrics: LyricsModule;
1014
+ readonly favorites: FavoritesModule;
1015
+ readonly offline: OfflineStorageManager;
1016
+ private http;
1017
+ private storage;
1018
+ private cache;
1019
+ private clientInfo;
1020
+ private eventListeners;
1021
+ constructor(options?: JellyfinClientOptions);
1022
+ get serverUrl(): string;
1023
+ set serverUrl(url: string);
1024
+ get accessToken(): string;
1025
+ set accessToken(token: string);
1026
+ get userId(): string;
1027
+ set userId(id: string);
1028
+ get serverVersion(): string | null;
1029
+ set serverVersion(version: string | null);
1030
+ /**
1031
+ * Check whether the connected Jellyfin server is version 12.0 or higher.
1032
+ */
1033
+ isV12(): Promise<boolean>;
1034
+ /**
1035
+ * Query server and detect the server version via /System/Info/Public.
1036
+ */
1037
+ detectServerVersion(): Promise<string | null>;
1038
+ get info(): ClientInfo;
1039
+ setClientInfo(info: Partial<ClientInfo>): void;
1040
+ getCache(): CacheAdapter;
1041
+ setCache(cache: CacheAdapter): void;
1042
+ getStorage(): StorageAdapter;
1043
+ setStorage(storage: StorageAdapter): void;
1044
+ on(event: ClientEventType, listener: ClientEventListener): () => void;
1045
+ off(event: ClientEventType, listener: ClientEventListener): void;
1046
+ emit(event: ClientEventType, ...args: unknown[]): void;
1047
+ /**
1048
+ * Authenticate with username and password, update client state, and emit 'authenticated'.
1049
+ */
1050
+ authenticate(username: string, password?: string): Promise<AuthenticationResult>;
1051
+ /**
1052
+ * Log out and clear tokens and session.
1053
+ */
1054
+ logout(): void;
1055
+ /**
1056
+ * Manually set authentication credentials.
1057
+ */
1058
+ setCredentials(credentials: {
1059
+ serverUrl?: string;
1060
+ accessToken: string;
1061
+ userId: string;
1062
+ }): void;
1063
+ }
1064
+
1065
+ declare class MemoryStorage implements StorageAdapter {
1066
+ private store;
1067
+ getItem(key: string): string | null;
1068
+ setItem(key: string, value: string): void;
1069
+ removeItem(key: string): void;
1070
+ clear(): void;
1071
+ }
1072
+ declare class LocalStorageAdapter implements StorageAdapter {
1073
+ getItem(key: string): string | null;
1074
+ setItem(key: string, value: string): void;
1075
+ removeItem(key: string): void;
1076
+ }
1077
+ declare function getDefaultStorage(): StorageAdapter;
1078
+ declare function generateDeviceId(): string;
1079
+
1080
+ declare class JellyfinError extends Error {
1081
+ constructor(message: string);
1082
+ }
1083
+ declare class JellyfinApiError extends JellyfinError {
1084
+ readonly status: number;
1085
+ readonly endpoint?: string;
1086
+ constructor(message: string, status: number, endpoint?: string);
1087
+ }
1088
+ declare class JellyfinAuthError extends JellyfinApiError {
1089
+ constructor(message?: string, status?: number, endpoint?: string);
1090
+ }
1091
+
1092
+ export { AUDIO_QUALITY_PRESETS, type ArtworkUrlOptions, type AudioHlsStreamOptions, type AudioQualityOption, type AudioQualityPresetKey, type AudioStreamOptions, AuthModule, type AuthenticationResult, type BaseItemDto, type CacheAdapter, type CacheRecord, type ClientCapabilities, type ClientEventListener, type ClientEventType, type ClientInfo, type CreatePlaylistDto, type CreatePlaylistOptions, type DownloadItemOptions, type DownloadProgress, type DownloadRecord, type DownloadUrlOptions, FavoritesModule, type GetAlbumsOptions, type GetArtistsOptions, type GetEpisodesOptions, type GetMoviesOptions, type GetSeasonsOptions, type GetSeriesOptions, type GetSongsOptions, type GetVideosOptions, HttpTransport, IndexedDBCacheAdapter, type ItemsResponse, JellyfinApiError, JellyfinAuthError, JellyfinClient, type JellyfinClientOptions, JellyfinError, LibraryModule, LocalStorageAdapter, type LyricLine, type LyricsDto, LyricsModule, MediaModule, type MediaSourceInfo, type MediaStreamInfo, MemoryCacheAdapter, MemoryStorage, OfflineStorageManager, type PlaybackInfoOptions, type PlaybackInfoResponse, PlaybackModule, PlaylistsModule, type PublicSystemInfo, type RequestOptions, type SearchOptions, type StorageAdapter, type SubtitleTrackInfo, type SubtitleUrlOptions, type SystemInfo, SystemModule, type UpdatePlaylistOptions, type UserDto, type UserItemDataDto, VIDEO_QUALITY_PRESETS, type VideoHlsStreamOptions, type VideoQualityOption, type VideoQualityPresetKey, type VideoStreamOptions, buildAuthHeader, cleanUrl, fetchWithCache, formatBitrate, generateDeviceId, getAudioQualityList, getDefaultStorage, getVideoQualityList, isV12OrHigher, isVersionAtLeast, parseSemVer, resolveAudioQuality, resolveVideoQuality };