Skip to content

Tags: anobaka/Bakabase

Tags

v2.3.0-beta.294

Toggle v2.3.0-beta.294's commit message
fix: refresh resource list cards after cache rebuild

Refreshing a resource's cache (single or batch) rebuilt the cover/playable
cache on the backend but never told the frontend, so the resource list kept
showing stale cover and play-control state until a manual reload. Single
refresh relied on a frontend-only reload that the batch path bypassed, the
cover thumbnail URL had no cache-busting token, and play-control resolution
cached stale discovery results.

Backend:
- ResourceService.RefreshResourceCache now publishes PublishResourcesChanged
  after each rebuild, so both single and batch (which loops this method) emit
  a per-resource change. Deliberately not PublishResourceCoverChanged, which
  would trigger cover-cache invalidation and delete the cache just rebuilt.
- New ResourceChangePushService bridges OnResourceDataChanged to the existing
  UI SignalR hub (GetIncrementalData key "Resource"), aggregating bursts over
  a short window and pushing only the changed resource ids.

Frontend:
- New transient ResourceChangedChannel (no retained store) fanned out from the
  UIHub "Resource" push; the active resource tab reloads just the ids it shows
  via reloadResources(..., { forceRefresh: true }).
- reloadResources stamps a client-only reloadToken on force-refreshed
  resources. ResourceCover appends it (with the existing reloadKey) to the
  thumbnail URL so a regenerated image at an unchanged path is refetched.
- usePlayableItemResolution treats a reloadToken bump like a resource change,
  resetting its SSE discovery cache so a stale (often empty) result no longer
  overrides the freshly returned backend playable items.

Fixes #1212

v2.3.0-beta.293

Toggle v2.3.0-beta.293's commit message
feat(cache): batch "refresh cache" for multi-selected resources

Right-clicking more than one selected resource now offers a "Refresh cache
for N resources" action. Refreshing a large selection rescans the
filesystem and regenerates thumbnails per resource, so it runs server-side
as a cancellable BTask (progress-reported) instead of blocking the request
or firing N individual calls from the client.

- IResourceService.RefreshResourcesCache: sequential batch over the existing
  per-resource refresh, with progress and per-resource error isolation.
- POST /cache/resources/refresh enqueues the batch as a BTask
  (ReplaceIfExists so a new request supersedes a running one).
- Context menu item shown only for multi-selection; single-selection keeps
  its existing synchronous refresh.

Regenerated SDK and added en/zh localization for the new task + menu item.

Closes #1210

https://claude.ai/code/session_01L3vo9qnAZSRPjUkG8tZvWU

v2.3.0-beta.284

Toggle v2.3.0-beta.284's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Merge pull request #1202 from anobaka/claude/vibrant-euler-DeWj7

feat(downloader): add ExHentai "prioritize tasks with torrent" option

v2.3.0-beta.282

Toggle v2.3.0-beta.282's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Merge pull request #1195 from anobaka/claude/brave-einstein-qo73Y

chore: disable auto-apply on startup for Velopack updates

v2.3.0-beta.280

Toggle v2.3.0-beta.280's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Merge pull request #1193 from anobaka/claude/bold-cerf-DGnXm

Fix AV mosaic parsing to return boolean instead of string

v2.3.0-beta.278

Toggle v2.3.0-beta.278's commit message

Verified

This commit was signed with the committer’s verified signature.
claude Claude
feat(workflow): typed-flow workflow engine + drag-drop editor

Introduce the `Bakabase.Modules.Workflow` module: a trigger → activity
chain executor where items flow between nodes carrying a semantic
item-type tag (e.g. `item.pixiv.illust`, `item.searchQuery`). The
editor walks the chain client-side to gate which activities are
addable at each position and automatically inserts an AI transform
node to bridge incompatible types.

- Backend: Trigger / Activity / ItemTypeDescriptor abstractions +
  registries + `IWorkflowEventBus`. The runner records per-step
  in/out/failed counts on a `WorkflowRun` row for the run-history
  drawer. Built-in triggers: `subscription.updated` (fired by the
  subscription module) and `downloader.completed` (fired by the
  downloader on terminal status). Built-in activities: title filter,
  generic AI transform, ExHentai search → first gallery, ExHentai
  enqueue download, generic send-notification (interpolates
  `{{field}}` against the item's JSON shape).
- Frontend: dnd-kit drag-drop editor, grouped activity picker with
  third-party icons via `GroupLabel`, ItemTypePill that shows the
  current item shape + reflected fields, run-history drawer with
  per-step funnel. Trigger / activity / item-type names are localized
  via per-kind i18n keys with the server's English display name as
  fallback.
- Integration: `DownloadTaskService` publishes `downloader.completed`
  events; menu order under "Tools" promotes Subscription + Workflow
  immediately after the File-name modifier so the cross-cutting
  surfaces sit with the rest of the file pipeline.
- Wire-up: solution / DI / DbContext / EF migrations / SDK regen / i18n
  registration land here so the previous two commits' modules become
  reachable end-to-end.

Closes #1191

v2.3.0-beta.275

Toggle v2.3.0-beta.275's commit message
fix(resource): scroll page indicator + auto-named tabs from filter va…

…lues

Two resource-page fixes shipped together because both edit the same
tab/grid stack.

1) Scroll-driven page number stopped updating.
   ResourceTabContent.onScroll mapped the viewport-center resource to a
   page via `pageContainerRef.current?.querySelectorAll("div[role='resource']")`,
   but ResourceCard's `role="resource"` was removed by eslint a11y
   (it isn't a valid ARIA value). The selector returned zero matches
   and the page chip went silent. Switch to `div[data-id]` — already
   unique to ResourceCard root divs.

2) Auto-generated tab names from selected filters.
   New `buildAutoTabName(form)` walks `form.group.filters` recursively
   and renders each enabled filter's bizValue as comma-separated text
   matching the property type's light variant. ResourceTabContent
   bubbles its live searchForm up; FilterPanel reports pre-debounce
   edits via `onSearchFormLiveChange` so the chip tracks filter edits
   in real time rather than waiting for the 1s auto-search. The page
   keeps a per-tab `liveSearchForms` map and derives display name as
   `s.name || buildAutoTabName(liveSearchForms[s.id]) || "Search N"`
   (localized) — so un-mounted tabs beyond the LRU cap and just-created
   tabs with no filters still read as "Search 1" rather than empty.
   Double-click pre-fills the input with the current display name;
   Enter / Blur / Escape all commit (per spec — entering edit mode
   locks the name). Clearing the input and committing is the way back
   to auto-mode.

   Backend: drop the "{Search} {N}" auto-naming in BuildNewSavedSearch
   (and the now-unused translationOfSearch param + IBakabaseLocalizer
   dependency in ResourceController) so new SavedSearches ship with
   Name = "" and the frontend's auto-name actually wins. Existing tabs
   with auto-numbered names keep them.

Fixes #1187
Closes #1188

v2.3.0-beta.273

Toggle v2.3.0-beta.273's commit message
docs(claude): warn about literal skip-ci substrings in commit bodies

GitHub matches the directive anywhere in the message, so prose that
mentions it (e.g. explaining a manual-override path) will silently
skip the pipeline. Just bit us on 0a428be.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

v2.3.0-beta.270

Toggle v2.3.0-beta.270's commit message

Verified

This commit was signed with the committer’s verified signature.
claude Claude
refactor(btask): fluent builder, transitional statuses, heartbeat and…

… UI cleanup

Six related improvements landed together to address the points raised in
#1183 (slow-feeling pause/stop, opaque builder API, drifting remaining
time, simplistic background page, scattered status checks, no easy way
to manually exercise the lifecycle).

1. Pausing / Resuming transitional statuses

   Pause()/Resume() now flip status to a transitional state synchronously
   so the chip stops lying about "Paused" while the task is still doing
   CPU/IO work between yield points. OnPause/OnResume from PauseTokenSource
   then promote to the final Paused / Running state when the body actually
   cooperates — matching the existing Cancelling behavior.

2. Heartbeat in BTaskHandler

   While the task body is in any active state (Running / Pausing /
   Resuming / Cancelling), a 1s heartbeat triggers _onChange so the
   SignalR push refreshes elapsed / remaining derived from
   handler.Sw.Elapsed. Without it the frontend timing simulator drifted
   when percentage plateaued. EstimateRemainingTime now extrapolates from
   live Sw.Elapsed instead of the last percentage-change snapshot.

3. Fluent BTaskBuilder API

   BTaskHandlerBuilder kept 16 fields with no signal as to which were
   required. BTaskBuilder.Create(id) plus fluent extensions
   (.Named, .Describe, .Run, .Persistent, .ConflictsWith,
   .ReplaceIfExists, ...) replaces the object-initializer construction
   across every direct call site (~20 places); only Id and Run have no
   sensible default. The property Run was renamed RunAction to free up
   the .Run() extension method (the delegate property otherwise
   shadowed it). OnStatusChange / OnPercentageChanged extensions are
   exposed as .WhenStatusChanges / .WhenPercentageChanges for the same
   reason.

4. Cooperative cancellation helper

   await args.YieldAsync() now bundles the standard
   ThrowIfCancellationRequested + WaitWhilePausedAsync pair into a
   one-liner; the rules doc nudges authors to sprinkle it through tight
   loops. Stop() also schedules a warning if the task body doesn't
   observe cancellation within 10s, so a missing yield point shows up in
   the log instead of as silent latency.

5. Background page reuses TaskTable

   src/web/src/pages/background-task replaces its bespoke static table
   with the FloatingAssistant TaskTable (per-row actions, real-time
   timing, filtering) and adds a separate Schedule panel below for
   editing interval / enableAfter on persistent tasks.

6. Consolidated status predicates

   The "is task busy / stoppable / advancing / finished" multi-state
   checks were copy-pasted across ~10 sites with subtle drift — adding
   the new transitional states required updating each one manually.
   Centralizes them on BTaskStatus as IsActive / IsActiveOrPending /
   CanBeStopped / IsAdvancing / IsFinished, each documented with the
   question it answers. Call sites now read like prose and stay correct
   when a new status joins the enum.

Plus two dev-only test tasks (gated by IWebHostEnvironment.IsDevelopment;
zero production footprint):

- DevTestPersistentTask: recurring 1-minute interval, ~60s body, with a
  deliberately non-yielding 3s section midway so authors can watch the
  Pausing / Cancelling chips linger while the body is stuck between
  yield points.
- DevTestOneOffTask: one-shot at startup, ~30s body, fully cooperative.
  Demonstrates the responsive case where pause / resume / stop land
  within a few hundred ms.

Other touch-ups: BTaskManager.Pause/Resume are now async. The "is busy"
checks in PathSyncManager, BackgroundTaskController, ComparisonController
and BakabaseHost.CheckIfAppCanExitSafely use the new predicates. Frontend
locales and useTaskTimingSimulation handle Pausing/Resuming consistently.
Three new tests in BTaskTransitionalStatusTests lock down the synchronous
status flip.

SDK regen committed (constants.ts).

Closes #1183

https://claude.ai/code/session_014DmnQqBi52c7pifRoD5CS8

v2.3.0-beta.258

Toggle v2.3.0-beta.258's commit message
refactor(av-enhancer): dispatch via IAvClient and serialize details d…

…irectly

Two maintenance traps in AvEnhancer/AvController: a hand-written 20-entry
dispatcher dictionary that AvEnhancer rebuilt per call, and a hand-written
20-key dictionary used to dump per-source debug results. Adding or
removing a scraper required updating both dispatchers plus the debug
shape, and the failure mode was silent — the new source just never got
called or its fields disappeared from the dump.

Introduce IAvClient (SourceId + lowest-common-denominator SearchAndParseVideo
signature). Each of the 20 per-site clients now implements it via explicit
interface implementation, preserving their strongly-typed overloads for
direct callers. AvEnhancer and AvController inject IEnumerable<IAvClient>
and build their dispatcher from SourceId, so adding a source only requires
implementing the interface and registering one DI binding.

Also replace the hand-written perSourceData dict with
JsonSerializer.Serialize(context.Details) — reflection over IAvDetail's
public getters captures every field automatically.

AvEnhancer no longer needs AiravClient just for its HttpClient; it pulls
a default-named client from IHttpClientFactory for cover/poster downloads.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>