- Change episode_offset type from int to int | None
- Only set episode_offset when virtual season split is detected
- For simple season mismatches (e.g., RSS S2 → TMDB S1), episode_offset is now None
- Improve reason messages to clarify when episode offset is/isn't needed
- Update database migration version to 7 and add migration check
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When offset scanner detects a mismatch, it now stores:
- suggested_season_offset: recommended season offset value
- suggested_episode_offset: recommended episode offset value
These values are returned in the API response for bangumi that need review,
allowing the frontend to display them to help users configure the correct offset.
Database migration v7 adds the new columns.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When user sets season_offset, the save path now reflects the adjusted season:
- _gen_save_path() uses (season + season_offset) for folder name
- Files saved directly to correct folder (e.g., Season 2 instead of Season 1)
- update_rule() now updates qBittorrent RSS rule's savePath when offset changes
- Existing torrents are moved to the new location
Renamer changes:
- gen_path() no longer double-applies season_offset (folder already has it)
- Season number taken directly from folder name
- Added path normalization for better save_path matching
- Added debug logging for offset lookup
Torrent name matching (title_raw) remains primary fallback for finding bangumi.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove the username requirement check that was blocking passkey login without
entering a username. The backend already supports discoverable credentials mode.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When multiple bangumi subscriptions share the same save_path (e.g., split-cour
anime with S01E1-12 and S01E13-24), the renamer's match_by_save_path() query
returned multiple rows causing "Multiple rows were found" errors.
Changes:
- Add qb_hash field to Torrent model for direct hash-to-bangumi linking
- Add database migration v6 for qb_hash column with index
- Add tags parameter to add_torrents() in all downloader clients
- Tag new torrents with ab:{bangumi_id} for offset lookup during rename
- Implement multi-tier lookup in renamer: qb_hash -> tags -> torrent_name -> save_path
- Fix auth tests by mocking DEV_AUTH_BYPASS for proper 401 testing
The renamer now reliably finds the correct bangumi and its offsets even when
multiple subscriptions download to the same directory.
Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
FastAPI's merged_lifespan mechanism triggers lifespan events for each
nested router layer. Since program_router is included in v1, which is
included in app, the startup handler was being called 3 times.
Added _startup_done flag to ensure Program.startup() only executes once.
Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
Mobile Layout Fixes:
- Fix config page horizontal overflow by adding min-width: 0 constraints
- Fix sticky action buttons positioning on config page
- Add loading states to config save/cancel buttons
- Reduce topbar padding and icon spacing for mobile
- Make search button fill space between logo and action icons
- Fix search modal header layout with close button visibility
Component Improvements:
- ab-topbar: Flex search button with "Click to search" text on mobile
- ab-status-bar: Reduce button sizes and gaps on mobile
- ab-fold-panel: Add max-width and overflow constraints
- ab-setting: Add max-width: 100% to prevent input overflow
- ab-search-modal: Reduce padding and element sizes on mobile
- ab-mobile-nav: Increase label font-size from 10px to 11px
- ab-sidebar: Fix toggle animation (rotateY → rotate)
Calendar & Bangumi Pages:
- Add lazy loading to poster images for better performance
- Move unknown air day items to separate section below grid
- Add actionable CTA button to empty state with useAddRss hook
Login Page:
- Add will-change: transform for background animation performance
i18n:
- Add click_to_search translation key for mobile search button
- Add add_rss_btn translation for empty state CTA
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add config-search-provider.vue component for managing search sources
- Support CRUD operations for custom search providers
- Default providers (mikan, nyaa, dmhy) cannot be deleted
- URL template validation ensures %s placeholder is present
- Add backend API endpoints GET/PUT /search/provider/config
- Add i18n translations for zh-CN and en
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The BangumiRule type uses episode_offset but components were using offset,
causing TypeScript errors.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add offset detector to identify season mismatches between RSS and TMDB
- Only suggest season_offset (user sets episode_offset manually)
- Add background scanner for existing bangumi rules
- Add detect-offset and dismiss-review API endpoints
- Add warning banner in edit dialog with auto-detect button
- Add iOS-style notification badge for needs_review items
- Yellow badge with "!" for warnings, purple badge for multi-rule count
- Combined badge shows "! | 2" when both conditions apply
- Yellow glow animation on cards needing review
- Highlight warning items in rule selection popup
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change resident key requirement from PREFERRED to REQUIRED during registration
- Add discoverable authentication options (empty allowCredentials)
- Add verify_discoverable_authentication method in WebAuthn service
- Update auth strategy to lookup user from credential when username not provided
- Make username optional in frontend passkey login flow
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix axios interceptor error when response.data is undefined by adding
optional chaining (?.msg_en, ?.msg_zh)
- Fix XML parsing crash in backend by catching ParseError exceptions
- Remove brotli (br) from Accept-Encoding header to fix mikan RSS fetch
issues (httpx doesn't auto-decompress brotli)
- Fix search card click event not triggering confirmation modal by
changing from native 'click' to custom 'select' event with typed payload
- Add NMessageProvider to App.vue to fix useMessage() outside setup error
- Replace structuredClone with JSON.parse/stringify in confirm modal
to handle Vue reactive Proxy objects
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add browser-like headers and full Chrome User-Agent to avoid Cloudflare blocking
- Use appropriate Accept headers for torrent files (application/x-bittorrent)
- Increase timeouts (connect: 5s→10s, read: 10s→30s) for slow responses
- Filter out None values from failed torrent fetches before sending to qBittorrent
- Add try-catch around add_torrents to prevent request crashes
- Improve logging from DEBUG to WARNING level for better visibility
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace dropdown search results with full-screen modal
- Add 4-tier filter chips: subtitle group, resolution, subtitle type, season
- Auto-extract filter options from search results
- Add confirmation modal before subscribing
- Support toggle close (click search input, Escape, or X button)
- Responsive grid layout: 1-4 columns based on viewport
- SSE streaming with fade-in card animations
- Add i18n translations for search filters and confirmation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Handles httpx.ReadError and other network exceptions when adding torrents
to qBittorrent by retrying up to 3 times with a 2-second delay.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add animated gradient background with floating blobs
- Use glassmorphism card with backdrop blur
- Add brand logo with theme-aware switching (light/dark)
- Improve form layout with input icons and better spacing
- Make login button full-width for better UX
- Add loading state for login button
- Improve passkey button styling with dashed border
- Respect prefers-reduced-motion for animations
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Make the "unknown" day column span 2 grid columns and display
items in a grid layout for better use of space.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Allow filtering logs by level (INFO, WARNING, ERROR, DEBUG) with
color-coded filter chips. Multiple levels can be selected simultaneously.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When migrating from older versions, new columns may have NULL values.
This adds a generic mechanism that scans all table models and fills
NULL values based on field defaults defined in SQLModel, improving
data consistency for upgraded databases.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Prevents startup from hanging indefinitely when downloader is
unreachable (e.g., due to proxy configuration). After 10 retries
(~5 min), program continues with an error log instead of blocking.
Fixes#955 (comment)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add size="small" to Resume, Pause, and Delete buttons in the
torrent action bar for consistent button heights.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When save_path ends with a season-only folder (Season 1, S01, 第1季),
display "Anime Name / Season 1" instead of just "Season 1"
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Increase dialog width from 380px to 460px to fit all content
- Unify button heights across ab-button and ab-button-multi components
- small: 32px, normal: 36px, big: 44px
- Restructure ab-rule form layout with consistent gap spacing
- Fix Episode Offset row to keep input and button on same line (mobile)
- Add proper z-index layering for ab-bottom-sheet (backdrop: 100, container: 101, panel: 102)
- Add scoped styles for ab-setting dynamic-tags wrapper
- Add action button separator line in edit dialog
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add _is_duplicate() helper to check by (title_raw, group_name)
- Fix add_all() to skip existing records and deduplicate within batch
- Improve add() to use same deduplication logic
feat(ui): calendar page grouping and accessibility improvements
- Calendar page now groups bangumi by title+season (same as main page)
- Add rule selection popup for grouped bangumi with multiple rules
- Add skeleton loading animation on bangumi list page
- Fix popup z-index layering with CSS variable system
- Improve accessibility: 44px touch targets, focus-visible states, aria-labels
- Add i18n translations for rule selection
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Hide page title on mobile for cleaner layout
- Change group badge color to purple (primary color)
- Fix badge positioning at card corners with fit-content wrapper
- Increase grid padding to prevent badge clipping
- Center grid items for better alignment
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add bangumi archive and episode offset features
Archive Feature:
- Add archived field to Bangumi model with database migration (v4)
- Add archive/unarchive API endpoints (PATCH /bangumi/archive/{id})
- Add auto-archive for ended series via TMDB metadata refresh
- Add collapsible archived section in UI with visual styling
- Add archive/unarchive button in edit rule popup
Episode Offset Feature:
- Extract series_status and season_episode_counts from TMDB API
- Add suggest-offset API endpoint with auto-detection logic
- Apply offset in renamer gen_path() for episode numbering
- Add offset field with "Auto Detect" button in rule editor
- Look up offset from database when renaming files
The offset auto-detection calculates the sum of episodes from all
previous seasons (e.g., if S01 has 13 episodes, S02E18 → S02E05
with offset=-13).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs: add changelog for bangumi archive and episode offset features
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Fix DetachedInstanceError in bangumi cache by expunging objects from
session before caching, preventing lazy loading errors when cached
objects are accessed from different request contexts
- Add database migration v3 to create passkey table for WebAuthn support,
fixing "no such table: passkey" error for users upgrading from older
versions
Closes#956
Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
Track RSS feed reachability during refresh cycles. Each feed now stores
connection_status (healthy/error), last_checked_at, and last_error.
The RSS management page shows a green "Connected" tag for healthy feeds
and a red "Error" tag with tooltip for failed feeds.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Cover RSS engine, downloader, renamer, auth, notifications, search,
config, API endpoints, and end-to-end integration flows. When all
210 tests pass, the program's key behavioral contracts are verified.
Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
- Fix 'dict' object has no attribute 'files' in renamer by using dict
access for qBittorrent API responses and fetching file lists via
separate torrents/files endpoint
- Replace version-file-based migration with schema_version table to
reliably track and apply database migrations on every startup
- Add air_weekday column migration as versioned migration entry
- Add torrents_files method to QbDownloader and Aria2Downloader
Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
- Upgrade VitePress from 1.0.0-rc.4 to 1.6.4 (stable)
- Update all dependencies (vue 3.5, typescript 5.6, @vue/tsconfig 0.5)
- Remove defunct Documate AI integration and google-analytics plugin
- Add Google Analytics via head config instead
- Translate all 25+ documentation pages from Chinese to English
- Add comprehensive REST API reference (docs/api/index.md)
- Add v3.2 changelog to sidebar navigation (fixes dead link)
- Update version string from v3.1 to v3.2
- Fix homepage changelog link to point to v3.2
- Update all WebUI screenshots with current v3.2 UI
- Add new screenshots: calendar view, bangumi poster wall
- Remove obsolete files: documate.json, deploy/windows.md, deploy/unix.md
- Update CSS variables for VitePress 1.6.x compatibility
Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>