1977 Commits

Author SHA1 Message Date
Estrella Pan
31edfd84b5 test: satisfy mypy for torrent manager private helper 3.3.3 2026-07-09 18:23:39 +02:00
Estrella Pan
b63f34675b chore: release 3.3.3 2026-07-09 15:44:53 +02:00
Estrella Pan
b279295515 Merge pull request #1070 from EstrellaXD/fix/issues-1067-1068 2026-07-09 15:42:56 +02:00
Estrella Pan
852272b860 Merge pull request #1064 from EstrellaXD/feat/anibt-search-provider 2026-07-09 15:42:45 +02:00
Estrella Pan
0a20eadcec Merge branch '3.3-dev' into main for 3.3.3 2026-07-09 15:42:34 +02:00
Estrella Pan
9586513f6f fix: address recent issue regressions 2026-07-09 14:28:33 +02:00
Estrella Pan
122cf68eac fix(ci): release only from manually pushed tags, never from merged PRs
Merging PR #1063 ("Doc update", 3.3-dev -> main) triggered the stable
release path, which fell back to the raw PR title as the version string
and shipped a Docker image tagged Doc-update as :latest — every
container pulling latest then crashed on SemVer parsing (#1065).

The release trigger is now explicit:
- bare X.Y.Z tag -> stable release, refused unless the tagged commit is
  an ancestor of main
- tag containing alpha/beta -> pre-release (unchanged)
- PR merges only run tests and a docker build test

Also pass head.ref through an env var instead of inlining it in the
script (injection hardening), and take release notes solely from the
changelog file since tag pushes carry no PR body.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jejs2dffkscAbhZkcjZ1oK
2026-07-08 16:25:09 +02:00
Estrella Pan
59ed2d926e feat(searcher): add AniBT as a built-in search provider
Add anibt.net as a first-class default search provider alongside
mikan/nyaa/dmhy, using its RSS search endpoint
(https://anibt.net/rss/magnets.xml?q=%s) with the tmdb parser.

load_provider() now merges newly added built-in sites into an
already-saved config/search_provider.json, so existing installs pick
up new default providers on restart while keeping user-customized
URLs and parsers untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YUaTRVgAxPq6zEiwJHnbiC
2026-07-08 11:27:43 +02:00
Estrella Pan
36f67a805b Merge pull request #1063 from EstrellaXD/3.3-dev
Doc update
2026-07-08 10:20:05 +02:00
Estrella Pan
277f3d740c docs: update configuration guide and locale routing 2026-07-08 10:18:24 +02:00
Estrella Pan
7716986f77 Merge pull request #1060 from EstrellaXD/3.3-dev
3.3.2
3.3.2
2026-07-07 23:06:10 +02:00
Estrella Pan
bccda1186a chore: bump version to 3.3.2
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 22:16:29 +02:00
Estrella Pan
4aa2cfb858 fix(webui): stop leaked search streams duplicating results and spinning
open() never closed the previous EventSource, so re-searching leaked
the old stream: it kept appending the same results (duplicate
variants/tags in the list), its onerror closed the NEW stream's
handle, and the leaked stream auto-reconnected forever — an idle
spinner even with an empty input.

- close the previous stream before opening a new one
- stale-stream handlers close themselves and never touch shared state
- de-duplicate appended results by rss_link as a safety net
- clearing the input stops an in-flight search
- eventSource must be a shallowRef: ref() proxies the EventSource and
  breaks the same-stream identity check

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 22:15:52 +02:00
Estrella Pan
96e33619f2 fix(downloader): confirm .torrent-file duplicates by infohash on qB <=5.1
qB <=5.1 answers every rejected add with an opaque 200 "Fails.". For
magnet adds we already confirm "actually a duplicate" via the btih
hash, but Mikan torrents are uploaded as .torrent files, so the check
never matched and the add was classified FAILED — and since failed
adds are deliberately not persisted (kept for retry), the same
torrents error-looped every RSS tick ("Fails." ... "no matching
torrent found") forever, e.g. after purging orphan records while the
torrents still exist in qB.

Compute the v1 infohash (SHA-1 of the bencoded info dict, minimal
cursor — no new dependency) from the uploaded bytes and confirm
existence in qB; corrupt files still fail loudly and keep retrying.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 22:09:52 +02:00
Estrella Pan
b9473da2ec Merge pull request #1059 from EstrellaXD/3.3-dev
3.3.1
3.3.1
2026-07-07 19:02:17 +02:00
Estrella Pan
59350963d9 Merge fix/t1-batch: 3.3.1 (orphan-torrent fix + T1 issue batch) 2026-07-07 18:56:42 +02:00
Estrella Pan
f0866e6dc9 chore: bump version to 3.3.1
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 18:55:18 +02:00
Estrella Pan
1c6fdb85c0 fix(rss): restore disabled rules on explicit re-subscribe/collect
Codex review follow-up: a soft-deleted exact duplicate still orphaned
torrents (add() refuses the insert, the deleted row was refused for
linking, and download proceeded with no id) and the collect path
could link torrents to a still-disabled row. Explicitly subscribing
or collecting a disabled rule can only mean the user wants it back:
restore_one() re-enables the row (keeping its tuned config) and
torrents link to it. eps_complete is unaffected (not_complete already
filters deleted rows).

Also document the ab:renamed tag semantics (top-level media files;
subtitles follow in the same tick, nested extras never rename).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 18:53:43 +02:00
Estrella Pan
86b170de92 fix: address code-review findings on the T1 batch
- renamer: drop retroactive sanitization in gen_path — titles parsed
  from on-disk files are already legal; sanitizing them would batch-
  rename existing libraries containing ":" on upgrade. Sanitization
  stays in gen_save_path (new rules only), with an "Unknown Bangumi"
  fallback when a title is all reserved characters.
- renamer: tag failures no longer break the rename flow (notification
  still returned, cycle continues); collections with unparseable
  media files are not marked ab:renamed.
- collector: duplicate resolution no longer clobbers user-tuned
  fields (eps_collect is set via a targeted update); failed collects
  roll back the freshly inserted row; soft-deleted rules are never
  linked; stale ids pointing at removed rows are cleared.
- database: find_duplicate is deterministic (oldest row) and warns on
  legacy duplicate keys.
- api: auto_tag_torrents matches ab:<digits> exactly so the
  ab:renamed marker doesn't block re-linking.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 18:44:49 +02:00
Estrella Pan
3b24b4c6a0 fix(rss): resolve existing bangumi id when re-subscribing a duplicate
bangumi.add() returns False for exact (title_raw+group_name) and
semantic duplicates without backfilling the id, so re-subscribing an
already-known bangumi still orphaned every torrent (found in live
verification against the seeded dev stack). Add find_duplicate() to
the repo and resolve the existing row's id in subscribe/collect
before downloading.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 18:23:11 +02:00
Estrella Pan
618464a450 feat(config): user-configurable TMDB API key + Network settings panel (#975, #1042)
Backend: add network.tmdb_api_key (empty = fall back to the built-in
shared key, read live like tmdb_base_url); the config API masks it
automatically.

WebUI: the network section existed backend-only since #1042 — expose
it as a Network settings panel (TMDB API URL, TMDB API key,
Bangumi API URL) with types, initConfig defaults, i18n, and mocks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 18:05:53 +02:00
Estrella Pan
e002806bf6 feat(renamer): tag processed torrents with ab:renamed (#147)
After a torrent's media files are renamed (or already conform to the
target naming), add an ab:renamed tag in the downloader so external
scripts (filebot, hlink, ...) can filter tasks AutoBangumi has
finished processing. Skips the API call when the tag is already
present, skips failed renames, and skips the none/normal
pass-through methods. Capability-guarded via the facade, so
aria2/mock downloaders are unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 17:59:20 +02:00
Estrella Pan
92ad33b2e4 fix(renamer): keep fractional episode numbers like 12.5 (#667, #704)
The filename parser already yields 12.5 as a float, but gen_path and
rename_file int()-floored it to 12, overwriting the real episode 12.
Extract the duplicated offset logic into _adjust_episode and add
_format_episode (fraction preserved, integer part zero-padded:
"09.5"); widen Notification.episode to int | float so notifications
carry the fraction too.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 17:53:29 +02:00
Estrella Pan
bbc91d89f2 fix(renamer): sanitize reserved characters in generated paths (#721)
Titles containing Windows/qB reserved characters (e.g. "Fate/Zero")
were joined raw into save paths and filenames, letting qBittorrent
split them into extra directories or silently truncate. Replace
<>:"/\|?* and control chars with a space in the save-path folder and
in every rename method's title component; collapse whitespace and
strip trailing dots/spaces.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 17:50:25 +02:00
Estrella Pan
64cfc1b1f8 feat(notification): support Server酱³ sendkeys (#904)
sctp<uid>t-prefixed sendkeys route to the Server酱³ endpoint
(https://<uid>.push.ft07.com/send/<key>.send); Turbo keys keep the
legacy sctapi.ftqq.com endpoint.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 17:46:26 +02:00
Estrella Pan
9b194b1af6 fix(rss): link manually added torrents to their bangumi
Torrents added via search/subscribe/collect were persisted with
bangumi_id=NULL, so every matched torrent from those flows landed in
the orphan list regardless of the track_orphans setting, and the
ab:<id> qB tag was silently skipped (bangumi.id did not exist yet).

- subscribe_season/collect_season: insert the bangumi row before
  downloading so its id exists for the qB tag and the FK
- collect_season/download_bangumi: set torrent.bangumi_id before
  persisting

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 17:44:58 +02:00
Estrella Pan
dc3a032217 Merge pull request #1050 from EstrellaXD/3.3-dev
3.3.0: async architecture, first-class aria2, movies/specials, security hardening
3.3.0
2026-07-07 14:31:11 +02:00
Estrella Pan
21538d9db5 Merge origin/main into 3.3-dev: resolve version-file conflicts for 3.3.0
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 14:24:33 +02:00
Estrella Pan
18f5fab9db chore: bump version to 3.3.0
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 14:24:06 +02:00
Estrella Pan
90e2c55ffa Merge pull request #1057 from EstrellaXD/fix/issues-1052-1053
fix: torrent-download 429 throttling and stale RSS entries after deletion (#1052, #1053)
llm-plugins
2026-07-07 14:05:26 +02:00
Estrella Pan
5fdc2e723f fix: address code-review findings on #1052/#1053 fixes
- Disable (not delete) orphaned per-sub RSS feeds on bangumi deletion:
  a hard delete could not distinguish search-created subscriptions from
  user-added non-aggregate feeds, and RSSDatabase.delete's cascade also
  wiped torrent dedupe records that other bangumi may rely on. Disabled
  feeds keep their history and can be re-enabled; batch-disabled in one
  commit via disable_batch.
- Never remap known parser types (mikan/tmdb/parser) through the
  search-provider config in /rss/subscribe; only genuine site names
  (nyaa/dmhy) are mapped. Prevents parser='mikan' from being rewritten
  when the user customized the mikan provider's parser.
- RSSDatabase.search_url tolerates duplicate-URL rows (first() instead
  of scalar_one_or_none) - url has no DB unique constraint.
- _retry_after_delay rejects NaN Retry-After values, which would
  propagate through min/max into asyncio.sleep(nan) and never wake.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JhTduCYBGeHETU7dSWoh37
2026-07-07 13:02:32 +02:00
Estrella Pan
63821917a5 fix(downloader): throttle batch torrent fetches and back off on HTTP 429 (#1052)
Batch-collecting a season fired all .torrent file downloads at once via
an unbounded asyncio.gather, tripping nyaa's rate limiter; get_url then
gave up on the first 429 with no retry, so the whole batch silently
failed.

- add_torrent now fetches torrent files serially per host with a 1s
  delay between requests (parallel across hosts), mirroring the
  RSS_PER_HOST_DELAY pattern from #1026
- get_url retries 429 responses within the existing retry budget,
  honoring a numeric Retry-After header (clamped to 60s) and falling
  back to a 10s delay otherwise

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JhTduCYBGeHETU7dSWoh37
2026-07-07 12:42:35 +02:00
Estrella Pan
8f91899670 fix(manager): remove orphaned per-sub RSS feeds when deleting a bangumi (#1053)
Deleting a bangumi left its individually-subscribed (aggregate=False)
RSSItem enabled, so the WebUI kept showing the feed as active and the
RSS loop kept polling it. delete_rule now removes per-sub feeds that no
remaining bangumi references, splitting comma-joined rss_link values and
matching URLs exactly. Aggregate feeds and feeds still referenced by any
bangumi (including soft-disabled ones) are never touched.

Adds RSSDatabase.search_url for exact-URL lookup.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JhTduCYBGeHETU7dSWoh37
2026-07-07 12:42:35 +02:00
Estrella Pan
b659795288 fix(rss): map search-site name to its configured parser on subscribe (#1053)
Search-subscribe sent the provider site name (nyaa/dmhy) as the RSSItem
parser, but the analyser only understands mikan/tmdb, so those
subscriptions silently skipped TMDB title/poster enrichment. Resolve the
site name through the search-provider config at the subscribe boundary;
values that are already parser types pass through unchanged.

Note: the WebUI RSS tag for search-subscribed nyaa/dmhy feeds now reads
"tmdb" (the parser type) instead of the site name.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JhTduCYBGeHETU7dSWoh37
2026-07-07 12:42:35 +02:00
Estrella Pan
1b928ee326 feat(rss): setting to disable orphan-torrent tracking
New bangumi_manage.track_orphans toggle (default on = current
behavior). When off, refresh_rss no longer persists unmatched torrents
(bangumi_id NULL orphan records): they are re-matched in memory each
tick (cheap, no network — the analyser dedups via bangumi rules, not
torrent records), and a rule added later can retroactively pick up
episodes still in the feed, which persisted orphans used to block
forever. Season-collect flows still persist their NULL records for
feed dedup and are not gated.

WebUI: "Track Unmatched Torrents" switch in Settings -> Manage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 12:15:06 +02:00
Estrella Pan
f2875d9870 chore: release 3.3.0-beta.8
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
3.3.0-beta.8
2026-07-07 11:38:00 +02:00
Estrella Pan
3caefb5705 Merge feat/torrent-management: bangumi/orphan torrent management (#1051)
3.3 port of #1020 (orphan-torrent DB methods, 7 API endpoints, torrent
management pages), rebased onto 3.3-dev and reworked to the Soft Ink
ab-* component system per code review. Merged locally because the
rebased branch could not be force-pushed to the PR head.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 11:34:47 +02:00
Estrella Pan
55105d4841 chore(webui): regenerate auto-imports after #1056 merge
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 11:34:47 +02:00
Estrella Pan
b887f1833c fix(log): keep log history across restarts and rotation
The log page intermittently showed nothing because the file lifecycle
destroyed history at both ends:

- setup_logger(reset=True) deleted log.txt on every process start
  (container restart, online update), wiping history exactly when the
  user wants to inspect what happened before the restart. Boot now
  rotates the previous run into log.txt.1-3 via the stdlib
  RotatingFileHandler.doRollover (delay=True, rename-only), matching
  runtime rotation naming; failures warn instead of aborting boot.
- At rotation, the UI collapsed to a near-empty log.txt: both readers
  (GET /log and the SSE log event) only read log.txt. The tail read
  now stitches log.txt.1 in front when the current file fits inside
  the 512 KB budget — and never when the read was truncated, which
  would fake a time-jump above a silent gap. A file renamed mid-read
  (rollover race) reads as empty instead of raising, which previously
  could kill the whole SSE stream.
- Rotation cap tightened to 2 MB x 3 backups (~8 MB total); the UI
  renders at most 512 KB so nothing visible is lost.
- POST /log/clear also removes rotated backups (stitching would
  resurrect them) and runs its file I/O in a thread like get_log.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 11:32:53 +02:00
Estrella Pan
d91686486b refactor(webui): rework torrent-management UI to Soft Ink ab-* layer
Post-rebase rework addressing review findings on #1051 (the branch
predated the component-system migration):

- Replace retired ab-popup confirm with the useConfirm() promise hook
- Replace NButton and bare <button> with ab-button / ab-icon-button;
  badge pills with ab-tag / ab-badge marks; empty state with ab-empty;
  drop hardcoded colors for theme variables
- Make the per-bangumi page's route param reactive with a NaN guard,
  and remount the list on param change
- Add a "View torrents" entry point in the rule edit dialog
- Reload the torrent list in finally so partial batch-delete failures
  don't leave stale rows
- Align the orphan card title across locales; regenerate dts files

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 10:58:58 +02:00
Estrella Pan
7c1a7938b1 fix(types): annotate CursorResult.rowcount for mypy in delete_orphans
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAxVyRwrY7z5NotTtgnwVs
2026-07-07 10:48:07 +02:00
Estrella Pan
679bd2621c feat: manage bangumi torrents and orphan torrents (port of #1020)
Port zhushanwen321's torrent-management feature (#1020) from the 3.2 sync
architecture to the 3.3 async design.

Backend:
- TorrentDatabase: search_orphans / count_orphans / delete_orphans / delete_obj
- bangumi API: list/delete endpoints for per-bangumi torrents and orphan
  torrents (bangumi_id IS NULL); literal /torrents/orphans routes registered
  before /{bangumi_id}/torrents

WebUI:
- Others card on the bangumi list with orphan count badge
- Torrent list pages (per-bangumi and orphans) with multi-select,
  batch delete, and clear-all confirm dialog

The PR's mikan_parser and rss/analyser fixes are not ported: 3.3-dev
already handles failed poster downloads and missing elements.

Co-authored-by: zhushanwen321 <zhushanwen321@users.noreply.github.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAxVyRwrY7z5NotTtgnwVs
2026-07-07 10:48:07 +02:00
Estrella Pan
a9839e0725 Merge pull request #1056 from EstrellaXD/feat/nexusphp-pt-provider
feat(webui): NexusPHP PT-site preset for search providers
2026-07-07 10:45:52 +02:00
Estrella Pan
fd2dccac4d Merge pull request #1055 from EstrellaXD/perf/slim-docker-image
perf(docker): shrink image 208MB -> 160MB
2026-07-07 10:44:51 +02:00
Estrella Pan
77e50484f3 fix(webui): correct NexusPHP category format and validate input
Review findings on #1056, verified against upstream NexusPHP source:

- torrentrss.php only recognizes per-category flags (cat402=1); the
  bare cat=402 form was silently ignored. Emit cat<ID>=1 and accept
  comma-separated IDs.
- Validate that category IDs are numeric, with a warning and Apply
  gating in the dialog.
- Stock NexusPHP hardcodes $searchstr = null (search unsupported), so
  the template only filters on sites/forks that kept search support —
  the hint now tells users to verify this on their site instead of
  implying it always works.
- Mask the passkey in the dialog's URL preview (stored URL unchanged).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 10:42:53 +02:00
Estrella Pan
afcfc0d605 fix(webui): submit login on Enter and auto-prompt passkey
- The login button was type="button", so the form had no submit button
  and Enter in the password field did nothing (no implicit submission
  with two inputs). The button is now the form's submit button and the
  handler guards re-entry.
- Auto-trigger the passkey prompt on the login page for browsers that
  have successfully used a passkey before (hasPasskey localStorage
  flag, set on passkey login/registration). A cancelled or unavailable
  silent ceremony (DOMException) disarms the flag so a stale entry
  can't doom every visit; API errors keep it (interceptor already
  toasts). An explicit logout suppresses the next auto-prompt via
  sessionStorage so a reflexive Touch ID confirm can't log straight
  back in.
- Extract the shared withSetup test helper instead of a third copy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 10:22:37 +02:00
Estrella Pan
028a0420d5 fix(downloader): qBittorrent 5.x WebAPI compatibility
Verified against qB source at release tags 4.6.7/5.0.0/5.1.0/5.2.0:

- torrents/add: accept qB 5.2 JSON response (200/202) — partial success
  and pending URL fetches count as ADDED, matching legacy "Ok."
  semantics; 409 Conflict is DUPLICATE for synchronous file uploads and
  hash-confirmed magnets, otherwise raised for retry. Send both paused
  and stopped form params (renamed in 5.0, each era ignores the other).
- torrents/pause|resume: renamed to stop|start in qB 5.0 with no
  aliases; try the modern name first, fall back on 404, remember which
  era worked.
- torrents/info: filter=paused was renamed and unknown filter values
  silently mean All — filter paused/stopped client-side by state.
- torrents/delete, torrents/renameFile: treat any 2xx as success
  (qB 5.2 returns 204 for empty-body responses).
- webui: map qB 5.0+ stoppedDL/stoppedUP states to the paused label.
- .gitignore: exclude local runtime data (backend/data), agent
  workspace (.claude), and task notes (tasks).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pz1EmcTPzjgEpkGQWzb8AQ
2026-07-07 10:22:27 +02:00
Estrella Pan
378acc90cb feat(webui): NexusPHP PT-site preset for search providers
Add PT (private-tracker) support via the existing RSS-based search
pipeline. The Add Search Provider dialog gains a "PT Site (NexusPHP)"
mode that builds a torrentrss.php search template from base URL +
passkey + optional category ID (e.g. Audiences.me anime = 402), so
search -> subscribe -> auto-download -> rename works end-to-end on
NexusPHP trackers with no backend changes.

- webui/src/utils/nexusphp.ts: URL-template builder (vitest-covered)
- config-search-provider.vue: segmented custom/NexusPHP add dialog
  with live URL preview; en + zh-CN strings
- backend test_nexusphp_rss.py: regression tests proving NexusPHP
  torrentrss output (enclosure and linktype=dl variants) parses
  through the generic rss_parser path

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JhTduCYBGeHETU7dSWoh37
2026-07-07 10:19:26 +02:00
Estrella Pan
c1a0cf8559 perf(docker): shrink image 208MB -> 160MB
Two changes, verified with local builds:

- Drop UV_COMPILE_BYTECODE=1: shipped .pyc files were 51MB. The venv is
  root-owned and the app runs long-lived as 'ab', so bytecode only saved
  a few seconds of import time once per container start. This also
  matches the boot_overlay uv-sync path, which never compiled bytecode.
- mcp[cli] -> mcp: the app only imports mcp.server; the cli extra pulled
  typer/rich/pygments/markdown-it (~14MB) for an unused console script.
  python-dotenv, the extra's other member, is already a direct dep.

Compressed pull size drops 64.2MB -> 48.8MB. Image verified: packages
absent, no __pycache__, 'import main' succeeds; pytest and mypy green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEnmRvBJL93fAURbRf1koK
2026-07-07 10:13:51 +02:00
Estrella Pan
c19da52497 chore: release 3.3.0-beta.7
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAxVyRwrY7z5NotTtgnwVs
3.3.0-beta.7
2026-07-06 16:38:20 +02:00