Desktop reader / Draft
Media Library Reader
A local library reader built around responsive browsing, right-to-left spreads and switching between black-and-white and colour editions without losing your place.
Python / PySide6 / CPU raster rendering / Local filesystem
Draft case study / Screenshots and recordings pending.
- Index albums and chapter identities
- Load visible covers and nearby pages
- Compose the current reading spread
- Persist progress and edition preferences
A Reader for Existing Libraries
This page focuses on viewing and navigating media already stored in local libraries. Albums and chapters form the browsing structure, while saved covers and progress make it possible to return to a long-running series without reconstructing the previous session.
The reader is implemented with PySide6 and a custom CPU-painted viewport. It does not depend on a Qt Quick scene or an OpenGL, Direct3D or Vulkan rendering path. That choice concentrates the performance work on image decoding, scaling, caching and deciding which pages genuinely need to exist in memory.
Library Identity and Progress
Filesystem names are useful labels but are not always stable identities. A chapter named 1 in one edition can correspond to 0001 in another. Numeric chapter identity mapping allows those folders to be associated without requiring identical spelling.
A local viewer-state file stores reading progress, selected covers, edition associations and preferences such as pairing shifts and fullscreen behaviour. Progress tracks the underlying chapter and source-page index, not just the number of a rendered spread. That distinction matters whenever two editions or pairing settings produce different layouts from the same sequence of pages.
Directory, chapter and cover-path caches reduce repeated filesystem work. These caches serve navigation, while the thumbnail cache serves image presentation; treating those as different jobs makes it easier to invalidate or rebuild the part that changed.
Right-to-Left Reading
Two-page spreads follow a right-to-left arrangement. A pairing shift can leave the first page alone, and marking a page as fullscreen changes how subsequent pages are paired. These are reading decisions, not edits to the original image files.
The renderer retains borders already present in the source rather than imposing an additional application gutter. Page zoom and an overview contact sheet support two different tasks: inspecting a page closely and finding a position in the chapter. Moving beyond the chapter end can continue into the next chapter instead of forcing a return to the library.
Because progress is tied to the source sequence, changing how pages are paired need not be confused with changing the reader's place. The same principle supports restoring the precise chapter scroll position after another interaction.
Two Editions, One Place
The colour switch selects an associated alternate album. It is not an image-colourisation model: black-and-white and colour are separate source libraries supplied to the reader. Chapter mapping connects the editions, while per-mode cover and pairing preferences allow each to retain the layout that suits its files.
Switching preserves the source location where the mapping permits it. Where an alternate chapter is unavailable, the reader falls back to the original material rather than showing an invented match. This turns a potentially disruptive library change into a reading operation with explicit limits.
Alignment controls handle differences between editions through translation and scale. Fine adjustment modifiers and small scale increments support more precise matching than a coarse drag alone. Those controls are useful because corresponding pages can have different crop, margin or image dimensions.
Doing Less Work per Frame
The library viewport is virtualised: visible covers and the region near them receive work before content that is far off screen. Thumbnail decoding and scaling run asynchronously, and a disk cache keeps useful raster results between sessions. The goal is not to create a widget or decoded image for every page in an entire collection.
During reading, neighbouring spreads are prefetched. A double-buffered handover keeps the current image visible until the replacement is ready, addressing the black flash that can otherwise accompany a page change. Prioritised work helps an alignment or reading interaction avoid waiting behind unrelated thumbnail generation.
Alternate-edition covers are prewarmed after a short idle delay, in small batches around the visible area. This prepares an edition switch without eagerly decoding the whole other library. The optimisations are workload choices, not an unverified claim that every machine or collection loads a fixed number of times faster.
A Cold-Start Failure
A particularly important failure involved two thumbnail workers entering image construction during a cold start. The resulting native deadlock did not behave like a normal Python exception. Initialising the relevant image path on the GUI thread before concurrent work addressed that startup ordering problem.
The first reproduction approach was misleading: it warmed the image bindings and used a different window size, changing the thumbnail workload. A cold-cache run at the real application dimensions, using the actual context-menu route, reproduced the problem. An external native stack capture could then observe the blocked process without depending on the frozen UI.
Lessons and Boundaries
Responsiveness comes from controlling when work happens as much as from making each operation faster. Virtualisation, nearby prefetching, cache reuse and small idle batches address different parts of the experience and need to be evaluated together.
The debugging lesson was equally concrete: a test that changes startup state can remove the failure it is meant to observe. This draft focuses on library browsing, edition switching and reading behaviour. Media acquisition is outside the scope of this presentation.