-
v0.8.0
Stablereleased this
2026-07-13 00:44:03 +02:00 | 0 commits to pgsql since this releaseBug Fixes
-
Fix recap
-
Correct TimeRange.Intersects containment and identity handling (#816)
-
Fix
-
Fix2
-
Fix3
-
Use dotnet publish to include all runtime dependencies
-
Exclude design-time DLLs and enable dynamic loading
-
Db
-
Db2
-
Db3
-
Db4
-
Db5
-
Use pgsql plugin id in dashboard
-
Migrate pgsql config hash columns
Features
-
Native PostgreSQL provider for Intro Skipper
-
Initial pgsql plugin release
-
Exclude Jellyfin framework assemblies from plugin package
-
Adopt upstream cache dashboard for pgsql
-
Migrate pgsql season state
Miscellaneous
-
Bump actions/checkout from 6 to 7 (#800)
-
Bump Microsoft.NET.Test.Sdk from 18.6.0 to 18.7.0 (#813)
-
Bump github/codeql-action/init from 4.36.2 to 4.36.3 (#824)
-
Bump github/codeql-action/autobuild from 4.36.2 to 4.36.3 (#823)
-
Bump github/codeql-action/analyze from 4.36.2 to 4.36.3 (#825)
-
Add plugin fork management to build system
-
Update manifest for v1.10.11.17
-
Update manifest for v1.10.11.17 [skip ci]
-
Trigger release
-
Pull Jellyfin packages from Forgejo NuGet registry to match unsigned server build
-
Bundle meta.json with assemblies whitelist in release zip
-
Avoid node lts alias in release
Other
- Ffmpeg extract cache (#784)
-
refactor: extract FFmpegOutputParser and FFmpegProcess from FFmpegWrapper (PR 1)
-
Update FFmpegOutputParser.cs
-
Refactor FFmpeg services
-
Address review feedback: thread-safe chromaprint logs, log version-check failures, dedupe fingerprint range, use NullLogger in tests
- Replace _chromaprintLogs Dictionary with ConcurrentDictionary: writers are serialized via ScheduledTaskSemaphore, but the support bundle endpoint enumerates the map concurrently
- Log the exception in CheckFFmpegVersion instead of silently swallowing it
- Use GetValueOrDefault in GetChromaprintLogs/FormatFFmpegLog so a failed version check can no longer crash the support bundle with KeyNotFoundException
- Fix comment typo ("supports of the all")
- Move detection-cache reads before ffmpeg arg construction in DetectSilence/DetectBlackFrames/DetectKeyFrames
- Consolidate duplicated GetFingerprintRange into QueuedEpisode as the single source of truth for detection cache keys
- Replace undisposed new LoggerFactory() instances in tests with NullLogger.Instance
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Address CodeQL findings: log kill failures, StringBuilder in GetChromaprintLogs, NullLogger in TestTimeAdjustmentHelper
- KillProcessTree now logs instead of silently swallowing kill failures (debug for the already-exited race, warning for Win32/NotSupported)
- GetChromaprintLogs builds the support bundle section with StringBuilder
- TestTimeAdjustmentHelper uses the NullLogger.Instance singleton instead of an undisposed NullLoggerFactory
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Address CodeQL findings: narrow process-priority catch, use Path.Join for ffprobe path
- Filter the PriorityClass catch to the documented failure modes (InvalidOperationException, Win32Exception, NotSupportedException)
- Use Path.Join in GetFFprobePath so no path segment can silently drop earlier arguments
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Make FFmpeg service process calls async (#785)
-
Make FFmpeg service process calls async
-
Address async cutover review comments
- Optionally append SponsorBlock chapter types to Intro Skipper chapter regex (#769)
-
Add SponsorBlock chapter pattern defaults
-
Refine SponsorBlock regex literals
-
Remap SponsorBlock intermission chapters
-
Make the predefined chapters a blanket option
-
Add missing documentation annotations
-
Prevent rejecting a match for an invalid fallback
-
Move intro animation to into, but intermission to commercial
-
Potential fix for pull request finding 'Nested 'if' statements can be combined'
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
-
Assign explicit labels to types, ambiguous to commercial
-
Address the comments by fixing tests
Co-authored-by: copilot-swe-agent[bot] 198982749+Copilot@users.noreply.github.com
Co-authored-by: TwistedUmbrellaX twistedumbrella@gmail.com
Co-authored-by: TwistedUmbrellaX 1173913+AbandonedCart@users.noreply.github.com
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>-
Fix colon-delimited chapter end labels
-
Refactor media segment refresh services (#786)
-
Refactor media segment refresh services
-
Reduce Plugin singleton coupling and dedupe segment provider options
- Inject ILibraryManager into MediaSegmentRefreshService and MediaSegmentEditorService; resolve items via GetItemById instead of Plugin.Instance.GetItem
- Centralize the duplicated external-provider LibraryOptions into MediaSegmentProviderDefaults
- Simplify id filtering in RefreshAsync(IEnumerable) with LINQ
- Add ID-path refresh test; use collection expression in test fake
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Rethrow fatal exceptions in MediaSegmentRefreshService.RefreshAsync
Mirror MediaSegmentEditorService: let cancellation and critical/system-level
exceptions (OOM, StackOverflow, ThreadAbort, etc.) propagate instead of being
logged-and-swallowed, while keeping per-item log-and-continue resilience for
ordinary provider failures.Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Consolidate ILibraryManager test stub and cover critical-exception rethrow
- Extract the duplicated DispatchProxy-based ILibraryManager fake from
TestSkipIntroController and TestMediaSegmentRefreshService into a shared
EntrypointTestHelpers.CreateLibraryManager helper - Add a test asserting RefreshAsync rethrows critical/system exceptions
instead of swallowing them
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Add direct unit tests for MediaSegmentEditorService
Cover the previously-untested editor surface: provider-not-found no-op,
non-commercial replace (delete-existing + create, ItemId/provider id/type
filter), commercial dedup (skip identical, create distinct), delete-failure
resilience, per-item lock serialization of concurrent same-item edits, and
all GetSegmentAsync/DeleteSegmentAsync paths.Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Reanalyze settled seasons to improve segment quality (#787)
- Reanalyze settled seasons to improve segment quality
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Fix settled-season reanalysis guard and make reset atomic
- Split the one-time guard into ShouldSettleReanalyze (read-only check) and
RecordSettleReanalysis (commit), recording completion only after the reset
succeeds so a cancelled/failed pass is retried instead of permanently skipped. - Wrap segment deletes and the EpisodeIds clear in ResetSeasonForReanalysisAsync
in a single transaction so a cancel can't strand episodes as NoSegments. - Update tests for the split guard API.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
-
Add settled-season reanalysis state
-
Remove settled-season rescan interval
-
Drop test-only ShouldSettleReanalyzeAsync; route guard test through production read path
- Remove Plugin.ShouldSettleReanalyzeAsync (per-mode async wrapper) that was only
exercised by tests; production eligibility goes through the batch
GetSettleReanalysisStatesAsync + static ShouldSettleReanalyze. The persistence
guard test now exercises that same production read path via a local helper. - Document why ExpandSettledResetModesForDerivedSegments' derived Preview mode is
reset but not tracked in completedSettledModes (its completion rides on Credits).
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- cleanup
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Add optional recap detection fallback to early black frame (#771)
-
Initial plan
-
Add optional recap fallback using first black frame
-
Recap segments from the first-black-frame fallback now pass through TimeAdjustmentHelper
-
Use a combination of black frames and audio
Changed:
Added Recap fingerprint range support in FFmpegWrapper.cs (line 135).
Added Recap-mode Chromaprint behavior and blackframe boundary refinement in ChromaprintAnalyzer.cs (line 117).
Improved blackframe recap fallback to pick the latest valid black frame, not the first, capped before intro when available in ChapterAnalyzer.cs (line 177).
Ensured Introduction runs before Recap and added Recap Chromaprint to the analyzer chain in BaseItemAnalyzerTask.cs (line 68).
Added Recap Chromaprint tuning to config hashing in ConfigHasher.cs (line 44).
Updated UI copy/options in analysis.ts (line 109) and action-bar.ts (line 19).
Added/updated tests in TestChapterAnalyzer.cs (line 53) and TestRecapDetection.cs (line 17).-
Provide settings for recap min and max durations
-
Make sure the FullLengthChapters setting is applied
-
Addressed the review comments with a comment
-
Rename the setting to avoid confusion
-
Resolve conflicts with merged branch
Co-authored-by: copilot-swe-agent[bot] 198982749+Copilot@users.noreply.github.com
Co-authored-by: TwistedUmbrellaX 1173913+AbandonedCart@users.noreply.github.com
Co-authored-by: TwistedUmbrellaX twistedumbrella@gmail.com- Add structured exclusion lists (#795)
-
Add structured exclusion lists
-
Add library name autocomplete to series/movie exclusion fields
Feed the SeriesExclusions and MovieExclusions fields native datalist
suggestions sourced from the user's libraries (getLibraries +
getShowsInLibrary, filtered by item type), reusing the existing
exclusion-list-field suggestion hook used by the path field. Gives
type-to-filter search without a bespoke combobox.Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Harden exclusion name evaluation and document cache-delete cancellation
- Accept nullable series/movie names in ExclusionPolicy and trim safely,
restoring the defensive null handling the pre-refactor code had (Jellyfin
metadata is non-null at compile time but not guaranteed at runtime). - Document why the excluded-timestamp cache delete uses CancellationToken.None:
the segment/season-state rows are already deleted, so aborting would orphan
cache entries — mirroring the existing rationale in EraseSeasonAsync.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Fixea´s
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Make credit black-frame detection adaptive (#799)
-
Make credit black-frame detection adaptive
-
Address credit-detection review findings
- ConfigHasher: include BlackFrameMinimumPercentage in the BlackInterval
detection-cache hash. It is passed to blackdetect as pic_th and baked into
cached intervals, so changing it must invalidate the cache. - CreditSceneBuilder.FindSupportingInterval: select the overlapping interval
that yields the longest supported scene instead of the first match, so an
early short interval no longer masks a later one that meets the minimum
duration. - CreditSceneBuilder.DetectCreditScenes: gate refinement-only short scenes on
whether boundary refinement is enabled, so an unrefinable short scene no
longer suppresses the interval fallback when RefineCreditsBoundary is off. - FFmpegService.DetectBlackIntervalsAsync: drop -skip_frame noref so blackdetect
sees the full decoded stream (avoids merging through non-black B-frames or
missing short intervals). - Tests: assert the probe-window Start/End directly (TimeRange equality is
duration-based), update the BlackInterval cache-hash test, and add regression
tests for interval selection and the disabled-refinement fallback.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Make blackdetect frame-skip configurable (ThoroughBlackIntervalScan)
Restore the -skip_frame noref performance optimization on the credits
blackdetect scan and make it opt-out via a new ThoroughBlackIntervalScan
setting. The default keeps reference-frame-only decoding (fast); enabling
it decodes every frame for higher accuracy on very short or B-frame-only
black intervals, at the cost of slower scans.- FFmpegService.DetectBlackIntervalsAsync: emit -skip_frame noref unless
ThoroughBlackIntervalScan is enabled. - ConfigHasher: include ThoroughBlackIntervalScan in the BlackInterval
detection-cache hash so toggling it invalidates cached intervals. - Add the toggle to the Black Frame settings tab, gated on the alternative
black frame analyzer like RefineCreditsBoundary. - Tests: restore the noref arg-string expectation and add a cache-hash
invalidation test for the new toggle.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Clean up credit detection: dedupe density check, centralize tuning constants
- Replace the local MeetsBlackFrameDensity helper with
CreditSceneMetricsCalculator.Calculate(...).MeetsDensity(...). The helper
duplicated the metrics calculator, and its ref-cursor "optimization" was inert
(MergeNearbyScenes re-declared the cursor to 0 on every iteration), so this
removes the duplication with no behavior or performance change. - Move MinimumIntervalOverlapSeconds and MinimumBoundaryProbeWindow into
CreditDetectionPolicy alongside the other tuning constants.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
-
Simplify adaptive credits detection
-
Tidy blackdetect duration constant and argument construction
- Reintroduce a single source of truth for the blackdetect minimum duration
(BlackInterval.MinimumDetectionDuration), referenced by both the blackdetect
d= filter argument and the BlackInterval detection-cache hash so the two
cannot silently drift. - Collapse the now-unconditional blackdetect argument list back into a single
collection initializer.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Restore matrix coverage for RankCreditCandidates ranking
Replace the single two-scene assertion with a focused theory covering:
latest-scene fallback, interval promoting an earlier scene, sub-threshold
overlap (below MinimumIntervalOverlapSeconds) not counting as support, an
interval supporting the later scene, and the latest supported scene winning
among multiple candidates.Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Clarify IsSparse doc and pin sparse-no-interval-support behavior
Reword IsSparse to describe it as an opportunistic interval-refinement
trigger rather than a hard trust gate (it is only consulted for a single
scene that has already cleared the density and duration gates).Add a regression test pinning that a temporally sparse single scene whose
blackdetect probe finds no supporting interval is still returned, as the
deliberate counterpart to the count==0 candidate path.Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Detect non-black "card" credits via an entropy/saturation fallback (#798)
- Detect non-black "card" credits via an entropy/saturation fallback
When the black-frame scan finds no credits, fall back to a single extra
keyframe decode that emits luma-histogram entropy + mean saturation
(stock FFmpegentropy,signalstats,metadata=print) and accepts a
sustained, near-uniform "card" background as credits. This is
colour-agnostic, so credits rendered on black, coloured, or bright cards
are all detected. The frame-accurate black-frame path is byte-for-byte
unchanged and runs first; the fallback can only add detections when the
black path returns nothing. Gated by a newDetectNonBlackCredits
configuration option (default on) and cached like the black-frame scan.Also includes three correctness/perf fixes found while auditing the
analyzer:- NormalizeThreshold: clamp the 1st-percentile index into range so a
sparse keyframe set (<100 frames) cannot index out of bounds. - CreditsBoundaryHelper.SelectProbeMinimum: use FirstOrDefault and fall
back to the scene-change threshold instead of throwing from First()
when a scene start frame has no matching keyframe (interval-derived
scenes). - CreditSceneBuilder: hoist the merge-search cursor out of the merge
loop so scene merging no longer rescans from frame 0 every iteration
(O(n^2) -> O(n)).
- Invalidate stored credits analysis when DetectNonBlackCredits toggles
Include the DetectNonBlackCredits flag in the Credits-mode analysis hash
so enabling/disabling the non-black fallback re-runs credit detection
instead of hash-matching a stale result with the old segments. Add a
regression test asserting the hash changes with the flag.- Rename SelectLongestQualifyingRun to SelectLatestQualifyingRun
The helper selects the latest qualifying credit run (credits sit at the
tail), not the longest. Rename the method and the carried-over best
parameter, and document that the running best is preserved rather than
compared by length. No behavior change.- Trim over-extended non-black credit tails via density-anchored run end
FindCreditRange bridged across non-card keyframes purely on a time gap, so
periodic near-uniform frames in non-credit tail content kept extending a
credit run past its real end (over-skip). Anchor the run end to the dense
card cluster: walk the end back while the final card attaches only through
an above-cadence gap (> maximumInRunGap * TrailingTrimGapFactor), dropping
isolated tail cards without touching the dense body, so genuinely
interleaved credits (a brief ident bracketed by cards) are preserved.Factor 0.5 validated against a synthetic bracket (over-extension trims;
mid/near-end interludes, sparse 8s-GOP credits, and a 4s-spaced final card
all preserved). Adds focused + bracket regression tests.Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Collapse double blank line in FakeFFmpegService test mock
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Anchor credit tail-trim to the run's own cadence (fix long-GOP false negatives)
The trailing-trim threshold derived from maximumInRunGap, which is capped at
MaximumSceneMergeGapSeconds (20). For keyframe cadences above ~10s the cap
decoupled the threshold from the real cadence, so every card in a uniformly
sparse all-card run (e.g. 12s GOP) looked isolated and the run was trimmed to
nothing — a false negative on long-GOP sources.Key the trim off the run's own median card-to-card gap (x TrailingTrimGapMultiplier
= 2.5) instead: a uniform run has every gap near its median so nothing trims,
while a sparse tail drifting off a denser body still sits well above that body's
median and is removed. Adds a 12s-cadence regression case; the ambiguous
short-dense-prefix case now correctly keeps as a sparse run.Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Trim isolated leading cards too (symmetric credit-run anchoring)
The trailing trim only walked the run end; SelectLatestQualifyingRun always
took runCards[0] as the start, so an isolated low-entropy pre-credit card
(e.g. a title card 14-16s before the real credits) that bridged into the dense
block on a longer-GOP source pulled the start too early.Generalize the trim to both ends: TrimIsolatedEnds walks each end inward,
dropping a leading or trailing card whose gap to its neighbour exceeds the
run's own median card gap x TrailingTrimGapMultiplier. Each end stops at the
first in-cadence card, so a dense body - including two real credit sub-blocks
separated by a gap - is untouched, and uniform sparse long-GOP runs are still
preserved. Adds a focused leading-trim regression plus a bracket case.Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
-
cleanup
-
Update CreditEntropyFallback.cs
-
Add null guard to FindCreditRange; expose IsCreditCardKeyframe as internal with boundary theory test
- ArgumentNullException.ThrowIfNull(visuals) in FindCreditRange to match the
codebase's argument-validation convention (was an unguarded NRE path). - IsCreditCardKeyframe: private -> internal (InternalsVisibleTo already set) so
the entropy/saturation classification boundary is unit-testable directly. - Restore focused TestIsCreditCardKeyframe [Theory] pinning both exclusive
maxima (entropy < 0.35, saturation < 96) at their boundaries.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Bound non-black credit scan to credits window and normalize saturation scale
- DetectKeyframeVisualsAsync now scans [CreditsFingerprintStart, CreditsFingerprintEnd]
via GetFingerprintRange +-to range.Duration(was start-to-EOF). FindCreditRange
picks the latest qualifying run, so an unbounded scan could select a muted tail
beyond the credits window (e.g. trailing video after the probed audio duration) as
credits. Cache is now keyed by the real (start, end). Black-frame path unchanged. - Prepend format=yuv420p to the entropy/signalstats filter graph. signalstats SATAVG
is reported in the source's native sample scale (~4x higher on 10-bit), so the
8-bit-tuned saturation<96 gate missed muted cards on 10-bit/HDR sources; forcing
8-bit pins both signals to the tuned scale.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Require SATAVG before emitting a KeyframeVisual
ParseKeyframeVisuals emitted a frame once entropy was parsed, even if the
signalstats.SATAVG line was missing (e.g. output truncated before it). The
default saturation 0 then passed the low-saturation credit-card gate
(0 < SaturationCreditMaximum), so a low-entropy frame with dropped saturation
could fabricate a false non-black credit. Track hasSaturation alongside
hasEntropy, reset it per frame, and require both at both emit sites, mirroring
the existing "drop blocks without entropy" behavior. Adds a regression test for
a trailing block truncated before SATAVG.Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Anchor credit grouping/trim to card cadence (fix sparse-credit miss & tail over-extend)
Two cadence-estimation bugs in the non-black credit fallback:
-
Grouping (Finding 1): EstimateMaximumInRunGap derived the in-run bridge from the
median gap of ALL keyframes, so dense pre-credit content drove it below the card
spacing and split long-GOP static-card credits into discarded sub-minimum runs.
Now estimated from card keyframes only, so it tracks the credit-card cadence. -
Trim (Finding 2): TrimIsolatedEnds keyed off the bridged run's overall median,
which a long sparse tail dominates -> the trailing trim stops and the range
over-extends to the last stray card. Now anchored to the dense-body cadence
(lower-quartile gap); when trimming would leave less than the minimum duration
there is no dominant dense body, so the full (uniformly sparse) run is kept.
Adds regression tests for both, plus an empty-blackFrames fallback-branch test.
All 11 trailing-trim bracket cases and existing fallback tests stay green.Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Decouple credit run grouping; gate non-black hash; harden metadata parsing
Addresses four review findings in the non-black credit fallback:
-
Finding 1 (grouping): the in-run bridge was one global cadence estimate, so an
earlier dense card run pulled it below a later long-GOP credit run's spacing and
split the real credits into discarded sub-minimum runs (returning the earlier
run). Replaced with a fixed MaximumSceneMergeGapSeconds bridge so each run is
independent; removed the now-dead cadence estimate. The dense-anchored trim still
handles within-run isolated edges. -
Finding 2 (cache): ConfigHasher appended |nonblack= unconditionally, invalidating
cached credits on the default BlackFrameAnalyzer path that cannot observe the flag
(and hides it in the UI). Now included only when UseAlternativeBlackFrameAnalyzer
is true. -
Finding 3 (parser): the keyframe pts_time/entropy/saturation regexes were not
exponent-aware and truncated exponent-form numbers at the mantissa. Made them
exponent-aware (defensive; stock FFmpeg emits decimal here). -
Finding 4 (tests): added coverage for the candidate->interval-miss->fallback path.
Regression tests added for each; all trailing-trim bracket cases stay green.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Reject sparse cards bridged across busy content via card-density floor
FindCreditRange skipped non-card keyframes entirely, so two isolated
card-like frames within MaximumSceneMergeGapSeconds bridged across busy
content (non-card keyframes between them) qualified as a sustained credit
run. Add a card-density check on the trimmed run span: keyframes inside
the span must be >=50% cards. A genuine long-GOP sparse run has no
non-card keyframes between its cards (density ~1.0) and is kept; only
sparse cards interspersed with busy content are rejected.Add regression test plus flip the bracket's predominantly-sparse case
(same false pattern) to null.Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Add disabled-setting regression test for the empty black-scan branch
TestDetectCreditsAsync_NonBlackCreditsDisabled_SkipsFallback seeded
non-empty pblack=0 frames, covering only the blackFrames.Count > 0 path.
Add a companion that seeds an empty scan ([]) with DetectNonBlackCredits
off and asserts the keyframe-visual fallback is never started
(VisualScanCalls == 0), pinning that the Count == 0 branch also honors
the user-disabled option. Test-only; no production change.Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
-
Fix ffmpeg test fixture noise
-
Scope DetectNonBlackCredits copy to muted/neutral cards, not vivid colour
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
The UI/config wording advertised 'solid coloured' cards, but the classifier gates on saturation < 96, so a vivid saturated card (e.g. solid blue, SATAVG ~113) is rejected. Excluding vivid uniform frames is deliberate: a solid-colour content frame (fade, stylised transition, saturated sky) is indistinguishable from a saturated colour card by entropy+saturation alone, so admitting them would cost the fallback's zero-false-positive discipline. Correct the UI string and code docs to describe what is actually covered (black/white/grey/muted-colour near-uniform cards) and document the exclusion rationale on the saturation constant. No logic change.
-
Update TestCacheOperations.cs
-
Keep sparse all-card credit runs together across long GOP gaps
FindCreditRange split a run on any card-to-card gap over the fixed 20s
bridge, so a real all-card credit sequence on a source whose keyframe
cadence is just above 20s (e.g. cards every 21s) was split into
one-frame runs that each failed the minimum duration, returning null.Break a run only when real content separates two cards: a gap beyond the
bridge AND at least one intervening non-card keyframe. A sparse all-card
source (keyframes farther apart than the bridge but nothing non-card
between) now stays one run regardless of GOP length; genuine content
between two card groups still splits them (the latest qualifying run
wins). Unifies with the density floor: non-card evidence, not raw time,
separates runs.Add a regression test for the 21s-cadence all-card case, and make the
LaterSparseCredits test realistic (it omitted the content that exists
between two separated credit groups, which is the evidence the split
keys on).Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- Clip non-black keyframe scan to the credits window
DetectKeyframeVisualsAsync relied on -to to bound the scan, but FFmpeg
with -skip_frame nokey still emits keyframes well past the requested
duration (reproduced on the repo fixture: a 5s window via -ss 1 -to 5
returned pts_time 9/19/29; -ss 5 -to 30 returned 5/15/25/35/45/55).
Those out-of-window frames were parsed, cached, and returned, so
FindCreditRange could select a low-entropy run past CreditsFingerprintEnd
and DetectNonBlackCreditsAsync would persist credits outside the
configured scan window.Clip parsed visuals to [0, range.Duration] (times are relative to the
-ss seek) before caching/returning. Add a real-FFmpeg regression test on
credits.mp4 asserting the window [5,35] returns only the in-window
keyframes (5/15/25) and never the leaked frames past the duration; the
prior fixture test only exercised the showinfo DetectKeyFramesAsync path.Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
-
Inline FFmpeg process runner
-
Simplify detection cache schema check
-
Move shared CI setup
-
Moved shared helper out of TestEntrypointEvents into EntrypointTestHelpers
-
Remove RefCountedSemaphore, _itemLocksLock, RentItemLock, and ReturnItemLock
-
Refine scheduled task semaphore lease
-
FindContiguous droping the final currentRange
-
Keep
NoSegmentsepisodes eligible for analyzer fallback chain (#812)
-
Allow NoSegments episodes to be re-analyzed
-
Document and test NoSegments analyzer eligibility
-
Fix NoSegments seasons stranded when Chromaprint becomes available
Revert the analyzer-gate change back to NotAnalyzed semantics: a season
settled as NoSegments is a negative-cache hit for the current config and
must not be re-run every scheduled pass. Instead, fold FFmpeg/Chromaprint
availability into the analysis config hash for the Chromaprint-using modes
(Introduction, Credits, Recap).Root cause: when the first scan ran without a Chromaprint-capable FFmpeg,
episodes were recorded as analyzed-with-no-segments and reloaded as
NoSegments on later scans. Because ffmpegValid was not part of the config
hash, hashMatches stayed true and the season was skipped forever even after
Chromaprint became available. Hashing ffmpegValid makes the stored hash stop
matching on a capability change, so those episodes reset to NotAnalyzed and
are re-analyzed exactly once instead of every run.Tests: gate tests corrected to negative-cache semantics; added hash tests
asserting capability-awareness for chromaprint modes and invariance for
chapter-only modes (Preview, Commercial).Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
-
Handle null chapter results in queue verification
-
DispatchProxy cannot use a sealed proxy type
Co-authored-by: copilot-swe-agent[bot] 198982749+Copilot@users.noreply.github.com
Co-authored-by: rlauuzo 46294892+rlauuzo@users.noreply.github.com
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Co-authored-by: TwistedUmbrellaX twistedumbrella@gmail.com
Co-authored-by: TwistedUmbrellaX 1173913+AbandonedCart@users.noreply.github.com- Optimization to prevent marking analyzed episodes (#817)
-
Handle null chapter results in queue verification
-
Cache FFmpeg validity in queue manager
- Optimize queue verification and remove analysis hash overload. (#818)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
-
Release v1.10.11.22
-
Move black frame recap option to black frame page
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-