Files
ComicOPDS/docs/smartlists.md
T

10 KiB

🧠 Smart Lists

Access through /search

Smart Lists allow you to create saved search filters that appear as "virtual folders" in your OPDS feed.

Creating Smart Lists

Simple Filters

Add filters using the web interface:

  • series=Batman
  • year=2024
  • publisher=DC Comics

Advanced Filters

Create complex queries with multiple conditions:

series contains 'Scrooge McDuck'
volume equals 1953
number >= 285
number <= 297

JSON Configuration Example

For advanced users, Smart Lists are stored in /data/smartlist.json:

 {
    "name": "Maul + Vader (1-5)",
    "slug": "maul-vader-1-5",
    "groups": [
      {
        "rules": [
          {
            "not": false,
            "field": "series",
            "op": "contains",
            "value": "Maul"
          },
          {
            "not": false,
            "field": "number",
            "op": "<=",
            "value": "5"
          },
          {
            "not": false,
            "field": "format",
            "op": "equals",
            "value": "Limited Series"
          }
        ]
      },
      {
        "rules": [
          {
            "not": false,
            "field": "series",
            "op": "contains",
            "value": "Vader"
          },
          {
            "not": false,
            "field": "number",
            "op": "<=",
            "value": "5"
          },
          {
            "not": false,
            "field": "format",
            "op": "equals",
            "value": "Main Series"
          }
        ]
      }
    ],
    "sort": "series_number",
    "limit": 0,
    "distinct_by": "",
    "distinct_mode": "oldest"
  }

Maul + Vader (1-5):

  • Group 1:
    • series contains "Maul"
    • number <= 5
    • format = "Limited Series"
  • Group 2:
    • series contains "Vader"
    • number <= 5
    • format = "Main Series"
  • Sort:
    • series_number
    • limit: 0
    • Distinct: no

Supported Fields

All metadata fields from ComicInfo.xml plus:

  • filename - File name (useful for custom naming schemes, e.g., filename contains "[R]" for read status)
  • name - Same as filename

Supported Operations

  • equals, contains, startswith, endswith
  • =, !=, >=, <=, >, < (for numeric fields)
  • not modifier for any operation

"Distinct by series and volume (latest)"

When that option is enabled, a smart list will return at most one comic per series and volume. For each series, it picks the latest issue, using this tie-break:

  1. Newer year (cast to integer)
  2. If year ties: higher number (cast to integer)
  3. If number ties: newer file mtime (last modified time)

So you get a de-duplicated "what's the newest issue for each series?" view.

Use Cases:

  • A clean "latest per series" shelf (e.g., to see what's new without 300 issues of Batman).
  • Weekly pulls / backlog triage: combine with filters like publisher=Image or year >= 2020.

Important details / edge cases

  • Numeric casting: blank or non-numeric year/number are treated as NULL → effectively 0, so those won't beat entries with proper numbers (eg. 16A).

Example use

  • "Latest Image series":
    • Rules: publisher = "Image Comics", year >= 2018
    • Distinct by series: on

→ One newest issue per Image series since 2018.

Dynamic Smart Lists (Auto-Grouping)

Dynamic Smart Lists automatically create sub-folders based on distinct values in a metadata field. Instead of manually creating one smart list per writer, publisher, or series, you can create a single dynamic smart list that generates them automatically.

This feature provides folder/stack view within smart lists - perfect for organizing search results by series, writer, publisher, or any other field.

How It Works

When you set the Group By field to a metadata field (e.g., series, writer, publisher, format):

  1. The smart list becomes a navigation folder showing all distinct values for that field
  2. Each value appears as a sub-folder with a count (e.g., "Batman (1940)" (127), "Batman vs. Dracula" (4))
  3. Clicking a sub-folder shows all comics matching both:
    • Your smart list filters (if any)
    • That specific field value

Example: Browse Batman Comics by Series

Instead of getting a long flat list of all Batman issues, you can create a grouped view:

Create a smart list named "Batman Comics":

  • Group By: series
  • Rules: series contains "Batman"
  • Sort: series_number

Result: You get folder/stack view like:

Batman Comics/
  ├── Batman (1940) (387)
  ├── Batman and Robin (2009) (26)
  ├── Batman vs. Dracula (4)
  ├── Batman: The Dark Knight (2011) (29)
  └── ...

Clicking into "Batman (1940)" shows all 387 issues sorted by number.

Example: Browse by Writer

Create a smart list named "All Writers":

  • Group By: writer
  • Rules: (optional) Add filters to narrow down, e.g., year >= 2020
  • Sort: series_number or issued_desc

Result: You get a folder structure like:

All Writers/
  ├── Brian K. Vaughan (47)
  ├── Ed Brubaker (92)
  ├── Grant Morrison (156)
  ├── Jeff Lemire (73)
  └── ...

Example: Browse Trade Paperbacks by Series

Create "TPB by Series":

  • Group By: series
  • Rules: format equals "TPB"
  • Sort: series_number

Result: Only TPBs, organized by series name.

Supported Group By Fields

  • writer - Group by writer/author
  • publisher - Group by publisher
  • series - Group by series name
  • format - Group by format (TPB, Hardcover, etc.)
  • year - Group by publication year
  • tags - Group by tags
  • characters - Group by character appearances
  • teams - Group by team appearances
  • genre - Group by genre

Combining with Regular Filters

Dynamic smart lists work with all regular smart list features:

  • Filters: Pre-filter comics before grouping (e.g., only 2020+ or only Image Comics)
  • Distinct: De-duplicate by series+volume
  • Limit: Cap results per sub-folder
  • Sort: Control ordering within each group
    • Issued (newest first) - Sort by publication date (year/month/day)
    • Series + Number - Sort by series name and issue number
    • Title - Sort alphabetically by title
    • Publisher - Group by publisher, then series
    • Recently Added - Sort by when the file was added to your library (requires ENABLE_WATCH=true for accurate timestamps)

JSON Configuration Example

{
  "name": "Recent Comics by Writer",
  "slug": "recent-by-writer",
  "group_by": "writer",
  "groups": [
    {
      "rules": [
        {
          "not": false,
          "field": "year",
          "op": ">=",
          "value": "2020"
        }
      ]
    }
  ],
  "sort": "issued_desc",
  "limit": 0,
  "distinct_by": "",
  "distinct_mode": "latest"
}

This creates a dynamic list showing all writers who published comics since 2020, with each writer's comics sorted by newest first.

Screenshot


CBL Reading Lists

ComicOPDS supports .cbl files (ComicRack Reading List format) as a separate "Reading Lists" section in the OPDS feed.

What are CBL files?

CBL files are XML-based reading lists exported from comic book managers like ComicRack. They define a list of comics using two matching methods:

  • Explicit Books — specific issues referenced by Series, Number, Volume, and Year
  • Series Matchers — pattern-based rules that match all issues of a series by name

Note: CBL files are meant to be exported from ComicRack. They are not a practical format to create by hand. If you want to build custom lists without ComicRack, use the Smart Lists feature and its built-in web UI instead.

Setup

  1. Place your .cbl files in the /data/ directory (the ./data volume mount in your compose.yaml)
  2. No restart or reindex needed — CBL lists are read on the fly

OPDS Feed

CBL reading lists appear as a separate "Reading Lists" folder in the OPDS root, alongside the existing "Smart Lists" folder:

Library/
  ├── 📁 Smart Lists
  ├── 📁 Reading Lists
  │     ├── Stranger Things
  │     └── Letter 44
  ├── DC/
  ├── Marvel/
  └── ...

CBL File Format

Explicit Book List

Lists specific issues by Series, Number, Volume, and Year. Comics are matched against your library's ComicInfo.xml metadata (case-insensitive series matching).

<?xml version="1.0"?>
<ReadingList>
  <Name>Stranger Things</Name>
  <Books>
    <Book Series="Stranger Things SIX" Number="1" Volume="2019" Year="2019" />
    <Book Series="Stranger Things SIX" Number="2" Volume="2019" Year="2019" />
    <Book Series="Stranger Things" Number="1" Volume="2018" Year="2018" />
  </Books>
  <Matchers />
</ReadingList>

Series Matcher

Matches all issues of a series by name. Useful for collecting an entire run without listing every issue.

<?xml version="1.0"?>
<ReadingList>
  <Name>Letter 44</Name>
  <Books />
  <Matchers>
    <ComicBookMatcher xsi:type="ComicBookSeriesMatcher"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <MatchValue>Letter 44</MatchValue>
    </ComicBookMatcher>
  </Matchers>
</ReadingList>

Combined

A single CBL file can use both explicit books and matchers — results are combined.

Matching Behavior

CBL Element Matches Against Logic
Book Series="X" m.series (case-insensitive) AND with Number/Volume if present
Book Number="N" m.number (exact) Optional, narrows match
Book Volume="V" m.volume (exact) Optional, narrows match
ComicBookSeriesMatcher m.series (case-insensitive) Matches all issues of that series

Multiple books and matchers within a single CBL file are combined with OR logic.