• 6 posts
  • 3 comments
Joined 3 months ago
Cake day: April 27th, 2026

I’ve been building Fathom, a desktop Jellyfin client, for quite some time and just put out the first public release (0.9.0) for Linux and Windows.

The real draw is having everything in one place. Your Jellyfin movies, shows, music, and Live TV; most of Jellyfin’s important server-side management (users, libraries, scheduled tasks, transcoding, Live TV and DVR, and more); and optional Seerr requests plus a full YouTube client, all without leaving the app. No bouncing between the web dashboard, a requests page, and a browser tab. One window does the lot.

What’s in it:

  • Server management, built in. Handle users, libraries, scheduled tasks, transcoding, active sessions, Live TV and DVR, and more, without opening the Jellyfin web dashboard.
  • Optional Seerr requests right from the detail page, with Jellyfin, Seerr, or API-key sign-in.
  • Optional YouTube client. SponsorBlock, DeArrow, dislike counts, downloads, no ads and no account, off unless you turn it on.
  • One shared player. Jellyfin and YouTube use the same controls, seek bar, and shortcuts. Picture-in-picture, or pop a video out to a floating, always-on-top window on your desktop.
  • Plus: SyncPlay watch-together (works with other Jellyfin clients too), ratings (Rotten Tomatoes, IMDb, and more), in-app updates with a stable or beta channel, light/dark/AMOLED themes, and searchable settings. Everything plays through mpv, so you get direct play, hardware decoding, and proper subtitle and audio track control.

It’s Linux-first (built and tested on Arch/KDE) with a self-contained AppImage, plus a portable Windows build. Android and more features are on the roadmap.

Download + source: https://github.com/Fathom-Media/fathom/releases/tag/v0.9.0 Repo (AGPL-3.0): https://github.com/Fathom-Media/fathom

This is the first public release, so expect a few rough edges. All feedback is genuinely wanted: bug reports, feature requests, and ideas. The goal is to grow Fathom into one of the best Jellyfin clients out there, so open an issue or start a discussion and it’ll get read.

AI Disclosure

Per Rule 7 / [AIP] disclosure requirements AI was used during development as a coding assistant. Level per category:

  • Design (architecture, system design): Hint — I make the architectural calls; AI suggests trade-offs and edge cases I might have missed.
  • Implementation (production code): Pair — roughly 50/50. AI drafts, I review, adjust, test on real hardware, and only commit what I’ve verified. Every commit is manually reviewed before it goes to my dev repo.
  • Testing (writing tests, test plans, QA): Assisted — real-device testing is manual (I test on my own PC before every release). AI helps draft test plans and think through edge cases.
  • Documentation (docs, comments, README, CHANGELOG): Pair — release notes and changelog entries are drafted with AI then edited for tone; comments and code docs are mostly Pair as well.
  • Review (code review, PR feedback): Assisted — I’m the reviewer; AI helps with security sweeps, audit passes on complex changes, and consistency checks.
  • Deployment (CI/CD config): Hint — GitHub Actions/release pipeline is largely conventional; AI-suggested improvements only.

CookTrace is a self-hosted recipe manager. Runs in a single Docker container, PWA + native Android app, no accounts on external services, no data leaving your network, AGPL-3.0.

Retiring -rc.N and moving to strict semver. Docker images now publish under multiple tags so you can pin :1.0, :1, or :latest depending on how aggressively you want updates. Also delivers a real Send Test email flow with recipient dialog, fixes two Android bugs (recipes showing the wrong creation date, SMTP settings loading blank), patches a high-severity adm-zip CVE in the backup restore path, and adds public contributor docs.

Every future release uses strict semver: PATCH for bug fixes, MINOR for new features, MAJOR for breaking changes. Existing rc.N image tags and release assets stay live indefinitely; anyone pinned to a specific rc release is unaffected.

Added

  • Multi-Tag Docker Publishing. :1.0.0, :1.0, :1, :latest. Pin :1.0 to auto-receive patches without opting into future 1.1.0 features.
  • :dev Docker Tag. Rolling image built from the dev branch.
  • Send Test Email Dialog. Asks where to send the test, pre-filled with your account email.

Changed

  • Retired the -rc.N suffix.
  • Send Test actually sends an email now (was just verifying SMTP auth).
  • Email section moved under Admin.
  • Password field uses a Change button when the server has a stored value.

Fixed

  • Recipes on Android showed the first-connect date instead of the real creation date. Heals on next sync after upgrade.
  • Email settings blank on the Android app.
  • Trace AI chef hat clipped at the top of the FAB.

Security

  • adm-zip 0.5.x → 0.6.0 (CVE-2026-39244, high). Crafted ZIP file could trigger a 4GB memory allocation during full-backup restore.

AI Disclosure

Per Rule 7 / [AIP] disclosure requirements AI was used during development as a coding assistant. Level per category:

  • Design (architecture, system design): Hint, I make the architectural calls; AI suggests trade-offs and edge cases I might have missed.
  • Implementation (production code): Pair, roughly 50/50. AI drafts, I review, adjust, test on real hardware, and only commit what I’ve verified. Every commit is manually reviewed before it goes to my dev repo.
  • Testing (writing tests, test plans, QA): Assisted, real-device testing is manual (I test on my own PC and mobile devices before every release). AI helps draft test plans and think through edge cases.
  • Documentation (docs, comments, README, CHANGELOG): Pair, release notes and changelog entries are drafted with AI then edited for tone; comments and code docs are mostly Pair as well.
  • Review (code review, PR feedback): Assisted, I’m the reviewer; AI helps with security sweeps, audit passes on complex changes, and consistency checks.
  • Deployment (CI/CD config): Hint, Docker / GitHub Actions / release pipeline is largely conventional; AI-suggested improvements only.

CookTrace is a self-hosted recipe manager (Docker + Android, AGPL-3.0). rc.3 is the next public roll-up, bundling everything since the rc.1 first public release plus the rc.2 patches in between.

What’s new

  • Pantry variants. A pantry row can now carry brand-specific rows underneath it. Recipes link to the generic parent (Whole Milk); each variant (Greenwise, Publix) has its own barcode, photo, stock, and expiration date. A generic can either use its own nutrition or pull from a chosen variant, so recipe math reflects the label of the product you actually cook with. Add Variant with inline suggestions from existing pantry rows; deleting a parent with variants asks whether to keep them as standalone items or remove them together.
  • Pantry expiration dates + digest push. Every pantry row gains an Expires On field with amber/red pills and an “Expiring Soon” filter chip. A once-a-day roll-up delivers everything expiring within a chosen window (1 / 3 / 5 / 7 / 14 days) at a chosen time, through Apprise, Gotify, or ntfy plus the local device channel. Past-expiry items always included.
  • AI Scan Label for pantry nutrition. Take a photo of a nutrition label from the pantry item editor and Trace extracts name, brand, serving size, and every nutrient it can read. Complementary to the existing barcode scanner: barcode → Open Food Facts lookup for name-brand products; label scan → store-brand jars, homemade batches, imports OFF doesn’t cover. Requires an AI provider configured in Settings.
  • Shopping list aisle grouping + drag reorder. New chip row toggles between By Aisle, By Recipe, and Flat. Every pantry category picks up an optional Default Aisle label; items added from a linked pantry row inherit that aisle automatically. Custom aisles work as free-text groups (write “Freezer” once and it becomes a group). Rows drag to reorder within a group; cross-group drops in By Aisle mode reassign the moved item’s aisle, so shuffling the list is the same gesture as reclassifying an item.
  • Simplified shopping quick-add + per-row edit. Primary add is now name plus optional qty plus a labeled Add pill, matching Google Keep, Bring!, AnyList, and OurGroceries. Unit moved to a per-row Edit modal so the sweep flow (“milk, eggs, bread”) is name-tap-Add-repeat rather than three fields per item. The two bulk-add sources (Recipe, Planned Cooks) collapse behind a single + button in the header.
  • Recipe Rest Time + Total Time. New Rest Time field for hands-off periods (rise, rest, marinate, chill, soak, ferment) rolls into the auto-calculated Total Time. Optional manual override on Total Time when the recipe’s stated total is bigger than the components would imply. Times render as 1h 15m across list cards, recipe view, cookbook, public share, and the recipe-card image.
  • Multi-select on Pantry and Recipes. Long-press to enter selection mode. Header title flips to “N Selected” and top-right icons become trash + cancel on Pantry, or trash + add-to-cookbook + cancel on Recipes. Matches the pattern used on NutriTrace’s Diary + Foods. Replaces the older floating action pill.
  • Mobile ingredient rows. The three per-row action buttons (link to pantry, section divider, delete) collapse behind a kebab menu on small screens so the ingredient name field has room to read. Adding a note is one tap in the kebab; the note appears on a second inline row.
  • Four animated page banner styles. Retired the illustrated SVG headers in favor of Shimmer, Drift, Pulse, and Aurora gradient animations. All four honor Reduce Motion. Settings → Appearance → Banner Style.

Fixes

  • Cook Mode now reliably keeps the screen awake on Android via the native KeepAwake plugin — the Web Wake Lock path silently stopped working on some Android WebView versions
  • Cook photos taken during a diary log render immediately on the Diary Photos tab; older photos still render via a backstop URL conversion
  • Bulk-add from a recipe or planned cook populates each row’s aisle from the linked pantry item’s category, so items land pre-grouped instead of piling into Uncategorized
  • Long-pressing a shopping row no longer lets you drag it while the action menu is open — the finger-hold that opened the menu was feeding pointer moves into the reorder tracker
  • Cancel out of Pantry multi-select no longer leaves an invisible layer blocking taps until reload
  • The Shopping quick-add box no longer freezes on mobile when the pantry has hundreds of items — the suggestion list is now capped
  • Last Cooked date no longer concatenates with a full timestamp
  • Mealie ZIP importer extracts cook-event photos for full live-API parity

Security

  • Dependency security bumps clear every actionable Dependabot alert: multer 1.4.5-lts.1 → 2.2.0 (three high-severity DoS CVEs on the LTS line), nodemailer 8.0.7 → 9.0.3 (five CVEs including TLS OAuth cert-validation bypass and CRLF header injection), vite 7.3.3 → 7.3.6 (dev-only server.fs.deny bypass), plus an esbuild override to clear a dev-server CORS advisory nested under svelte-i18n. Self-hosters on Docker just need to pull the new image.

Install / upgrade

  • Docker: pull the new image and restart your stack (see the README for compose snippets)
  • Android: signed APK on the release page
  • Full CHANGELOG: main repo

What is CookTrace?

Self-hosted recipe manager. Full recipe library with live scaling, ingredient unit conversion, FDA-style Nutrition Facts, cook mode, and cook log. Pantry catalog with barcode scanning (ML Kit on Android, QuaggaJS on web), Open Food Facts + USDA lookup, variants, expiration dates, and an “8/10 in pantry” match pill on every recipe card. Cook diary + meal planner with list and month-calendar views. Shopping list that pulls missing ingredients from a recipe and skips anything you already have stocked. Trace AI assistant (Claude / OpenAI / Gemini / Ollama). Multi-user with OIDC SSO. Federation with NutriTrace (nutrition) and LiftTrace (lifting). Docker on the server, Capacitor app on Android. AGPL-3.0 licensed.

NutriTrace is a self-hosted nutrition tracker (Docker + Android, AGPL-3.0). rc.53 is a catch-up roll-up, bundling everything from rc.48 through rc.53 — the last update posted here was rc.47.

What’s new

  • Reorder + hide Statistics categories. Settings → Statistics → Categories now has a drag list of every metric the chart page renders (nutrients, body stats, water, wellness). Drag rows to pick your own order, toggle any of them off. New wellness sources you connect later automatically append to the end. (#85)

  • Bulk delete on Foods, Meals, Recipes. Long-press an item in your catalog, pick “Select Multiple” from the action sheet, tap other items to add them to the selection, delete them all with one confirmation. Matches the multi-select UX the Diary already has. Diary entries that reference deleted items keep their nutrition snapshot but lose the link.

  • Open Food Facts serving sizes + density. Foods scanned or searched from OFF now auto-import their serving units (1 slice, 1 cookie, 1 bottle, etc.), so you can log them in those units directly instead of converting to grams. Foods can also carry an optional density (g/ml) for accurate cross-system conversion on liquids like oil or honey. Unit metadata is opt-in via Settings → Diary → Show Unit Metadata for anyone who wants the leaner default. (#69, #70)

  • Trace AI now logs real foods. Asking “add an apple to snacks” or “log Greek yogurt for breakfast” creates a real food entry with full nutrition (protein, carbs, fat, fiber, vitamins) instead of a Quick Calories row with just kcal. Searches your local catalog first, then Open Food Facts. Honors renamed / reordered meals so “snacks” routes to the right slot. (#79)

  • French language. Full UI translation contributed by @antoinech2 (PR #72). Switchable in Settings → Language. A handful of less-common settings screens are still English and will be translated incrementally.

  • Background Health Connect sync on Android. Wearable data syncs to the server about once an hour in the background even when NutriTrace is closed, so today’s steps are already there when you open the browser build on a desktop. Settings → Wellness → Health Connect has a Background Sync row showing when the last sync ran plus battery-optimization guidance. (#68)

  • Tap a date in the Statistics history list to jump into that day. Nutrient / water / body-stat rows open the Diary on that date, wellness rows open the Wellness page. Pairs with the rc.47 Nutrition Summary drill-down for an end-to-end “chart shows a spike, day page shows the cause” flow. (#64)

  • Body-stat charts auto-fit their Y-axis to your actual data range (weight, HRV, RHR, body measurements, etc.) instead of pinning the floor to zero. If a goal is set, the range extends to keep the goal in view. Nutrient / counted charts still anchor to zero. (#67)

  • Animated banner styles. The illustrated SVG page banners are retired in favor of four animated gradient styles: Shimmer, Drift, Pulse, Aurora. Pick in Settings → Appearance → Banner Style. All four honor the OS’s Reduce Motion preference.

Fixes

  • Editing a diary or body-stat entry from mobile and PWA in the same day could silently wipe an earlier entry when the two devices’ sync windows overlapped. Every save path now refetches server state before writing so a stale cache can’t overwrite fresh data from another device (#81)
  • Browser password suggestions (“Suggest strong password” in Safari, 1Password, Bitwarden, etc.) now include a special character and pass validation on the first try (#82)
  • Statistics charts were blank for users whose only wellness source was Health Connect or Google Health. Every wellness-source check across the app now routes through a single shared gate (#65)
  • Adding a food with a phone-camera photo to the diary no longer fails with a silent 413 on busy days. Photos now save as proper uploaded files instead of inline base64 in the food record (#74)
  • Removing a food or meal photo by tapping the X actually removes it now (kilkalabs follow-up on #74)
  • Statistics chart tooltip no longer throws when hovering over days with missing data (#66)
  • Wellness sync icons on Fitbit / Garmin / Withings / Google Health buttons rotate in the direction their arrows point (#86)
  • Readiness on severe HRV crash days reads closer to Fitbit’s own value (raised the interaction penalty cap to fully reflect the combined HRV+RHR crash signal)
  • Inline barcode scan icons are accent-coloured and meet the 44x44 tap-target minimum (#71)
  • OFF nutrients flagged as estimated no longer pull rough numbers into your totals

Security

  • rc.53 clears every actionable Dependabot alert. multer 1.4.5-lts.1 → 2.2.0 (three high-severity DoS CVEs on the LTS line), nodemailer 8.0.7 → 9.0.3 (five CVEs including a TLS OAuth certificate-validation bypass and CRLF header injection), vite 6.4.1 → 6.4.3 (dev-only, server.fs.deny bypass on Windows). No user-facing changes; self-hosters just need to pull the new image.

Install / upgrade

  • Docker: pull the new image and restart your stack (see the README for compose snippets). The image is multi-arch (amd64 + arm64), so Raspberry Pi 4 / Pi 5 works without a source build (#76). The README’s compose snippet now includes env_file too, so INSECURE_COOKIES and other .env vars actually forward into the container.
  • Android: signed APK on the release page
  • Full CHANGELOG: main repo

What is NutriTrace?

Self-hosted nutrition tracker. Diary + Foods catalog (with Open Food Facts / USDA / Mealie search + barcode scan), wellness integrations (Fitbit, Garmin, Withings, Google Health, Health Connect), workouts, goals, statistics, recipes, multi-user, OIDC SSO, federation with LiftTrace and CookTrace, AI assistant (Claude / OpenAI / Gemini / Ollama). Docker on the server, Capacitor app on Android. AGPL-3.0 licensed.

LiftTrace is a self-hosted weightlifting tracker (Docker + Android, AGPL-3.0). rc.7 is the next public roll-up, bundling everything from rc.6 plus the rc.7 security-only follow-up.

What’s new

  • Per-exercise sharing. Every exercise now has a Share button in its detail header that produces a portable JSON file. Send it to another LiftTrace user through any channel (email, Drive, whatever), and they can import it. The Exercises page’s “+” button offers Import From File and Import From URL, so anyone can pull an exercise from a public URL (raw.githubusercontent.com works out of the box; github.com/blob URLs are auto-rewritten). Sets the stage for a community exercise repo pattern.
  • CSV workout export. The Workout Summary sheet has a download button that produces a long-format CSV (one row per set) with date, exercise, set number, reps, weight, RPE, warmup flag, completion state, and per-set / exercise / workout notes. Unilateral splits become two rows so left and right stay separate. PWA downloads directly; Android writes the file to Cache and opens the system Share sheet. Made for anyone feeding an external analysis pipeline.
  • Custom equipment. Add your own equipment types (Slackboard, Sandbag, Weight Vest, whatever’s in your home gym or hotel gym) via a new “+ Add” pill in the Exercise Editor’s equipment picker. Custom entries sync across devices via your account. They also appear as dashed-border chips in the Exercises filter row when at least one exercise uses them.
  • Multi-select equipment filter. The Exercises page equipment chip strip is multi-select now (was one-at-a-time), so you can pick everything you have access to today (Barbell + Dumbbell + Bodyweight when you’re travelling and the hotel gym is bare) and filter the library to matching exercises. Selection persists across navigation.
  • Animated banner redesigned. The illustrated SVG banners that used to fill each page’s header on Animated mode were retired (cross-viewport rendering issues on narrow phones, the art crowded the title and hid action buttons on the Exercises page). Setting Banner Style to Animated now paints the same compact accent bar as Gradient plus a subtle motion effect, picked under Settings → Appearance → Banner Animation: Shimmer (soft white sweep, default), Drift (slow hue rotation), Pulse (brightness breathing), or Aurora (overlapping accent clouds). All four honour Reduce Motion. Reclaims about 40 pixels of vertical real estate on every page.

Fixes

  • Editing the same workout from two devices near-simultaneously (phone + PWA) could clobber the other device’s just-completed sets with a stale in-memory snapshot; the workout store now refetches and merges before writing.
  • Browsers and password managers now correctly generate passwords that satisfy the policy (upper + lower + digit + special char, 8+ chars) when signing up, accepting an invite, resetting a password, or changing one from Profile. Previously the “suggest strong password” flow produced passwords without a special char, which the field then rejected.
  • Trace FAB visualizer on Android now tracks music dynamics with the same amplitude as it does on the PWA; was previously over-damped by an extra smoothing layer.

Security

  • Multer 1.4.5-lts.1 → 2.2.0 closes three high-severity CVEs on the LTS line (unhandled-exception DoS, crafted-request DoS, unclosed-stream memory leak).
  • Nodemailer 8.0.7 → 9.0.3 closes five CVEs including raw-option bypass, TLS OAuth cert validation, and CRLF header injection.
  • Vite bumped for the Windows server.fs.deny bypass patch.
  • npm audit at both root and server now reports zero vulnerabilities. Self-hosters should pull the new Docker image or rebuild from source.

Install / upgrade

  • Docker: pull the new image and restart your stack (see the README for compose snippets)
  • Android: signed APK on the release page
  • Full CHANGELOG: main repo

What is LiftTrace?

Self-hosted weightlifting tracker. Workouts and programs with progressive overload memory, statistics, exercise library with imports from Strong / Hevy / FitNotes / Jefit + custom exercises, radio + library music player (Subsonic / Jellyfin / Plex / Emby), body stats + weight trend, rest timer with countdown beeps, Smart Log (text or voice), superset / warm-up / RPE tracking, multi-user, OIDC SSO, federation with NutriTrace for calories-burned sync, AI assistant (Claude / OpenAI / Gemini / Ollama). Docker on the server, Capacitor app on Android. AGPL-3.0 licensed.

Features

  • Bulk Food Import via paste JSON or upload CSV (Settings → Import & Export)
  • Live nutrition preview on the Add to Diary sheet (macros update with portion / unit / servings)
  • Mass-aware unit conversion when scaling nutrition (g ↔ oz ↔ lb, ml ↔ cup, tsp ↔ tbsp)
  • Custom Units in Settings (“shot”, “scoop”, “stick”, etc.)
  • Scan Label: snap a photo of a nutrition label and the AI Assistant fills in the values
  • Smart Share / View on OFF: existing Open Food Facts products link straight to their wiki page for editing; new ones get a Share button to contribute back
  • Connection status banners across every integration with one-tap Test / Sync / Disconnect
  • Settings auto-save by default; no Save button to remember
  • Day rollover at midnight when the app stays open overnight
  • Barcode scanner now fully on-device on Android, no Google Play Services required (works on GrapheneOS / CalyxOS / e/OS)
  • Custom nutriment order from Settings is reflected everywhere (food editor, meal editor, diary nutrition bar)
  • Vitamin D, Calcium, Iron, and Potassium visible by default on new installs (FDA Nutrition Facts label mandatory fields)
  • Svelte 5 + Vite 6 + Express 5 + bcryptjs 3 framework upgrade (main bundle ~22% smaller)

Fixes

  • Disabling user management no longer triggers the setup wizard on every reload (#34)
  • Data APIs in single-user mode no longer return 503 “Setup required” on every call (#34 part 2)
  • Single-user mode: only the first food item added each day was visible in the UI. SQLite quirk on null user_id. Includes a one-time migration that recovers items already in the database (#37)
  • Food saves on Android no longer duplicate the previous food (#32)
  • “Most Used” / “Recently Used” food sort on Android now reflects real usage
  • MyFitnessPal Reports → Export CSV imports cleanly now (aggregate-per-meal shape)
  • Wellness scores refresh if today’s sleep finishes syncing after the morning snapshot
  • Import Nutrition History action row no longer overlaps the duplicate-date radios (#33)
  • Barcode scanner no longer gets stuck re-opening the camera after a scan
  • Barcodes that don’t match anything in OFF now drop you in the food editor with the code prefilled instead of a dead-end toast, so you can contribute the product back
  • Open Food Facts contribution now sends correct per-serving values and uploads your product image (both were silently broken)
  • AI Assistant respects AI_ENABLED=true and the full AI_* env-var set; toggle, settings card, and chat all honour the proxy (#36)
  • kcal / kJ values are consistent everywhere now: food editor, diary footer, meal totals, statistics, goals, weekly summary email, push notifications (#38)
  • AI Assistant Gemini models updated to 2.5 Flash + Lite (Google retired 2.0 Flash and 1.5 Flash)
  • nodemailer updated to 8.0.7 (patches an SMTP command-injection advisory)
  • Several smaller things, see the full changelog

Signed APK + docker image on the release page.

Self-hosted, AGPL-3.0, no telemetry, no account needed. docker compose up and go.