Skip to content

Optimize and reduce Jellyfin API calls and patch various issues - #267

Open
MattKercher wants to merge 2 commits into
Jeffser:mainfrom
MattKercher:feature/jellyfin-api-fixes
Open

Optimize and reduce Jellyfin API calls and patch various issues#267
MattKercher wants to merge 2 commits into
Jeffser:mainfrom
MattKercher:feature/jellyfin-api-fixes

Conversation

@MattKercher

@MattKercher MattKercher commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Summary

The goal of this PR is to further refine the Jellyfin integration, as well as fix some outstanding bugs.

This started as a way to optimize for #259 but even with that closed, the changes ended up being useful for a lot of Jellyfin efficiency gains. This PR gets rid of any network requests made to the server while the models are being processed in bulk so the initial page loading is faster. Although I prefer to avoid changing the base.py API, I added a minimal flag to the verify functions so rows/buttons can instruct the integration to load a leaner API call since they don't require as much data. From there, the verify functions now work to layer on new data as it's retrieved, instead of an all-or-nothing approach where it used to check simply if the model existed.

Notable Fixes

  • The Home page loads much faster, as it'll load when the initial default lists are returned and then fill in the missing API data as needed after the page is loaded.
  • The album pages load immediately, fixing an issue where songs couldn't be be added to the queue until rows were tediously loaded one by one.
  • The starred pages no longer overwhelm Jellyfin with API calls for coverArt. Previously the starred pages would request coverArt for every starred song/artist despite not being loaded by the UI, but now it only checks for cached images.
  • Fixed the systemSearch function so it will now check the album model for cover art when the song doesn't have it.
  • Fixed logins frequently failing due to ping function timing out too quickly.

Detailed Changes

  • Added a COVER_SIZE dict to constants.py to keep track of the two sizes for the covers, which can be called with COVER_SIZE["big"] for gdkPaintableBig and COVER_SIZE["small"] for gdkPaintable
  • Added a MediaType StrEnum to Jellyfin to hold onto the names of the different media types instead of passing around raw strings, which can be called with MediaType.ALBUM, MediaType.ARTIST, MediaType.SONG, and MediaType.PLAYLIST
  • Added a getCachedCoverArt function to bypass network calls so __bulk_compile can simply grab from the image cache and write the album art to the model if the cover art has already been cached without making a network call if it's not cached. (This also fixes an issue with Favorite Songs which used to slam my Jellyfin server because of the code I wrote where it'd try to fetch the cover art for every favorite song I had. At the same time. 馃珷)
  • Changed updateCoverArt to only fetch the 750 pixel cover art and compresses it using PIL on-device to 240 instead of making two API calls to the server for different sized cover art.
  • Added a minimal argument to the verify functions to instruct them to make leaner API calls when less data is necessary. This variable is set to True on all buttons and rows that call the verify functions. Note: I added minimal to the function headers in Navidrome and Local but they don't utilize it.
  • Changed the verify functions to split each network call into its own nested function for cleaner threading, with a fetch_all function to handle the logic. Note: Some functions use threading.Thread to call fetch_all to prevent the self.threads ThreadPoolExecutor from locking up waiting for a child thread to finish that wasn't able to execute because the pool executor queue ran out of workers.
  • Added self.ongoing_requests to track which requests are currently running to prevent duplicate calls to the same verify function. It's a dict that holds onto whether the current verify call is a minimal call so it can do a full API call if you load an album/artist/playlist page even if a minimal request is ongoing. Previously the functions would check model_id in self.loaded_models but since the verify functions can layer on more data as it's brought in, it needed a separate variable to track currently ongoing requests.
  • Change __bulk_verify to __bulk_compile as the prefetch code no longer uses the verify functions and instead processes the artist/album/song/playlist lists directly with a new __compile_response_json function.
  • Added __write_to_model function that takes a dict and writes it to the corresponding model_id. It only writes on the main thread using GLib.idle_add(). As multiple threads can write to the model simultaneously, PyGObject was throwing C reference counter assertion errors due to GObject not being memory safe. Using GLib.idle_add() has the dual benefit of making it so callbacks on the model variables that modify UI elements are now called from the main thread to reduce flickering and crashes.
  • As such, added a check to connect_to_model to check whether it's on the main thread so it prevents GLib.idle_add from being called from a background thread.
  • Added a fallback to AlbumArtists for Albums and Songs if the ArtistsItems list is empty in __compile_response_json
  • Fixed the systemSearch function so it will now check the album model for cover art when the song doesn't have it.
  • Added albumArtCheck variable to the Song model so it knows if it fetched the albumArt from the album object. This prevents the verifySong function from repeatedly trying to fetch the album art if the album object doesn't have cover art either.
  • Increased the timeout for POST requests so ping can run for longer when the server is being slow.

Additional Thoughts/Questions

force_update

As of right now, the verify functions in Jellyfin ignore the force_update argument. Every time you'd navigate to the artist, album, or playlist pages it'd force the model to dump all of its information and redownload it. How come this is the default behavior? I imagine the Navidrome or Local integrations rely on it for something. I wanted to ask before messing with it, so I had the Jellyfin integration ignore it for now (it'd be trivial to re-add to the fetch_all function).

Anyway, sorry for the giant PR description 馃檭 Thanks again for the awesome app!

@MattKercher
MattKercher force-pushed the feature/jellyfin-api-fixes branch from 69aa7f3 to 354d7fa Compare August 22, 2026 00:11
@MattKercher
MattKercher force-pushed the feature/jellyfin-api-fixes branch 2 times, most recently from f18f1e5 to 772079e Compare September 4, 2026 21:17
@MattKercher
MattKercher force-pushed the feature/jellyfin-api-fixes branch from 772079e to 6c1364e Compare September 5, 2026 01:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant