Add dr-thumbs: a sharded, syncable thumbnail store

A thumbnail is the one derived artefact worth sending over the wire: it costs
a range fetch plus a decode to produce and is identical for every client
looking at the same file. A second device that downloads a shard gets a full
grid without fetching a byte of RAW.

Sharded at 25 MB, filled sequentially. The cap is about sync granularity, not
SQLite's limits — one growing database means every client re-downloads it
whenever a single thumbnail is added, whereas with sequential fill only the
newest shard is ever dirty and sealed shards are safe to cache forever.

Stored JPEG-encoded rather than as raw RGBA: a 256px RGBA buffer is ~256 KB
against ~20 KB encoded, and that 13x is transfer cost on every client.

Keyed on Nextcloud's oc:fileid, stable across server-side rename and move.

Assisted-by: LLM
This commit is contained in:
2026-08-09 20:38:12 +02:00
parent b6a5c0f090
commit d6ddd0703b
6 changed files with 1011 additions and 0 deletions
Generated
+49
View File
@@ -1262,6 +1262,7 @@ dependencies = [
"dr-types",
"log",
"rusqlite",
"serde_json",
"thiserror 2.0.20",
]
@@ -1351,10 +1352,23 @@ dependencies = [
"url",
]
[[package]]
name = "dr-thumbs"
version = "0.1.0"
dependencies = [
"dr-types",
"jpeg-encoder",
"log",
"rusqlite",
"thiserror 2.0.20",
"zune-jpeg 0.4.21",
]
[[package]]
name = "dr-types"
version = "0.1.0"
dependencies = [
"serde",
"thiserror 2.0.20",
]
@@ -1363,17 +1377,21 @@ name = "dr-ui"
version = "0.1.0"
dependencies = [
"anyhow",
"dr-catalog",
"dr-decode",
"dr-gpu",
"dr-pipeline",
"dr-plat",
"dr-sync",
"dr-sync-nextcloud",
"dr-thumbs",
"dr-types",
"log",
"pollster",
"reqwest",
"rusqlite",
"serde_json",
"serde_norway",
"slint",
"slint-build",
"tokio",
@@ -3115,6 +3133,12 @@ dependencies = [
"libc",
]
[[package]]
name = "jpeg-encoder"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0370574b86f7eca156b9f298392b5e69a23f8c86f3f865add60bbc2e79467a6"
[[package]]
name = "js-sys"
version = "0.3.104"
@@ -5333,6 +5357,12 @@ dependencies = [
"unicode-script",
]
[[package]]
name = "ryu"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
[[package]]
name = "same-file"
version = "1.0.6"
@@ -5473,6 +5503,19 @@ dependencies = [
"zmij",
]
[[package]]
name = "serde_norway"
version = "0.9.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e408f29489b5fd500fab51ff1484fc859bb655f32c671f307dcd733b72e8168c"
dependencies = [
"indexmap",
"itoa",
"ryu",
"serde",
"unsafe-libyaml-norway",
]
[[package]]
name = "serde_repr"
version = "0.1.21"
@@ -6554,6 +6597,12 @@ version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]]
name = "unsafe-libyaml-norway"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39abd59bf32521c7f2301b52d05a6a2c975b6003521cbd0c6dc1582f0a22104"
[[package]]
name = "untrusted"
version = "0.9.0"