Skip to content

v8.0.0

Latest

Choose a tag to compare

@github-actions github-actions released this 16 Oct 04:08
· 1 commit to master since this release
806a371

A big maintenance release. Requires Node 24, upgrades every dependency, turns on strict null types, finishes PlexClient, and fixes a batch of bugs that were silently returning wrong data. Everything landed in #60, which also rolled in #61, #62 and #63.

Upgrading from v7

Node.js 24 or newer is required.

Types are strict. strictNullChecks is on, so fields Plex can leave out are typed T | undefined. Expect new compile errors where code assumed a value was always there. PlexServer.query() and MyPlexAccount.query() return unknown unless you pass a type argument.

Positional arguments became options objects:

// v7
await account.device('Living Room');
await resource.connect(true, 10_000);
await device.connect(10_000);
await queue.removeItem(item, false);
await movie.updateProgress(90_000, 'paused');
await client.seekTo(1000, 'video');
client.proxyThroughServer(true, server);

// v8
await account.device({ name: 'Living Room' }); // or { clientIdentifier }
await resource.connect({ ssl: true, timeout: 10_000 });
await device.connect({ timeout: 10_000 });
await queue.removeItem(item, { refresh: false });
await movie.updateProgress({ time: 90_000, state: 'paused' });
await client.seekTo(1000, { type: 'video' });
client.proxyThroughServer({ server });

Other changes that may need code updates:

  • Music sections list artists by default. MusicSection is LibrarySection<Artist>, so all(), get(), search(), recentlyAdded() and collections() return Artist unless you pass a libtype.
  • onDeck() returns LibrarySearchItem[] on a generic section, Episode[] on shows and Track[] on music. MusicSection.stations() returns Playlist[].
  • Audio art and thumb are server paths. Use artUrl / thumbUrl for URLs with a token.
  • plex.tv devices come from the JSON API. MyPlexDevice.id is a number, connections is always an array, and MyPlexDevice no longer extends PlexObject.
  • Collection items need a type. Passing plain { ratingKey } objects to createCollection() throws BadRequest instead of guessing the section type.
Full list of breaking changes
  • PlexClient: Commands take { type } instead of a positional mtype and resolve to void. proxyThroughServer({ enabled, server }), query({ path, method, headers }), timelines({ wait }) and isPlayingMedia({ includePaused }) take options objects. isPlayingMedia() defaults includePaused to true and checks every timeline. createPlayQueue() uses the server the items came from. _baseurl, _token, _server and _proxyThroughServer are replaced by baseurl, server and isProxied. PlexOptions is now PlexClientOptions. ClientTimeline leaves missing values undefined instead of 0 or ''.
  • Connections: MyPlexResource.connect(ssl, timeout) and MyPlexDevice.connect(timeout) are connect({ timeout }).
  • MyPlexDevice: No longer extends PlexObject and is built from (account, data) with plex.tv's v2 device JSON. id is a number. version, productVersion, vendor, screenDensity and token are optional. connections is always an array.
  • Options objects: updateProgress(), updateTimeline(), PlayQueue.removeItem() and MyPlexAccount.device({ name } | { clientIdentifier }).
  • Library: MusicSection is LibrarySection<Artist>. onDeck() returns LibrarySearchItem[] (Episode[] for shows, Track[] for music). MusicSection.stations() returns Playlist[]. Regular collection items need a type.
  • Types:
    • query() on PlexServer and MyPlexAccount returns unknown by default. PartialPlexObject.delete() resolves to void.
    • Fields Plex omits are optional across Media, MediaPart, streams, Video, Movie, Show, Season, Episode, Collections, LibrarySection, Hub and SearchResult. PlexObject.key is optional and parent is a WeakRef<PlexObject>. thumbUrl, artUrl and resourceFilepath can return undefined.
    • Show and Episode originallyAvailableAt are optional instead of an Invalid Date. Playlist addedAt / updatedAt are optional. Collections addedAt / updatedAt are Dates. playQueueSelectedMetadataItemID is a string.
    • Marker and Chapter no longer extend MediaTag. Video.uploadPoster() requires url or file.
  • plex.tv: MyPlexServerSectionsResponse is replaced by MyPlexServerResponse and PLEXSERVERS points at the v2 endpoint. XML responses from MyPlexAccount.query() no longer wrap attributes in $, so the MyPlexUser, MyPlexInvite and MyPlexServerShare data types are flat.
  • Alerts: AlertListener._ws is a standard WebSocket, and connection errors carry the socket event as their cause.

New

  • setPlexHeaders({ product, version, identifier, ... }) so Plex lists your app under its own name and client identifier instead of PlexAPI.
  • PlexClient is a typed API: navigation, playback, streams, parameters, playMedia(), createPlayQueue() and timelines(). It works directly or through the server proxy, and handles players that answer in XML or plain text.
  • connectClient() on MyPlexResource and MyPlexDevice connects to a player instead of a server.
  • createPlayQueue() on collections and photo albums.
  • Fields that appear in real payloads were never loaded before and are now. Examples: Media container, videoResolution and audioProfile; AudioStream gainOffset and canNormalizeLoudness; slugs, audience ratings and network on videos; contentChangedAt on library sections.

Fixes

  • Every AudioStream value (channels, samplingRate, gain, loudness, ...) was always undefined.
  • season.reload() and section.reload() wiped every field, including ratingKey and key.
  • Music sections built Track objects for artist rows, and onDeck() built shows from episode rows.
  • Collections.create() in a music section made an empty artist collection, and playlist dates landed in 1970.
  • Episode.section() was flaky depending on garbage collection.
  • PlayQueue.removeItem() and clear() kept stale totals.
  • PlexClient.playMedia() could play the wrong queue item and never sent the server address, port, type or token.
  • MusicSection.stations() always returned undefined.
  • PlexServer.url() and PlexClient.url() dropped existing query params when adding the token.
  • MyPlexDevice.delete() threw for accounts created with new MyPlexAccount().
  • Importing a model module such as audio.ts before the package index built the item class map too early, so track lookups quietly fell back to the section's class.
  • Devices get their per-device tokens again. plex.tv's devices.xml had stopped sending them.
  • Show and episode air dates were an Invalid Date when Plex had none, and media flags such as optimizedForStreaming were 1 instead of true.

Dependencies

Runtime dependencies go from seven to four: fast-xml-parser, jose, ofetch and uint8array-extras.

  • ws is replaced by Node's built-in WebSocket.
  • @ctrl/mac-address is replaced by node:os, so client identifiers stay the same.
  • type-fest is dropped.
  • xml2js is replaced by fast-xml-parser, which only handles the plex.tv endpoints that have no JSON version (friends, invites, shared servers) and players that answer in XML.

Every other response is requested and parsed as JSON.

Full changelog: v7.1.0...v8.0.0