README.md

July 3, 2026 · View on GitHub

smart-covers banner

Cover extraction for Jellyfin libraries with online fallback

Latest Release Tests Build Status License Jellyfin 10.11+ .NET 9.0 listed on awesome-jellyfin codecov


A Jellyfin plugin that provides cover-image extraction for books, audiobooks, comics, magazines, and music libraries. It works alongside built-in providers as a safety net: when they fail to find a cover -- or crash on mislabeled embedded art -- SmartCovers steps in. As a final fallback, it can search Open Library and Google Books for cover images automatically.

Supported Formats

FormatTypeExtraction Method
PDFBook / Magazine / ComicFirst-page rendering via built-in PDFium (no external tools needed)
EPUBBookArchive introspection with 3-tier image search
CBZ / CBRComic / MangaFirst page in natural page order (built-in ZIP/RAR reading, no external tools)
MP3Audiobook / MusicEmbedded art via ffmpeg raw stream copy
M4A / M4BAudiobook / MusicEmbedded art via ffmpeg raw stream copy
FLACAudiobook / MusicEmbedded art via ffmpeg raw stream copy
OGG / OpusAudiobook / MusicEmbedded art via ffmpeg raw stream copy
WMAAudiobook / MusicEmbedded art via ffmpeg raw stream copy
AACAudiobook / MusicEmbedded art via ffmpeg raw stream copy
WAVAudiobook / MusicEmbedded art via ffmpeg raw stream copy
FolderAudiobookSidecar image lookup, then first-file embedded art
AnyAllOnline fallback via Open Library and Google Books

How It Works

PDF -- First Page Rendering

The plugin renders the first page of a PDF as a JPEG using a bundled PDFium native library (via the PDFtoImage NuGet package). No external tools like poppler-utils or pdftoppm are required. DPI is configurable, and a per-render timeout prevents hangs on malformed files. The native library is included for Linux (x64, arm64, musl), macOS, and Windows.

EPUBs are ZIP archives. When other plugins fail to extract a cover, SmartCovers opens the archive and searches with three strategies, in order:

  1. By filename -- files explicitly named cover, portada, front, frontcover, or book_cover (with any image extension).
  2. By path -- any image file with cover in its full archive path (e.g., OEBPS/Images/cover-image.jpg).
  3. By size -- the largest image in the archive (above 5 KB, to skip icons and logos).

CBZ / CBR -- Comic Archive First Page

Comic archives are containers of page images: CBZ is a ZIP, CBR is a RAR. SmartCovers opens them with format detection based on the file content, not the extension -- mislabeled archives (a RAR renamed to .cbz, a ZIP renamed to .cbr) are common in the wild and still work. Both RAR4 and RAR5 are supported, including solid archives.

Cover selection follows comic conventions:

  1. Explicit cover entry -- an image named cover, portada, front, frontcover, or book_cover anywhere in the archive wins.
  2. First page in natural order -- otherwise the first image page is the cover, using natural sort so page-2.jpg correctly precedes page-10.jpg (plain alphabetical order would not).

macOS junk entries (__MACOSX/, AppleDouble ._* files), hidden files, and tiny images (icons/thumbnails) are skipped, and every candidate is verified by magic bytes before being used -- an entry with an image extension but garbage content is passed over. Everything runs in-process; no external tools are required.

Audio -- Raw Stream Copy with Magic-Byte Detection

Jellyfin's built-in Image Extractor uses ffmpeg to decode embedded artwork. This fails when the codec tag does not match the actual data -- a common problem in MP3 files where JPEG cover art is tagged as PNG in ID3 metadata.

SmartCovers sidesteps this entirely by using ffmpeg -vcodec copy to raw-copy the embedded image stream without decoding. It then identifies the actual format by inspecting magic bytes:

Magic BytesDetected Format
FF D8 FFJPEG
89 50 4E 47PNG
47 49 46GIF
42 4DBMP
52 49 46 46 ... 57 45 42 50WebP

Any leading null/padding bytes injected by the raw stream copy are stripped automatically.

Folder-Based Audiobooks

For multi-file audiobooks stored as a directory of chapter files, the plugin:

  1. Checks for sidecar images in the folder (cover.jpg, folder.jpg, front.jpg, poster.jpg, thumb.jpg).
  2. Falls back to extracting embedded art from the first audio file in the directory.

Online Cover Fetching (Last Resort)

When all local extraction methods fail, the plugin can search online sources for a matching cover:

  1. Open Library (openlibrary.org) -- searched first, using title and author metadata.
  2. Google Books (books.google.com) -- searched as a fallback, preferring the highest-resolution image available.
  3. If author-qualified search finds nothing, a title-only retry is attempted on Open Library.

The plugin parses clean titles and authors from item metadata, stripping common audiobook filename noise (format tags like (Mp3), locale tags like [Castellano], Audible codes, year suffixes, and series indicators). No API keys are required. Fetched covers are cached by Jellyfin after the first scan, so online lookups only happen once per item.

This feature is enabled by default and can be toggled in the plugin settings.

Installation

Add the following repository URL in Dashboard > Plugins > Repositories:

https://geiserx.github.io/smart-covers/manifest.json

Then install SmartCovers from the plugin catalog and restart Jellyfin.

From Releases

  1. Download smart-covers_7.3.2.0.zip from the latest release.
  2. Extract the contents into your Jellyfin plugins directory:
    <jellyfin-config>/plugins/SmartCovers_7.3.2.0/
    
    The zip contains SmartCovers.dll (with the CBZ/CBR archive reader merged in), PDFtoImage.lib (the PDFtoImage managed library, shipped with a .lib extension so Jellyfin's plugin scanner skips it), native PDFium libraries for all platforms under runtimes/<rid>/native/, and THIRD-PARTY-NOTICES.md.
  3. Restart Jellyfin.

Building from Source

dotnet publish SmartCovers/SmartCovers.csproj -c Release -o publish

The output will be in the publish/ directory. Merge SharpCompress into the main assembly (ilrepack /internalize /out:SmartCovers.dll publish/SmartCovers.dll publish/SharpCompress.dll — a separate SharpCompress.dll makes Jellyfin 10.11 mark the plugin NotSupported, because nothing can resolve the reference during the plugin scan), then copy the merged SmartCovers.dll, the PDFtoImage managed library (renamed PDFtoImage.dllPDFtoImage.lib so Jellyfin's plugin scanner skips it), and the runtimes/ folder containing native PDFium libraries to your plugins directory.

Requirements

DependencyRequired ForNotes
Jellyfin 10.11+All featuresMinimum supported server version
ffmpegAudio coversBundled with Jellyfin Docker images
Bookshelf plugin v13+EPUB coversRecommended; handles standard EPUB covers as primary provider

PDF rendering requires no external dependencies -- the native PDFium library is bundled with the plugin for all platforms (Linux x64/arm64/musl, macOS x64/arm64, Windows x64/x86/arm64). CBZ/CBR extraction is pure managed code (SharpCompress, merged into SmartCovers.dll) and works everywhere with no external dependencies either.

Configuration

After installation, configure the plugin in Dashboard > SmartCovers (appears in the sidebar):

SettingDefaultDescription
Online Cover FetchingEnabledSearch Open Library and Google Books when local extraction fails. No API key needed.
DPI150Resolution for PDF first-page rendering. Higher values produce sharper covers at the cost of speed.
Timeout30 sMaximum time allowed per extraction. Applies to both PDF rendering and ffmpeg.

Per-Library Enable/Disable

The plugin settings page includes a Libraries section where you can enable or disable SmartCovers for each library directly -- no need to navigate to individual library settings. A Refresh Images button is available for enabled libraries.

Troubleshooting

PDF covers are not extracted

  • Check the plugin config page -- it shows whether the PDFium native library loaded successfully.
  • Grep the Jellyfin log for pdfium native library. On success it logs pdfium native library loaded — PDF cover extraction enabled; if the bundled native cannot load on this host it logs pdfium native library not available — PDF cover extraction disabled and PDF cover extraction is disabled while all other features keep working.

Audio covers are not extracted

  • Confirm ffmpeg is available: run which ffmpeg inside the container.
  • Check the Jellyfin log for ffmpeg not found.

Comic (CBZ/CBR) covers are not extracted

  • Grep the Jellyfin log for Failed to extract comic cover -- corrupt archives are skipped (the online fallback still applies).
  • Archives whose images are all smaller than 1 KB, or that contain no image entries at all, produce no cover by design.

Covers appear for some items but not others

  • The plugin only acts as a fallback. If a higher-priority provider already supplied a cover, this plugin will not run.
  • To force re-extraction, delete the existing cover image for the item in Jellyfin and rescan the library.

Extracted cover looks corrupted

  • This is rare but can happen if the embedded art stream contains unusual padding. Open an issue with the file format details and the Jellyfin log output.

Online covers are not being fetched

  • Check that "Enable online cover fetching" is toggled on in the plugin settings.
  • Verify the Jellyfin server has outbound internet access (the plugin queries openlibrary.org and googleapis.com).
  • Items that already have a cover from a higher-priority provider will not trigger online fetching. Delete the existing cover and rescan to force it.

Other Jellyfin Projects by GeiserX

  • quality-gate — Restrict users to specific media versions based on configurable path-based policies
  • whisper-subs — Automatic subtitle generation using local AI models powered by whisper.cpp
  • jellyfin-encoder — Automatic 720p HEVC/AV1 transcoding service with hardware acceleration
  • jellyfin-telegram-channel-sync — Sync Jellyfin access with Telegram channel membership

License

This project is licensed under the GNU General Public License v3.0. Bundled third-party components are listed in THIRD-PARTY-NOTICES.md.