Executes docs/superpowers/specs/2026-07-07-runtime-performance-pass-design.md: - database.rs: every pooled connection now runs WAL + synchronous=NORMAL + busy_timeout=5000 + foreign_keys=ON via with_init (in-memory pools get the latter two). Fixes the SQLITE_BUSY failure mode under the parallel scanner and makes FK cascades work on every connection, not just whichever one last ran the old one-shot pragma in delete_folder. - database.rs: prepare_cached for the per-video info_cache queries; new info_cache_put_many bulk upsert (single transaction) replaces the per-row autocommitted info_cache_put, with a round-trip unit test. - library.rs: enrich_with_cache collects cache misses and flushes them once per channel; title sort uses sort_by_cached_key. - app.rs: Title/ChannelAsc sorts use sort_by_cached_key instead of allocating two lowercased strings per comparison. - Cargo.toml: panic=abort in release (crash-hook still fires; Cargo forces unwind for test harnesses). PACKAGING.md documents the local RUSTFLAGS target-cpu=native opt-in; repo stays portable. - .gitignore: catacomb.db-wal / catacomb.db-shm sidecars. Verified: 146 tests pass (integration suite exercises the pragmas end-to-end), x86_64-pc-windows-gnu check green, live smoke shows journal_mode=wal + batched cache writes landing correct rows. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
129 lines
6.8 KiB
TOML
129 lines
6.8 KiB
TOML
[package]
|
|
name = "catacomb"
|
|
version = "0.1.0"
|
|
edition = "2021"
|
|
description = "Self-hosted archive for YouTube, TikTok, Twitch, Vimeo, Bandcamp, SoundCloud, Odysee and more. Desktop GUI + web UI, bundled yt-dlp with curl_cffi impersonation, Plex export, SQLite-backed resume tracking. AGPL-3.0."
|
|
license = "AGPL-3.0-only"
|
|
repository = "https://codeberg.org/anassaeneroi/catacomb"
|
|
homepage = "https://codeberg.org/anassaeneroi/catacomb"
|
|
authors = ["InannaBeloved <anassaeneroi@pm.me>"]
|
|
readme = "README.md"
|
|
|
|
[dependencies]
|
|
# Default to the wgpu (Vulkan/Metal/DX) renderer instead of the default glow
|
|
# (OpenGL) one. NVIDIA + Wayland crashes the GL surface on window resize
|
|
# (Glutin EGL_BAD_ALLOC / OutOfMemory on maximize); wgpu's Vulkan path
|
|
# reconfigures the swapchain cleanly. Keep glow compiled in as an escape
|
|
# hatch for machines where wgpu/Vulkan creates a window but never presents
|
|
# a frame (`YT_OFFLINE_RENDERER=glow` or `--renderer glow`).
|
|
eframe = { version = "0.29", default-features = false, features = ["accesskit", "default_fonts", "wayland", "x11", "wgpu", "glow"] }
|
|
image = { version = "0.25", default-features = false, features = ["webp", "jpeg", "png"] }
|
|
toml = "0.8"
|
|
serde = { version = "1.0", features = ["derive"] }
|
|
serde_json = "1.0"
|
|
rusqlite = { version = "0.31", features = ["bundled"] }
|
|
r2d2 = "0.8"
|
|
r2d2_sqlite = "0.24"
|
|
notify-rust = { version = "4", default-features = false, features = ["z"] }
|
|
axum = { version = "0.7", features = ["macros", "ws"] }
|
|
tokio = { version = "1", features = ["full"] }
|
|
tokio-util = { version = "0.7", features = ["io"] }
|
|
tokio-stream = "0.1"
|
|
tower-http = { version = "0.5", features = ["cors", "fs", "compression-gzip"] }
|
|
argon2 = "0.5"
|
|
rand = "0.8"
|
|
# HTTP client for federation (remote-library mode). Pure-Rust TLS (rustls, no
|
|
# system OpenSSL) to match the bundled-everything posture. Blocking API + a
|
|
# cookie store so RemoteClient can log into a password-protected peer and
|
|
# reuse the session; the web layer calls it under spawn_blocking, desktop
|
|
# calls it directly.
|
|
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "blocking", "json", "cookies"] }
|
|
libc = "0.2.186"
|
|
|
|
# Platform-specific desktop deps. On Linux the tray (ksni — StatusNotifierItem
|
|
# over zbus) and the rfd file picker (xdg-portal backend) stay pure-Rust with no
|
|
# GTK build dep, matching notify-rust. On Windows/macOS there's no SNI tray yet
|
|
# (tray::start is a compiled-out no-op) and rfd falls back to its native backend
|
|
# (Win32 / AppKit) via its default features.
|
|
[target.'cfg(target_os = "linux")'.dependencies]
|
|
ksni = { version = "0.3.4", features = ["tokio"] }
|
|
rfd = { version = "0.15", default-features = false, features = ["xdg-portal", "tokio"] }
|
|
|
|
[target.'cfg(not(target_os = "linux"))'.dependencies]
|
|
rfd = { version = "0.15", features = ["tokio"] }
|
|
|
|
# Release Windows builds are linked as a GUI subsystem app (no console window —
|
|
# see the windows_subsystem attribute in main.rs), which is right for the egui
|
|
# GUI but means a `--web`/CLI run launched from a terminal has nowhere to print.
|
|
# windows-sys gives us AttachConsole to reattach to the launching console at
|
|
# runtime (see attach_windows_console in main.rs).
|
|
[target.'cfg(windows)'.dependencies]
|
|
windows-sys = { version = "0.59", features = ["Win32_System_Console"] }
|
|
|
|
[profile.release]
|
|
opt-level = 3
|
|
# Thin LTO does cross-crate inlining without the rust-lld + bundled-sqlite
|
|
# link breakage that full `lto = true` triggered (the previous !lto note
|
|
# was about full LTO; thin works with the current toolchain). Worth ~5-10%
|
|
# on hot paths.
|
|
lto = "thin"
|
|
# Codegen-units = 1 trades build time (~30s extra) for tighter inlining
|
|
# across the whole crate. Worth it for release binaries.
|
|
codegen-units = 1
|
|
# Strip debuginfo from release binaries — cuts binary size by ~30 MB
|
|
# without affecting runtime. The crash log still captures backtraces at
|
|
# runtime; those are less informative without symbols but usable with
|
|
# addr2line against the unstripped build artifact.
|
|
strip = "debuginfo"
|
|
# No unwinding tables/landing pads: smaller binary, marginally faster hot
|
|
# paths. The crash handler (crash.rs panic hook) still fires before the
|
|
# abort, so crash logging is preserved. Cargo forces `panic=unwind` for
|
|
# test/bench harnesses automatically, so `cargo test --release` and the
|
|
# #[cfg(test)] catch_unwind in crash.rs are unaffected. Tradeoff: a panic
|
|
# in a parallel scan worker aborts the process instead of one worker —
|
|
# acceptable, those workers treat all fallible I/O with .ok() already.
|
|
panic = "abort"
|
|
|
|
# ── Debian / Ubuntu package (cargo-deb) ──────────────────────────────────────
|
|
# `cargo deb` reads this to build a .deb. Runtime deps mirror the PKGBUILD:
|
|
# yt-dlp + ffmpeg + mpv are invoked as subprocesses, xdg-utils provides
|
|
# xdg-open, and libxcb is needed by the eframe/winit windowing stack.
|
|
[package.metadata.deb]
|
|
maintainer = "InannaBeloved <anassaeneroi@pm.me>"
|
|
copyright = "2026, InannaBeloved <anassaeneroi@pm.me>"
|
|
license-file = ["LICENSE", "0"]
|
|
extended-description = """\
|
|
Self-hosted archive for YouTube, TikTok, Twitch, Vimeo, Bandcamp, \
|
|
SoundCloud, Odysee and more. Ships a desktop GUI and a mobile-friendly \
|
|
web UI, with a bundled yt-dlp (curl_cffi impersonation), Plex export, \
|
|
and SQLite-backed resume tracking."""
|
|
section = "video"
|
|
priority = "optional"
|
|
# yt-dlp / ffmpeg / mpv are runtime subprocess deps, not link-time, so
|
|
# cargo-deb's auto-detection won't find them — list explicitly. libxcb
|
|
# is the one shared library the GUI actually dlopens.
|
|
depends = "libc6, libxcb1, yt-dlp, ffmpeg, mpv, xdg-utils"
|
|
recommends = "libnotify4"
|
|
assets = [
|
|
["target/release/catacomb", "usr/bin/", "755"],
|
|
["catacomb.desktop", "usr/share/applications/catacomb.desktop", "644"],
|
|
["icon.png", "usr/share/pixmaps/catacomb.png", "644"],
|
|
["README.md", "usr/share/doc/catacomb/README.md", "644"],
|
|
]
|
|
|
|
# ── Fedora / RHEL / openSUSE package (cargo-generate-rpm) ─────────────────────
|
|
# `cargo generate-rpm` reads this. Run `cargo build --release` first; it
|
|
# packages the already-built binary rather than building itself.
|
|
[package.metadata.generate-rpm]
|
|
summary = "Self-hosted multi-platform video archiver with desktop + web UI"
|
|
license = "AGPLv3"
|
|
# RPM distro package names differ from Debian's. yt-dlp is `yt-dlp` on
|
|
# Fedora; ffmpeg lives in RPM Fusion but we still declare the dep.
|
|
requires = { yt-dlp = "*", ffmpeg = "*", mpv = "*", "xdg-utils" = "*" }
|
|
assets = [
|
|
{ source = "target/release/catacomb", dest = "/usr/bin/catacomb", mode = "755" },
|
|
{ source = "catacomb.desktop", dest = "/usr/share/applications/catacomb.desktop", mode = "644" },
|
|
{ source = "icon.png", dest = "/usr/share/pixmaps/catacomb.png", mode = "644" },
|
|
{ source = "README.md", dest = "/usr/share/doc/catacomb/README.md", mode = "644" },
|
|
{ source = "LICENSE", dest = "/usr/share/licenses/catacomb/LICENSE", mode = "644" },
|
|
]
|