@francofantomius/jellyfin 0.1.0 → 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.
package/README.md CHANGED
@@ -3,8 +3,12 @@
3
3
  A modern, lightweight, modular, and type-safe Jellyfin SDK for Node.js and the Browser.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@francofantomius/jellyfin.svg)](https://www.npmjs.com/package/@francofantomius/jellyfin)
6
+ [![Documentation](https://img.shields.io/badge/docs-Material%20Design%203-6f42c1.svg)](https://francofantomius.github.io/jellyfin-sdk/)
6
7
  [![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
7
8
 
9
+ **Current Version: `v0.4.0`** (THE PROJECT IS BEING ACTIVELY DEVELOPED. WAIT FOR VERSION 0.5.0 TO USE IT)
10
+
11
+
8
12
  ---
9
13
 
10
14
  ## Features
@@ -15,12 +19,25 @@ A modern, lightweight, modular, and type-safe Jellyfin SDK for Node.js and the B
15
19
  - **Clean modular architecture**:
16
20
  - `client.auth` - Server authentication, user profiles, capabilities reporting.
17
21
  - `client.library` - Browse music and video libraries (movies, series, seasons, episodes, videos, search, playback info).
22
+ - `client.search` - Dedicated universal search with granular item type, genre, year, and library view scoping.
18
23
  - `client.media` - Universal audio and video stream URLs, HLS playlists, subtitles, direct downloads, and responsive artwork.
19
24
  - `client.playlists` - Create, edit, delete playlists, manage tracks, and upload cover images.
20
25
  - `client.playback` - Report playback start, progress, and stop to Jellyfin for scrobbling and playback sync.
21
26
  - `client.lyrics` - Fetch synced or unsynced song lyrics.
22
27
  - `client.favorites` - Toggle favorite items.
23
28
  - `client.offline` - Browser IndexedDB media download manager for offline audio and video playback.
29
+ - `client.resume` - Continue watching / resume items querying (`/UserItems/Resume`).
30
+ - `client.nextUp` - Next unplayed TV show episodes (`/Shows/NextUp`).
31
+ - `client.latest` - Recently added media (movies, episodes, albums) (`/Users/{userId}/Items/Latest`).
32
+ - `client.transcode` - Teardown active transcoding sessions (`/Videos/ActiveEncodings`).
33
+ - `client.websocket` - Real-time WebSocket event streaming, keep-alive heartbeat, and automated reconnection.
34
+ - `client.sessions` - Remote control active sessions, playback commands, volume adjustment, and message modals.
35
+ - `client.quickConnect` - Quick Connect pairing flow for TVs and secondary devices.
36
+ - `client.trickplay` - Jellyfin 10.9+ trickplay HLS tile manifests, image tiles, and scrubbing thumbnail coordinate calculations.
37
+ - `client.chapters` - Chapter navigation, preview thumbnails, typed MediaSegments, and intro/credits skipping.
38
+ - `client.genres` - Video genres, music genres, and production studios browsing.
39
+ - `client.collections` - BoxSet collection querying, creation, and item membership management.
40
+ - `client.displayPreferences` - Persist and retrieve view types, sorting configurations, and custom client UI preferences via `/DisplayPreferences/{id}`.
24
41
  - **Quality Settings & Presets**: Standard video (4K, 1080p, 720p, 480p, 360p, direct) and audio (320k, 256k, 192k, 128k, direct) presets and resolution utilities.
25
42
  - **Subtitles**: Direct VTT/SRT subtitle streaming URLs, raw text fetching, and automated track extraction from media metadata.
26
43
  - **Direct Downloads**: Server file download URLs, progress-tracked file downloads, and offline caching.
@@ -280,6 +297,238 @@ client.on('unauthorized', () => {
280
297
 
281
298
  ---
282
299
 
300
+ ### 11. Dashboard, Continue Watching & Next Up
301
+
302
+ ```typescript
303
+ // Fetch in-progress items for Continue Watching carousels
304
+ const resume = await client.resume.getResumeItems({
305
+ limit: 10,
306
+ mediaTypes: ['Video']
307
+ });
308
+ console.log('Continue watching:', resume.Items);
309
+
310
+ // Fetch the next unplayed episodes for followed series
311
+ const nextUp = await client.nextUp.getNextUp({
312
+ limit: 12,
313
+ enableTotalRecordCount: true
314
+ });
315
+ console.log('Next up episodes:', nextUp.Items);
316
+
317
+ // Query recently added media across libraries or specific types
318
+ const latestMovies = await client.latest.getLatestMovies({ limit: 10 });
319
+ const latestEpisodes = await client.latest.getLatestEpisodes({ limit: 10 });
320
+ const latestAlbums = await client.latest.getLatestAlbums({ limit: 10 });
321
+ ```
322
+
323
+ ---
324
+
325
+ ### 12. Active Transcode Session Teardown
326
+
327
+ ```typescript
328
+ const playSessionId = 'playback-session-id';
329
+
330
+ // Teardown active server transcoding to terminate lingering FFmpeg processes
331
+ await client.transcode.stopActiveEncoding(playSessionId);
332
+
333
+ // Or automatically teardown during playback stop reporting:
334
+ await client.playback.reportStopped(movieId, currentTicks, { playSessionId });
335
+ ```
336
+
337
+ ---
338
+
339
+ ### 13. Universal & Scoped Search
340
+
341
+ ```typescript
342
+ // Universal search across all items
343
+ const results = await client.search.search('Inception', {
344
+ includeItemTypes: ['Movie', 'Series'],
345
+ genres: ['Sci-Fi'],
346
+ limit: 20
347
+ });
348
+
349
+ // Search within a specific library folder
350
+ const musicResults = await client.search.searchInLibrary('music-library-id', 'Queen');
351
+
352
+ // Media-specific search shortcuts
353
+ const songs = await client.search.searchSongs('Yellow');
354
+ const albums = await client.search.searchAlbums('Parachutes');
355
+ const movies = await client.search.searchMovies('Interstellar');
356
+ const series = await client.search.searchSeries('Breaking Bad');
357
+ ```
358
+
359
+ ---
360
+
361
+ ### 14. Real-time WebSocket Event Streaming
362
+
363
+ ```typescript
364
+ // Connect to real-time WebSocket event feed
365
+ client.websocket.connect({
366
+ autoReconnect: true,
367
+ keepAliveIntervalMs: 30000
368
+ });
369
+
370
+ // Listen to connection state
371
+ client.websocket.on('open', () => console.log('WebSocket connected'));
372
+ client.websocket.on('close', (code, reason) => console.log('WebSocket closed', code, reason));
373
+
374
+ // Listen for library updates (scanned/added items)
375
+ client.websocket.on('libraryChanged', (data) => {
376
+ console.log('Library changed. Items added:', data.ItemsAdded);
377
+ });
378
+
379
+ // Listen for user data updates (played state, favorites)
380
+ client.websocket.on('userDataChanged', (data) => {
381
+ console.log('User data changed for user:', data.UserId);
382
+ });
383
+
384
+ // Subscribe to live session updates across the server
385
+ client.websocket.startSessionsSubscription(2000);
386
+ client.websocket.on('sessions', (sessions) => {
387
+ console.log('Active server sessions:', sessions);
388
+ });
389
+ ```
390
+
391
+ ---
392
+
393
+ ### 15. Remote Control & Sessions Management
394
+
395
+ ```typescript
396
+ // Query all active sessions
397
+ const sessions = await client.sessions.getSessions();
398
+ const targetSession = sessions.find((s) => s.DeviceName === 'Living Room TV');
399
+
400
+ if (targetSession) {
401
+ // Remote playback control
402
+ await client.sessions.play(targetSession.Id, ['movie-id-1'], {
403
+ playCommand: 'PlayNow',
404
+ startPositionTicks: 0
405
+ });
406
+
407
+ // Playback commands
408
+ await client.sessions.pause(targetSession.Id);
409
+ await client.sessions.playPause(targetSession.Id);
410
+ await client.sessions.seek(targetSession.Id, 120_000_000); // 12 seconds in ticks
411
+
412
+ // Volume control
413
+ await client.sessions.setVolume(targetSession.Id, 75);
414
+ await client.sessions.toggleMute(targetSession.Id);
415
+
416
+ // Send an on-screen dialog message
417
+ await client.sessions.sendMessage(targetSession.Id, {
418
+ header: 'Notification',
419
+ text: 'Dinner is ready in 5 minutes!',
420
+ timeoutMs: 8000
421
+ });
422
+
423
+ // Instruct session to navigate to an item
424
+ await client.sessions.viewItem(targetSession.Id, 'Movie', 'movie-id-1', 'Inception');
425
+ }
426
+ ```
427
+
428
+ ---
429
+
430
+ ### 16. Quick Connect Device Pairing Flow
431
+
432
+ ```typescript
433
+ // On a secondary device (e.g. Smart TV or CLI app):
434
+ if (await client.quickConnect.isEnabled()) {
435
+ const { Code, Secret } = await client.quickConnect.initiate();
436
+ console.log(`Enter this code on your phone/PC: ${Code}`);
437
+
438
+ // Automatically poll until authorized
439
+ const state = await client.quickConnect.poll(Secret, { intervalMs: 2000, timeoutMs: 120000 });
440
+ if (state.Authenticated && state.AuthenticationToken) {
441
+ client.accessToken = state.AuthenticationToken;
442
+ if (state.UserId) client.userId = state.UserId;
443
+ console.log('Successfully authenticated via Quick Connect!');
444
+ }
445
+ }
446
+
447
+ // On an already authenticated device (e.g. phone or PC):
448
+ await client.quickConnect.authorize('123 456');
449
+ console.log('Device authorized!');
450
+ ```
451
+
452
+ ---
453
+
454
+ ### 17. Trickplay & Scrubbing Thumbnails
455
+
456
+ ```typescript
457
+ // Fetch manifest and available resolutions
458
+ const item = await client.library.getItem('video-id');
459
+ const resolutions = client.trickplay.getAvailableResolutions(item); // e.g. [320]
460
+
461
+ // Calculate exact sprite coordinates for scrubbing seekbar
462
+ const thumbnail = client.trickplay.getThumbnailForTimestamp({
463
+ item,
464
+ timestampMs: 45000, // 45 seconds into the video
465
+ width: 320
466
+ });
467
+
468
+ if (thumbnail) {
469
+ console.log(`Image: ${thumbnail.imageUrl}`);
470
+ console.log(`Offset: x=${thumbnail.x}px, y=${thumbnail.y}px, size=${thumbnail.width}x${thumbnail.height}px`);
471
+ }
472
+ ```
473
+
474
+ ---
475
+
476
+ ### 18. Chapters & Intro / Credits Skipping
477
+
478
+ ```typescript
479
+ // Fetch item chapters and images
480
+ const chapters = await client.chapters.getChapters('episode-id');
481
+ const chapterImage = client.chapters.getChapterImageUrl('episode-id', 1, { maxWidth: 400 });
482
+
483
+ // Detect intro/credits from /MediaSegments or chapter heuristics
484
+ const markers = await client.chapters.getIntroCredits('episode-id');
485
+
486
+ // During playback, check if skip button should appear
487
+ const currentTicks = 850_000_000; // 85s
488
+ const activeSegment = client.chapters.findCurrentSegment(currentTicks, markers);
489
+ if (activeSegment?.type === 'Intro') {
490
+ const skipToTicks = client.chapters.getSkipPosition(currentTicks, markers);
491
+ console.log(`Skip Intro available -> Jump to ${skipToTicks / 10_000_000}s`);
492
+ }
493
+ ```
494
+
495
+ ---
496
+
497
+ ### 19. Genres, Studios & BoxSet Collections
498
+
499
+ ```typescript
500
+ // Browse genres and studios
501
+ const movieGenres = await client.genres.getGenres({ limit: 20 });
502
+ const rockMusic = await client.genres.getMusicGenre('Rock');
503
+ const studios = await client.genres.getStudios({ searchTerm: 'Universal' });
504
+
505
+ // Browse and manage BoxSet Collections
506
+ const collections = await client.collections.getCollections();
507
+ const newBoxSet = await client.collections.createCollection({
508
+ name: 'Alien Anthology',
509
+ ids: ['alien-1', 'alien-2']
510
+ });
511
+ await client.collections.addToCollection(newBoxSet.Id, ['alien-3', 'alien-4']);
512
+ await client.collections.removeFromCollection(newBoxSet.Id, 'alien-1');
513
+ ```
514
+
515
+ ---
516
+
517
+ ### 20. User Display Preferences
518
+
519
+ ```typescript
520
+ // Get folder/view UI preferences
521
+ const prefs = await client.displayPreferences.getDisplayPreferences('folder-id');
522
+
523
+ // Update view layout and sorting
524
+ await client.displayPreferences.setViewType('folder-id', 'Poster');
525
+ await client.displayPreferences.setSortPreferences('folder-id', 'CommunityRating', 'Descending');
526
+ await client.displayPreferences.setCustomPreference('folder-id', 'showBadges', 'true');
527
+ ```
528
+
529
+ ---
530
+
283
531
  ## License
284
532
 
285
533
  MIT © [Franco Fantomius](https://github.com/francofantomius)
534
+