Ctrl K
ComunidadGuías…

CHANGELOG.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [3.4.0] - 2026-11-06

### Added

- music: Monitor singles by default
- search: Find tracks, singles and EPs, and let lists skip their total
- web: Select every match on the movie and series lists
- db: Mark uploaded download records
- upload: Stream multipart uploads into staging
- importer: Import uploaded records by copy
- music: Upload albums, tracks and discographies
- book: Upload ebooks and audiobooks
- api: Upload endpoints for music and books
- web: Upload files onto albums, tracks, artists and books
- web: Follow the design's hover token and progress scope
- web: Collapsible discography sections with bulk monitor, artist tags and total length
- web: Set the preferred book language on Settings → Library
- web: A compact, searchable book language picker
- activity: Name an uploaded track and drop torrent fields from uploads
- activity: Link queue, history and torrents to the title's page
- web: Follow the design on search rows, page-change scroll, Added columns and the series hero
- An admin stats page and the music library as an artist grid
- import: Choose a held album's tracks in the resolve prompt
- import: Hold an album on any title or file its tracks do not account for
- import: Hold an album an import would leave with empty tracks
- music: Choose which edition an album follows
- music: Choose a held discography pack's albums per folder
- library: Detect a library root that looks gone
- library: Migrate music and book root paths
- library: Accept files really gone from an offline root
- web: Show an offline library root and how to fix it
- library: Record when a missing file is confirmed and how long to wait
- library: Keep a missing file's row until the re-download wait ends
- library: List files missing from disk and forget them
- web: Mark files missing from disk and list them in settings

### Changed

- db: Serve reads from a query_only pool beside the single writer
- bittorrent: Read pieces past the page cache
- Merge remote-tracking branch 'origin/main' into ccr-4072b327-j2fbzi

### Fixed

- nix: Grant the music and book roots to the sandboxed unit
- lxc: Back up through streamline backup instead of copying the database
- deps: Update go modules (#153)
- metadata: Drop TVDB's disambiguation year from series titles
- library: Move sidecars and trickplay folders with renamed media
- library: Delete an episode's trickplay folder with it
- deps: Bump anacrolix/torrent past GHSA-2wrx-84qj-4pcg and GHSA-4mxg-hpvf-2386
- nix: Restore the pnpm store index in WAL mode
- web: Size the monitor dropdown to its options
- api: Answer a duplicate grab with grab_rejected, not a 500
- music: Keep a recording's row and file through a re-pick
- activity: Sort stalled downloads after active ones in the queue
- activity: Order a queue status group by progress in the Status sort
- torrents: Link the torrent's name, not the release line
- activity: Name the albums an uploaded discography filled
- music: Hold a file whose title contradicts its track
- db: Check foreign keys only after a migration applied
- music: Delete credits through the indexed foreign key
- db: Refresh stale planner stats at boot
- db: Index foreign keys and drop unused indexes
- hygiene: Count drift grace from missing_since and stop stamping present files
- db: Index media events by owner
- music: Load per-track credits behind the artist page
- hygiene: Revert albums and book slots when drift confirms a missing file
- db: Make media file owner indexes partial so large IN lists keep them
- music: Keep track credits out of the refresh every monitor toggle triggers
- hygiene: Leave an offline library root alone
- importer: Wait for an offline library root
- search: Grab nothing for an offline library root
- api: Refuse file changes on an offline library root
- library: Close the gaps the offline root review found
- api: Refuse album tag apply on an offline library root
- web: Refresh the health pill after a path migration and name each root's example path
- db: Index book_kind so a one-kind book library checks its roots cheaply
- web: Show a detail hero's status on the cover, only while something is pending
- db: Settle an album a re-hydration completes
- library: Leave files missing from disk out of tagging, transcoding and renames
- importer: Let an import fill a file missing from disk
- db: Keep other roots in the drift walk while a book root is offline
- library: Read a boolean wait as off and prefer a present file over a missing row
- library: Close the remaining gaps around files missing from disk
- metadata: Read every release of a group past the lookup's 25
- web: Describe the purge-uploads and music-tag-sync jobs
- web: Scroll the settings sidebar on its own
- stats: Read dynamic range and resolution from the probe
- stats: Leave bulk imports out of the pipeline
- web: Put the stats period above the sections it changes

## [3.3.0] - 2026-10-28

### Added

- Music entities
- Musicbrainz metadata provider
- config: Music quality profiles family
- metadata: Musicbrainz client
- Album cover art via posters proxy
- Music service
- Music REST endpoints
- Music SPA section
- Book entities
- Hardcover metadata provider
- Books config (hardcover key, paths, quality profiles)
- Hardcover client
- Book cover art via posters proxy
- Book service
- Books REST endpoints
- Books SPA section
- web: Section headings move into the page
- Plain-language manual search with tracker privacy and grab history
- library: Audio tag reading
- Ebook metadata reading
- Musicbrainz release-group search
- metadata: Hardcover book search and isbn lookup
- Music release parser and scoring
- Book release parser and scoring
- indexer: Album search
- indexer: Book search
- music: Import scan entities
- books: Import scan entities
- Download record album and book edges
- Music and book request entities
- Per-user subsonic password
- Per-user opds token
- Album release calendar
- Book release calendar
- audiotags: Tag writing
- Subsonic server package
- Opds feed types and auth
- Opds catalog feeds
- Opds downloads
- Music request flow
- Book request flow
- Album grabs
- book: Release search and grab per slot
- Music orphan scanner
- Adopt albums on music import commit
- Book orphan scanner
- Adopt books on import commit
- subsonic: Mount subsonic server
- opds: Mount opds server
- Import scan REST for music and books
- music: Album manual search and grab
- books: Book slot manual search and grab
- Music and book request REST
- importer: Import completed album downloads with tag writing
- importer: Import books per slot
- music: Backlog search and artist refresh schedulers
- book: Backlog search and author refresh schedulers
- rss: Auto-grab wanted albums from indexer feeds
- rss: Auto-grab wanted book slots from indexer feeds
- metadata: Deezer cover client, poster Put, album barcode and embedded-picture reader
- music: Resolve album covers from embedded art, folder, Deezer and the archive
- metadata: Honour Hardcover rate limit and daily budget
- e2e: Album, ebook and audiobook packs in the fake tracker
- web: Pull music, books, settings logs and bar titles from the design project
- Separate default quality profiles for movies and series
- api: Music and books contract for the design
- Music and book quality profiles, requests and lookup art for the design
- web: Wire the music and books design to the real API
- music: The backend the music design needs
- books: The book-first backend the books design needs
- Subsonic and opds access cards, hardcover key and codes, music and book calendar entries
- Music and book import review fields, release-group search and album requests
- web: Pull the second music and books design batch
- config: Seed a default music quality profile
- ci: Build the nix checks on the homelab builder
- activity: Name the album, pack artist or book on queue and history rows (#84)
- web: Lead the login page with SSO, fold the password form (#87)
- scheduler: Give music and books their own scheduled jobs
- metadata: Support preferred book language in Hardcover editions (#88)
- web: Redesign the dashboard around new arrivals across all four media
- library: List recent imports across movies, series, music and books
- music: Sort the artist list by name by default
- activity: Identify unmatched proposals as albums and books
- config: Add smtp section
- mailer: Add stdlib SMTP sender
- account: Add device email to the profile
- books: Send ebooks to a device by email
- api: Add book and series send endpoints
- web: Send books and series to an e-reader
- metadata: Read series membership and slugs from Hardcover
- books: Find series through translated titles and keep their slugs
- api: Expose series covers, slugs and translated matches
- web: Fan series covers and find series by translated title
- web: Bulk pause, resume and remove on torrents and activity
- subsonic: Serve the rest of the Subsonic API and OpenSubsonic (#99)
- music: Write the full MusicBrainz tag set without destroying the file's own (#105)
- web: Swipe actions on the activity and torrent touch rows
- History tab for music and books, swipeable detail tabs
- Record cancellations, monitoring and failed bulk imports for music and books; run the fake tracker anywhere
- music: Preview a release's files and grab only the missing tracks
- series: Grab only the missing episodes from a season or series pack
- series: Preview a season or series pack's files before grabbing it
- music: Preview a discography pack's files before grabbing it
- movies: Show the digital release date on the movie page
- activity: Open a download's torrent from the queue
- torrents: Show and search a builtin torrent by its release title
- search: List albums and episodes as their own search results
- web: Say "Searching…" while the search waits on its answers
- mediaserver: Targeted folder rescans, path mappings, coalesced refreshes (#144)
- config: Write the defaults when the config file is missing
- deploy: Unraid template and Proxmox LXC install script
- db: Back up the database before migrations, daily, and from the CLI
- download: Refuse a grab that would not fit on the download disk
- auth: API key read-only scope and expiry
- music: Co-artist edge and per-track artist credits
- metadata: Read each track's credited artists
- music: Shared albums on every artist's page, kept when an artist is deleted
- music: Tag each track with its credited artists
- music: Show shared albums and per-track artists
- subsonic: Serve shared albums under every artist
- music: Refuse single-file CD images before they download
- subsonic: Draw playlist covers as a mosaic
- ui: Add the add button to the music and books toolbars
- metadata: Make the MusicBrainz server URL configurable
- metadata: Make the MusicBrainz request interval configurable
- settings: Edit the MusicBrainz server and request interval

### Changed

- web: Move torrents, transcoding and imports to top-level routes
- db: Link download records to every episode they cover
- nix: Fetch Go modules without building the frontend
- migrate: Check every generated down step against the replayed schema
- migrate: Check the whole migration history and regenerate broken downs

### Fixed

- hygiene: Adopt library orphans in place instead of hardlinking a twin
- dashboard: Order recently added movies by file import time
- bittorrent: Report seeding only once every wanted piece is hash-verified (#74)
- web: Keep the topbar title still and stop doubling page headings
- web: Translate the remaining UI strings and fix search field chrome (#75)
- deps: Update go modules (#67)
- media: Rescan media servers after deletes, renames and bulk imports
- deps: Update go modules (#76)
- db: Keep a rejected upgrade's episode available
- download: Keep a completed record while its builtin torrent still seeds
- opds: Sanitize download filename and fix gosec directive
- subsonic: Log non-API errors before the generic envelope
- audiotags: Falsifiable replace spec, drop debug print
- media: Book and album grab review fixes
- bulkimport: Record span failures, dedupe adopted tracks, guard book commit and decisions
- Hardcover author role, shared book titles and subsonic POST params
- shared: Review findings for the design backend
- web: Review findings for the design backend
- music: Review findings for the design backend
- books: Review findings for the design backend
- db: Count held records as in flight for album searches
- Review findings for the round-2 backendA change
- Review findings for the round-2 backendB change
- Review findings for the round-2 spa change
- metadata: One member per person from musicbrainz relations
- metadata: Pass over fragment editions when naming a book's original
- indexer: Keep audiobooks out of music searches
- Never auto-grab or import a release that names another album or book
- download: Refuse a grab whose hash an in-flight record already holds
- bittorrent: Fail a magnet the path guard refuses after metadata
- mediaserver: Refresh media servers after music and book imports, renames and deletes
- opds,subsonic: Serve OPDS covers under Basic auth, stamp empty feeds, implement getIndexes
- posters: Serve the cached image's real type and leave no empty dir on a failed fetch
- request: Load the requester edge on the create response
- books: Date a book by its original edition and rank author matches first in lookup
- bulkimport: Adopt a multi-disc music album as one candidate
- subsonic: GetIndexes tracks album and track changes and never answers stale
- bulkimport: Clean the scan root before folding disc folders
- download: Revert stranded albums and book slots, read base32 magnet hashes as hex
- web: Read an import row by its own shape across scan-to-scan navigation
- web: Page title claims name their path so a left page's title never sticks
- web: Drop the in-page Imports heading the top bar already shows
- deps: Build with Go 1.27.2 and take toolchain patches from upstream (#82)
- web: Consistent monitoring, refresh and error feedback across movies, series, music and books (#83)
- music: Set aside album search results named for another album (#85)
- Prevent stale search results in releases dialog (#86)
- web: Artist rows show owned then wanted releases, never unmonitored ones
- music: An album monitored or dropped by hand survives the monitored-types catch-up
- db: The replace_mode migration rolls back
- Make #main positioned to contain sr-only labels (#89)
- series: A season or episode monitored by hand survives the specials catch-up
- deps: Update go modules (#93)
- web: Link Hardcover books through the id route
- mailer: Drop the connection when a message fails mid-write
- config: Accept a dotless smtp sender like streamline@localhost
- books: Leave unowned volumes out of a series send's skipped list
- importer: Refuse single-file CUE album images
- music: Park albums at failed after a refused import
- music: Settle a partial album on a failed or stranded grab
- books: Keep series status, the add pick and the book hits in translated series search
- books: Drop an empty series the batch did not return
- web: Stop retrying lookup covers that do not exist
- cli: Reject unknown commands instead of booting the server (#98)
- quality: Classify 4:3 1080p files as 1080p, not 720p (#100)
- web: Show Ctrl K, not ⌘ K, off Apple platforms (#104)
- docker: Re-run the vaapi apt upgrade on every CI build (#126)
- web: Make the activity page readable on phone, tablet and desktop
- web: The phone selection takes over the top bar
- download: Revert episodes, albums and books when a download is cancelled
- e2e: XML-escape the faketracker's .torrent link
- web: Let the release list scroll with the modal on phones
- music: Rank a partial MusicBrainz date after the fuller ones in its period
- music: Read tracker-tagged release names and interleaved editions
- download: Order the queue by status, then progress
- subsonic: List only albums and artists holding a playable file
- music: Skip video discs and take the standard edition on a same-day tie
- deps: Bump Go to 1.27.3 for GO-2026-6809 (#135)
- Run manual series and movie searches off the request and map add errors by cause
- movies: Return the digital release date from the add response
- importer: Import only the files the record's own torrent lists
- bittorrent: Delete only a removed torrent's own files
- web: Make search say what it finds and reach every settings section
- search: Rank the closest album and episode title first
- tvshow: Title aired episodes the metadata language has no translation for
- config: Ask for the secret again when a resource moves to another address
- config: Ask for the OIDC client secret again on an issuer change
- web: Hide Torrents and Transcoding from the nav while they are off
- downloads: Blocklist a release rejected from the held-download dialog
- db: Walk every episode of a failed record back, not just its anchor
- ci: Stop trying to set Issue Types — this repo has none (#142)
- web: Close phone search and bottom sheets on Back (#143)
- web: Show a distant API key expiry as a localized date
- web: Localize relative dates past one month
- artwork: Tell namesake artists apart for search tile photos
- search: Show covers and identifying text for every lookup hit
- music: Guard library artist photos against shared Deezer pages
- metadata: Wait a minute on a zero MusicBrainz Retry-After
- music: List a shared release group under every artist instead of failing the add
- music: Backfill track artists at any release size instead of bumping the credits layout
- music: Write track artists with MusicBrainz's join phrase and know a merged artist id by name
- music: Report a shared album's owner on every page and space the track credit lines
- subsonic: Name a split release's songs by their own artist and order co-albums by date
- music: Poll and show history for an artist's shared albums too
- music: Hand shared albums over inside the artist delete and re-tag them
- music: Log a shared album's link only once it is committed
- web: Tell a metadata provider's rate limit apart from a login lockout
- music: Hold MusicBrainz prefetch and background calls after a 503
- web: Count an artist's owed releases, not the whole discography
- download: Keep the records of torrents that still seed
- subsonic: Match search on artist and album names
- metadata: Drop Deezer's stock artist picture
- music: Run a refresh's artist photo lookup at interactive priority
- music: Refuse CUE images split one file per disc side
- db: Sort titles and artist names accent-folded
- activity: Show stalled downloads in the queue
- music: Scroll the release list on its own and open on a monitored album
- hygiene: Probe only movie and episode files
- importer: Fall back to file names for untagged album tracks
- music: Sort artists by their displayed name
- music: Treat remix, DJ-mix, mixtape and demo release groups as other
- music: Leave bootleg-only release groups out of the discography
- music: Flag search results that name neither the artist nor the album
- library: Read a year between the artist and the title of a release name
- deps: Update go modules (#149)
- music: Ignore search and bookkeeping events when pruning unlisted albums

## [3.2.0] - 2026-09-25

### Added

- nix: Package, NixOS and home-manager modules, VM test
- metadata: Store TMDB translated and alternative titles
- indexer: Match releases against the provider alias set
- indexer: Record the alias count on search spans
- web: Fade images in once fully decoded
- web: Fade backdrops, cast and lookup images in too
- auth: Let an OIDC provider auto-provision accounts under invite mode
- api: Page the pending adoption list

### Fixed

- ci: Drive the Claude CLI directly for release notes
- ci: Give the release-notes prompt the house style
- web: Translate the nav count lines instead of hard-coding English (#61)
- download: Match adopted movie torrents against aliases too
- media: Report files a delete did not remove and prune orphaned metadata
- download: Spare the seasons a multi-season pack claims
- indexer: Refuse a longer show built on this one's name
- download: Scope a record's episode-state writes to the episodes it claims
- download: Record what an adopted torrent's episodes are
- bittorrent: Survive an unusable announce URL and clean up a failed add
- bittorrent: Report fetching until file priorities are applied
- ci: Give each derived hash its own sentinel so the pins stop flip-flopping
- ci: Derive each package hash from its own attribute
- deps: Update go modules (#66)
- importer: Coalesce an enqueue that lands while its import is in flight
- ci: Enforce the release-notes no-tools rule in the CLI call
- requests: Count only the caller's own requests for request_only
- web: Gate admin-only pages, links and queries by role
- web: Hide the free-space tile from non-admins
- restapi: Answer the spec 403 on member-only movie and series verbs
- auth: Log the account an admin acts on as target.user.*
- web: Hide library controls from request_only users
- library: Keep deletes and renames inside the library root
- library: Widen a dash-chained release group in linear time
- importer: Fail a replacement with no usable media before removing the old file
- tvshow: Leave a pruned episode's file on disk on metadata refresh
- config: Redact secrets held inside list entries in the audit line
- config: Keep the config file owner-only on every write
- auth: Revoke a user's other sessions when OIDC claims change their role
- auth: Keep API keys and re-pointed issuers away from account-granting config
- auth: Withhold the trusted-network grant from cross-site writes
- api: Keep the download client's address out of the pending preview error
- otelx: Cap every outbound response body after gzip inflation
- download: Hold every release redirect hop to the indexer allowlist
- download: Bound adoption work per tick and prune stale proposals past the bind limit
- bittorrent: Refuse torrent names that land on other data and make removal survive a restart
- bittorrent: Cap how many torrents the builtin engine holds
- bittorrent: Keep release-named trackers and webseeds off internal addresses
- ci: Build release notes in a job that holds no publishing credentials
- api: Hand members a sealed release handle instead of the indexer's keyed link
- auth: Withhold the trusted-network grant from hosts DNS rebinding can forge
- api: Tell a grab with an expired release handle to search again
- media: Leave a file in place when the naming template would rename it out of the library
- media: Refuse a single-file delete outside the library root with 409
- download: Reject malformed listing hashes and prune proposals of disabled clients
- bittorrent: Refuse a torrent whose name holds another release's data on disk
- importer: Place a replacement before removing the file it replaces
- otelx: Bound each small JSON answer to its own ceiling

## [3.1.0] - 2026-09-16

### Added

- ci: Publish a chart release with Claude-written notes
- observability: Recover job panics and close the transcode/scheduler metric gaps
- auth: Observe registrations, denials and the rate-limiter lapse
- download: Count adoption, selection and reachability outcomes
- indexer: Classify query failures and instrument the metadata providers
- library: Log destructive file operations and count import runs
- db: Log lifecycle transitions, migrations and the request workflow
- events: Add library, file, transcode and request event types
- events: Record adds, removals and monitoring changes from mutation hooks
- media: Record renames, re-identifies and metadata refreshes
- transcoding: Record terminal job outcomes in the activity feed
- download: Record cancellations and widened grabs
- request: Record approvals against the title they added
- series: Record one monitoring event with an episode count, not one per episode
- web: Show loading skeletons instead of bare text while lists and panels load
- web: Narrate the wait for release search and scans, and lift the grab modifier into the modal footer
- series: Count seasons on the card and keep specials out of show totals
- cast: Normalize cast into persons and credits with real provider ids
- web: Add a cast member page and search people from the palette
- cast: Fetch person details from TMDB and TVDB at ingest
- web: Show biography, life facts and brand links on the cast page
- activity: Forget a proposal so its torrent can be adopted again
- events: Record bulk episode events once per series
- download: Adopt a torrent whose file is already in the library as completed
- tvshow: Keep TVDB aliases on the show and adopt torrents named by them
- transcoding: Defer an encode while its torrent is still seeding
- web: Surface defer_seeding and the deferred re-check on queued jobs
- web: Make every series detail kebab action work
- web: Edit a quality profile's transcode policy
- auth: Choose an invite's lifetime when creating it
- web: Icon the type and monitoring dropdown items
- api: Count list facets against the other filters
- scheduler: Report run progress and broadcast state changes
- jobs: Report progress from every per-item loop
- api: Stream schedules as server-sent events with run progress
- web: Live schedules page with run progress
- scheduler: Let a manual run waive job throttles
- transcoding: Leave lean sources alone with if.min_video_bitrate
- transcoding: Make hw_accel vaapi hardware-only
- download: Remove a builtin torrent with its files once seeding ends
- series: Surface per-series grab and import history
- series: Name what each history event touched
- movies: Give the recommendation add its full detail panel

### Changed

- release: One _changelog task for both changelogs
- release: Tag and push with jj instead of git
- web: Share one event mark table across both activity feeds
- web: Apply bulk import decisions in one request
- requests: Filter by media type server-side
- web: Share detail components and alias @components/@lib imports
- settings: Drop the App name card

### Fixed

- release: Ignore chart-v* tags in git-cliff and goreleaser
- ci: Stop the oldest changelog section swallowing the link block
- ci: Pin the release-notes model instead of drifting with the CLI
- release: Keep helm-scoped commits out of the app changelog
- observability: Stop log.app.enabled from disabling the whole pipeline
- events: Stop a failed event write from failing the mutation it records
- web: Portal the global activity bar to body so it paints above modals
- web: Give each activity event mark its own icon
- calendar: Fall back to the theatrical date when TMDB has no digital release
- web: Scroll long activity lists inside the list, not the page
- web: Give the transcoding page the app's own dropdown and a right-aligned chevron
- web: Tint rejected slate rather than red
- search: Fold punctuation so a title's commas need not be typed
- db: Keep foreign keys off across a migration run
- web: Open the rename modal from the series page kebab
- series: Make a show's monitored flag gate its episodes
- web: Size the IMDb wordmark so it resolves at chip size
- bulkimport: Match an episode file on its parent folder when the basename is bare
- bulkimport: Walk every folder above a bare episode file, not just one
- download: Let a folder torrent's sidecar files pad the size match
- download: Stop vetoing a same-size adoption on a template-parsed group
- importer: Drop a moved torrent from its client once its record imports
- library: Read the library config live in the import service
- activity: Badge History with the total, not the page
- settings: Lock every control on a read-only instance
- api: Stop logging a closed schedule stream as an error
- transcoding: Refund the attempt when boot recovery requeues a job
- docker: Drop pebble from the vaapi image so grype scans only our binary
- download: Adopt, locate and recover imports without stranding episodes
- bittorrent: Fence test fixtures on piece marks after verify
- series: Report a show's last import so arrivals surface new episodes
- people: Carry the episode rollup on series credits
- web: Hold the person backdrop still when the biography expands
- web: Stop read-only fields inviting an edit
- imports: Scroll the scan list inside its card

## [3.0.0] - 2026-09-08

### Added

- web: Serve the dashboard at the root route, drop /dashboard
- web: Media probe & import verification UI from design
- config: Add ffmpeg block
- ffmpeg: Ffprobe-backed media probe package
- db: Media info columns on media_file
- db: Thread probe info through media_file writes
- importer: Probe source media before transfer
- hygiene: Media-probe backfill job
- api: Expose probed media_info on media files and episodes
- api: Surface missing ffmpeg on system info
- config: Land probe verification and codec settings
- db: Held status and hold_reasons on download_record
- importer: Probe verification rules
- db: Held download lifecycle helpers
- importer: Hold suspicious imports for review
- api: Resolve held downloads
- api: Series type override, bulk import decisions, path-drift warning
- events: Media events for series and episodes, wire drift and search
- ui: Change-match action and series-aware activity feed
- activity: Add an events view for the media feed
- library: Make the monitored filter tri-state
- quality: Scoring engine core
- quality: Built-in format library
- config: Custom_formats resource and scored profile fields
- config: Custom format CRUD
- **BREAKING** rss: Score-ranked release selection
- rss: Feed-driven score upgrades
- api: Custom-formats endpoints and release score annotations
- restapi: Custom format handlers
- restapi: Score annotations on releases and files
- ui: Custom formats settings page
- ui: Scored profiles and release score display
- quality: Builtin format descriptions
- config: User custom format descriptions
- quality: Curate builtins, group chips, richer presets
- quality: Per-file replacement predicate
- importer: Per-episode replacement inside season packs
- config: Replace_whole_season quality profile key
- rss: Per-episode season pack upgrade selection
- api: Expose replace_whole_season on quality profiles
- ui: Replace_whole_season on the quality profile form
- web: Global in-flight indicator
- quality: Scale size bounds by the episode count a release carries
- config: Add torrent_listen_port to override the builtin client's port
- quality: Name the default profile in API responses
- series: Track episodes through downloading and importing
- torrents: Persist upload totals and surface known peers
- quality: Drop the replace_whole_season profile key
- bittorrent: Persist per-torrent file selection state
- download: File listing and selection on the client interface
- download: Selection intent and resolution on download records
- config: Download.selective_files flag
- download: Resolve a wanted-episode set to torrent file indexes
- download: Selective grab resolves the keep-set before AddTorrent
- rss: Pack grabs carry the episode set they serve
- download: Re-grabbing a held hash widens the selection
- download: Qbittorrent file selection
- download: Transmission file selection
- download: Deluge file selection
- download: Scheduled pass resolves pending file selections
- download: Zero-waste magnet adds for builtin and qbittorrent
- download: Deluge magnets resolve metadata before the add
- api: Expose selection state on queue rows and torrent files
- web: Selective downloads show selected size, not a stuck bar
- db: Per-show upgrade-candidate query
- rss: Missing-search packs replace what they beat
- rss: Missing search skips episodes a grab already serves
- mediaserver: Refresh the section matching the imported media kind
- settings: Edit both plex section keys
- bittorrent: Rebindable packet conn for utp and dht
- bittorrent: Rebindable tcp listener
- bittorrent: Engine owns its peer listening sockets
- bittorrent: Move the listen port without a restart
- api: Endpoint to move the builtin engine's listen port
- bittorrent: Dht announce on port move, plus socket helper cleanup
- download: Let an operator identify an unmatched adopted torrent
- metadata: Translate TVDB season names
- web: Search one season from the episodes tab
- settings: Expose library, download, metadata and lockout config
- settings: Expose the remaining config keys, editable or read-only
- web: Name the movie or series in the manual search modal title
- api: Report grab_failures on an episode
- web: Raise touch targets to 44px below lg
- web: Raise dashboard touch targets below lg
- library: Give episode templates tvdb_id, source, codec and group
- activity: Preview which episodes a pack proposal would import
- activity: Decide a pack proposal per episode, not per anchor
- quality: Answer language and audio-track conditions from the probe
- dashboard: Name what an import added in the arrivals row
- movies: Carry an importing status from the monitor through to counts
- web: Badge movie and series cards as importing
- series: Roll a show's in-flight grab up onto the library list
- web: Name what a series card has landing, not just its gaps
- activity: Sort the tables by column, and open with the queue
- library: Add the monitoring facet, series in-flight filters and release dates
- web: Pull the facet toolbars and release-day captions down from the design
- web: Ship a web-app manifest so the SPA installs to the home screen
- library: Add a bulk Rename files action to both library lists
- Transcoding config
- Transcode job entity
- Transcode job store
- Queue transcode on import
- Resolve ffmpeg and read HDR and audio streams
- Transcode rules, ffmpeg args and progress parser
- Transcode worker
- Transcode library scan
- Transcoding REST endpoints
- web: Transcoding queue and settings pages
- config: Transcoding.verify band and checks
- db: Rejected transcode job status
- transcoding: Reject an encode that fails output verification
- api: Expose transcode verification
- web: Rejected transcode jobs and verification settings
- config: Transcoding.hw_accel and hw_device
- transcoding: VAAPI encoding with a probed software fallback
- api: Expose hardware encoding on /config/transcoding
- web: Hardware encoding settings
- deploy: Vaapi image variant
- transcoding: Keep 10-bit sources at 10 bits on the VAAPI path
- indexer: Scope Prowlarr searches by kind and filter on release ids
- task: Release:app cuts the app release end to end

### Changed

- series: Push list filtering and episode counts into SQL
- db: Index the series tree foreign keys and cache posters at w500
- hygiene: Batch drift-check last_seen bookkeeping into one update per tick
- ui: Budget grid mounts on the movies and series pages
- db: Replace_mode on download records
- rss: Movie upgrades use the shared replacement predicate
- web: Move the releases table to shared
- Derive GOMEMLIMIT from the cgroup memory limit
- db: Index the hot predicates and the unindexed foreign keys
- db: Size the page cache, bound the WAL and analyze on boot
- movies: Count statuses in one GROUP BY pass
- bittorrent: Persist uploaded bytes only when they moved
- scheduler: Derive last_started_at instead of writing it every run
- download: Pace the file-selection pass inside its run
- auth: Debounce last_seen_at writes and split session lookup failures from 401
- bittorrent: Cap the anacrolix peer pool and unverified-bytes buffer
- db: Drop the cast blob from every list projection
- config: Memoise assembled quality profiles per config generation
- indexer: Bound torznab responses and cap merged results
- download: Skip the adoption scan when no client is enabled
- db: Open the raw driver when OTel has no endpoint
- series: Apply a monitoring preset in four statements, not one per row
- scheduler: Stagger the first run of each job at boot
- observability: Sample traces and size the log batcher for a small host
- hygiene: Page the drift check over a lean projection
- library: Index tracked shows by tvdb id without the episode tree
- movies: Push list filtering into SQL and store parsed file fields
- web: Paginate the library lists and drop the monitor filter
- library: Drop the never-populated {imdb_id} naming token
- **BREAKING** api: Stop carrying imdb_id end to end
- web: Give the app one dropdown surface
- web: Unfold the sidebar's activity group into two rows
- db: Lean-load the movie on the pending queue
- **BREAKING** config: Rename auth.oidc_default_role to auth.default_role
- task: Merge the chart release into the release namespace
- middleware: Body-limit carve-out uses auth.IsAdmin

### Fixed

- ffmpeg: Probe stream duration and skip cover art
- hygiene: Don't let unreadable rows consume the probe batch
- web: Surface the ffmpeg warning and restart notice
- config: Drop ffmpeg.path existence validation
- ffmpeg: Pick the largest video stream, not the first
- web: Label always_ask hold reasons
- web: Match the backend's resolution buckets
- web: Normalize formatDuration hour rollover
- web: Hide queue controls on held rows
- importer: Verify before replacing existing files
- download: Forward the deleteFiles flag to the client
- db: Held records keep their episodes from reverting
- importer: Fall back to the release title for the resolution claim
- importer: Don't hold records whose source file is missing
- api: Reject unknown resolve actions
- api: 409 queue verbs on held downloads
- web: Refresh system info after an ffmpeg config change
- bulkimport: Parse numeric titles and rank candidates before truncating
- bulkimport: Relocate existing files in rename mode and attach on re-add
- library: Paginate list fetches and stop mis-adopting same-titled shows
- bulkimport: Match on original title, fix nil-span panic, document the batch
- library: Collapse whitespace in sanitised paths and prune emptied dirs
- ui: Pin series toolbar rows and show the synopsis on mobile
- library: Size floor for episodes and TVDB search fallback
- posters: Size cache for the hero render and refill it on metadata refresh
- series: Refetch the poster on metadata refresh
- pathmigrate: Scope the boot drift warning to live download rows
- hygiene: Start the drift grace clock without clearing missing_since
- movies: Carry media files in list responses
- sysinfo: Stop rendering a branch build as a release version
- calendar: Stop labelling untitled episodes as digital releases
- ui: Stop layout shifts and reclaim space across the shell
- docker: Let the frontend stage see pnpm-workspace.yaml
- rss,importer: Close per-episode replacement seams
- rss,db: Stop stranding upgrade targets in downloading
- ui: Render searched activity events in movie history
- web: Clear the SPA typecheck and wire it into lint
- deps: Bump moby/go-archive past CVE-2026-17106
- series: Treat undated episodes as unaired, not wanted
- library: Stop parsing hyphenated source tags as release groups
- torrents: Give the torrent list a stable order
- library: Keep hyphenated release groups and fold bare WEB onto WEB-DL
- web: Refresh nav counts after every mutation
- torrents: Drop the download record when its torrent is removed
- bittorrent: File selections survive restart and metadata resolve
- bittorrent: Progress, completion and ratio over wanted files only
- download: Close pending-selection exits and final-review findings
- db: Replace_mode only ever raises
- mediaserver: Plex refresh falls back to every section
- web: Repaint library views when the download queue changes
- web: Load lookup posters eagerly so they render in modals
- mediaserver: Discover sections for a saved server using its stored token
- web: Latch the config form layout so a breakpoint flip cannot remount it
- web: Let a read-only operator pick and copy plex section keys
- web: Show only the picked plex sections in the config snippet
- bittorrent: Restore tcp dialing and single utp socket under owned peer sockets
- bittorrent: State the ipv6 narrowing honestly and stop upnp in tests
- i18n: Translate the three missing french keys
- dashboard: Mix series into the recently-added and wanted rows
- library: Cut a season pack's title at the season token
- web: Quieter, single-cadence nav and dashboard polling
- web: Give importing its own status kind
- indexer: Scope every TV search to what it asked for
- library: Read French season packs, chained ranges and mixed-case resolutions
- dashboard: Count downloading episodes in the downloading tile
- indexer: Report prowlarr as feed-incapable instead of feed-empty
- download: Bound the qbittorrent add response
- ffmpeg: Bound ffprobe stdout
- indexer: Dedupe merged results by release identity
- web: Count the downloading tile off the live queue
- api: Honour series_id on the activity feed
- indexer: Prefer TV releases that name the show being searched
- rss: Don't spend a grab failure on an unreachable indexer
- library: Match an anime file numbering SxxExx by absolute number
- api: Name a rejected grab's 422 so the UI can say why
- importer: Walk a pack's subdirectories so a whole-series torrent imports
- download: Anchor a pack on the first episode it can fill
- library: Read a three-digit episode number
- events: Stop the owner hook failing an owner-less record insert
- deps: Update go modules (#46)
- library: Read parsed_source off the release name, not the renamed file
- quality: Stop a negate condition matching input nobody recorded
- quality: Score a library file from its stored columns, not its renamed path
- web: Narrow the pack season index rather than assuming it
- db: Unstamp existing probes when the stream columns arrive
- calendar: Hold three items per month cell, floored by the lg row height
- settings: Pin the sub-nav below the toolbar, not under it
- indexer: Filter movie search results to the film that was searched
- restapi: Answer grab_rejected for a pack grab with no wanted files
- web: Claim the bottom-sheet drag on touch, not just the header
- db: Unstamp last_refreshed_at so the new release dates backfill
- web: Let the library filter field take the row's slack
- web: Keep the top bar clear of the status bar when installed
- rename: Build names from the media_file row, not the last rename
- deps: Update go modules (#54)
- Address the transcoding branch review
- web: Tell a refused scan apart from a running one
- docker: Upgrade base packages in the vaapi image
- library: Fold accents when normalizing titles for matching
- rss: Never auto-grab a release naming another show
- library: Search titles accent-folded and keep the list on screen while filtering
- library: Keep list filters when returning from a detail page
- spa: Name the reason when an upload is too large

## [2.0.0] - 2026-08-17

### Added

- imports: Search shows in the tv import review
- web: Add a monitored filter to the library toolbars
- dashboard: Count series and break free space down by library path
- series: Store episode overviews and expose the media file path
- web: Add an episode details modal, badge unmonitored episodes missing
- web: Bulk-select and act on movies and series
- web: Split torrents onto their own activity page
- web: Import the dashboard reworks from the design project
- web: Select controls and persisted sort for movies and series
- web: Show file path on movie detail file card
- movies: Enforce single media file per movie
- series: Enforce single media file per episode
- series: Unmonitor TBA episodes until a title or air date lands
- web: Drop the Files tab from series detail
- series: Opt-in specials monitoring with settings toggle and bulk apply
- **BREAKING** rss: Scan indexer feeds for wanted episodes
- web: Floating add button and select menus that stay on screen
- web: Split add/request flow with lookup detail and touch screen
- library: Advanced settings section with library path migration
- web: Responsive phone and tablet UI for library, detail and nav
- media: Serve movie and series detail metadata from the database
- web: Touch search surfaces and add pill for phone and tablet
- web: Activity and torrents on touch
- web: Dashboard on touch and add affordance follow-up
- web: Translate the SPA with paraglide js (en/fr)
- web: Sync calendar, imports and requests touch layouts from design
- web: Sync settings and account touch layouts from design
- server: Add security-headers middleware (CSP, XFO, nosniff, referrer, HSTS)
- auth: Meter /api/v1 credential failures per IP
- web: Pull dashboard and calendar layout work from the design project
- cli: Add user administration to the auth command group (#22)
- auth: Deny identity mutations to API-key requests

### Changed

- web: Drop the seasons tab and badge fileless series as missing
- web: Drop dead QueueItem type, stale Density import and unused EmptyCard
- role: Make db params take a role that names its authority
- web: Drop unreachable states from the live queue state map

### Fixed

- otelx: Bound outbound requests with a client timeout
- metadata: Collapse concurrent tvdb logins with singleflight
- web: Render one canonical version string
- web: Stop counting unmonitored fileless titles as wanted, colour the toolbar counts
- web: Split wanted from missing in series and season episode counts
- web: Drop hero isolate so the play-on menu paints over the tab bar
- web: Hide the dashboard scroller's native scrollbar
- web: Stop the torrents page flickering and the nav highlight sticking
- bittorrent: Bound the lost peer wakeup stall with a short keepalive
- download: Derive infohash locally when qbittorrent reports none
- restapi: Keep indexer name on manual grab results
- web: Reveal poster card overlays on keyboard focus only, not mouse clicks
- web: Show em-dash placeholders for missing file fields on movie detail
- web: Negative-cache missing posters instead of re-requesting on every mount
- series: Scope season rollups to monitored or downloaded episodes
- web: Match the season progress bar to the hero bar
- web: Show relative dates as year/month/day spans
- web: Skip the torrent nav query when the builtin engine is off
- rss: Skip feed and missing-search passes when no download client is enabled
- settings: Correct read-only lock scope and gate invites on registration mode
- web: Rework add-sheet drag for mobile Gecko smoothness
- web: Poster taps select instead of navigating in select mode
- web: Keep free-space value clear of the dashboard disk info button
- media: Key movie metadata staleness off last_refreshed_at
- tvshow: Degrade on cast fetch failure and bound the refresh tick
- web: Hide the empty layout section and correct series bulk search
- web: Render upcoming episodes in the calendar and dashboard lists
- web: Ignore accents and case in library search
- web: Show the import transfer-mode select in rename mode
- media: Drop cached posters and sidecars when deleting a title
- ci: Compile paraglide messages in the docker frontend stage
- restapi: Enforce default-deny role guard on every /api/v1 operation
- download: Restrict grab download URLs to configured indexers
- calendar: Show each upcoming episode's real status
- ci: Pin third-party actions to commit SHAs
- otelx: Keep indexer credentials out of traces and errors
- auth: Keep the generated seed admin password out of config and logs
- web: Block cross-site posts to the auth endpoints
- deploy: Harden the runtime image, chart securityContext and image CI
- download: Drop the duplicated release-source guard
- otelx: Redact fragment-only URLs and bound the unwrap walk
- server: Trust X-Forwarded-* only from configured proxies
- auth: Bound the login limiter without evicting throttled keys
- auth: Believe X-Forwarded-* only from configured proxies
- middleware: Accept the SPA session cookie without Fetch Metadata
- config: Create data_dir instead of requiring it to pre-exist
- web: Compare Origin against a bare serialised origin only
- web: Share one return-to guard and close its backslash hole
- auth: Stop successful logins from spending the rate limit
- web: Keep the app shell off the login page
- config: Keep env-owned values out of the write-back and guard what it writes
- auth: Gate OIDC account linking and cap the roles a provider may grant
- auth: Close the login enumeration oracles and the stored-hash DoS
- posters: Cap the artwork fetch at 20 MB
- middleware: Send no-store and COOP on non-static responses
- middleware: Accept a same-origin GET carrying only a Referer
- download: Contain torrent-name paths and serialize entity imports
- restapi: Clamp pagination limits to their documented maxima
- restapi: Tighten infra read roles, error output and draft tests
- request: Back active-request de-duplication with a unique index
- ent: Mark the password and invite token hashes sensitive
- auth: Bound self-registration, admin demotion and API keys
- deps: Update go modules (#9)
- deploy: Bind the observability stack to loopback and document the risk (#12)
- web: Give calendar kinds their own colours and unify the poster pill
- web: Title-case the live queue's Importing state word
- bittorrent: Disable WebTorrent to drop the WebRTC attack surface (#17)
- deps: Update module github.com/knadh/koanf/providers/env to v2 (#39)
- server: Set HTTP server timeouts to stop Slowloris (#14)
- server: Cap request body size on web auth and API JSON decoders (#19)
- auth: Unify forwarded-proto TLS detection for cookies (#13)
- mediaserver: Restrict Plex PIN flow to the starting admin (#15)
- auth: Keep the last admin during OIDC role sync (#20)
- auth: Revoke API keys on password change and admin reset (#18)
- auth: Revoke sessions when an admin changes a user's role (#16)
- auth: Require a session to create API keys

## [1.3.0] - 2026-07-31

### Added

- imports: Scan tv folders against tvdb
- dashboard: Report library filesystem free space

### Fixed

- web: Read sidebar version from /system/info instead of a hardcoded dev string
- restapi: Default page and limit on the movie list
- web: Add status tokens for stalled and fetching
- web: Drop the redundant add-torrent cta and row density toggle
- web: Give movies and series a matching toolbar layout
- web: Stop series detail actions reflowing between tabs
- auth: Record api key last-used timestamps

## [1.2.0] - 2026-07-30

### Added

- movies: Flag already-added titles in TMDB search
- web: Failed movie tab and already-added search flags

### Changed

- web: Shared kebab menu, formatBytes, session cards, read-only chrome
- server: Reuse grab conversion and scan-failure helpers

### Fixed

- auth: Drop revoked and expired rows from session list - closes #2
- rss: Episode search eligibility and per-item quality profiles
- download: Treat stopped and queued complete qBittorrent torrents as completed
- library: Episode drift revert, movie delete cascade, episode import parity
- tvshow: Profile validation, monitored-aware season views, pilot preset, counters
- auth: Atomic invite consumption, user delete with invites, limiter pruning
- metadata: Synchronize TVDB token and re-login on expiry
- server: Importer shutdown panic, scheduler rootCtx race, DB close on boot failure
- api: Expose failed movie status
- web: Movie quality-profile flow, add-modal reset, on-accent contrast
- web: History pagination, drawer scroll lock, play-on error state
- web: Scan navigation, series param reset, settings breadcrumbs
- web: Request approval invalidation, auth form reset, filter debounce, number field clearing
- web: Debounce user search, clearable priority fields
- server: Plex-only library_section on update, honest is_current for admin sessions
- web: Send explicit clear signal for library_section
- movies: Surface quality_profile in API responses and modal default option
- deps: Bump vulnerable modules and pin Go to 1.26.5
- series: Wire series renamer into REST server
- library: Return 404 for unknown import decision targets
- movies: 404 on refreshing metadata of unknown movie
- media: 404 renaming files of an unknown movie or series
- requests: 404 on approve/deny/reopen of unknown request
- library: 404 listing files/shows of an unknown import scan
- library: Scope import decision writes to their scan
- bittorrent: Deterministic teardown and port reuse in restore integration spec
- bittorrent: Drain piece-completion writes before closing the store

## [1.1.0] - 2026-07-21

### Added

- config: Builtin download client config
- db: Torrent session entity
- bittorrent: Builtin bittorrent engine
- bittorrent: Seed limits and torrent management views
- download: Builtin client in download manager
- server: Wire builtin torrent engine
- api: Torrents REST endpoints
- web: Add built-in torrent client UI
- torrents: Upload speed, eta, badges — close the design-fidelity gap
- web: Apply claude-design UI adjustments

### Fixed

- build: Inject version into internal/buildinfo, not main
- build: Glob web/static so asset changes rebuild the binary
- bittorrent: Address builtin torrent client review findings
- web: Unset builtin knobs read as auto/unlimited
- web: Draw checkbox glyph ourselves, native accent glyph off-center
- bittorrent: Drive downloads via file priorities, not DownloadAll

## [1.0.0] - 2026-07-12

### Changed

- Initial commit
- release: Add release:tag task, drop redundant release:gh

### Fixed

- sysinfo: Make disk-usage probe cross-platform for releases (#1)

[3.4.0]: https://github.com/datahearth/streamline/compare/v3.3.0..v3.4.0
[3.3.0]: https://github.com/datahearth/streamline/compare/v3.2.0..v3.3.0
[3.2.0]: https://github.com/datahearth/streamline/compare/v3.1.0..v3.2.0
[3.1.0]: https://github.com/datahearth/streamline/compare/v3.0.0..v3.1.0
[3.0.0]: https://github.com/datahearth/streamline/compare/v2.0.0..v3.0.0
[2.0.0]: https://github.com/datahearth/streamline/compare/v1.3.0..v2.0.0
[1.3.0]: https://github.com/datahearth/streamline/compare/v1.2.0..v1.3.0
[1.2.0]: https://github.com/datahearth/streamline/compare/v1.1.0..v1.2.0
[1.1.0]: https://github.com/datahearth/streamline/compare/v1.0.0..v1.1.0
[1.0.0]: https://github.com/datahearth/streamline/tree/v1.0.0

<!-- generated by git-cliff -->