• v0.8.0 ac4bbadd96

    v0.8.0
    All checks were successful
    Release / Check if release needed (push) Successful in 8s
    Release / Release (push) Successful in 12m2s
    Stable

    Wuast94 released this 2026-07-13 00:44:03 +02:00 | 0 commits to pgsql since this release

    Bug 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 FFmpeg entropy,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 new DetectNonBlackCredits
    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 NoSegments episodes 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
  • v0.7.1 3509e2154a

    v0.7.1
    All checks were successful
    Release / Check if release needed (push) Successful in 14s
    Release / Release (push) Successful in 2m16s
    Stable

    Wuast94 released this 2026-06-24 20:39:14 +02:00 | 29 commits to pgsql since this release

    Bug Fixes

    • Migrate pgsql config hash columns

    Miscellaneous

    • Avoid node lts alias in release
    Downloads
  • v0.7.0 cec7ba7b22

    v0.7.0
    All checks were successful
    Release / Check if release needed (push) Successful in 6s
    Release / Release (push) Successful in 2m16s
    Stable

    Wuast94 released this 2026-06-10 19:54:51 +02:00 | 31 commits to pgsql since this release

    Bug Fixes

    • 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 legacy pgsql fingerprint cache

    Features

    • Native PostgreSQL provider for Intro Skipper

    • Initial pgsql plugin release

    • Exclude Jellyfin framework assemblies from plugin package

    • Adopt upstream cache dashboard for pgsql

    Miscellaneous

    • Bump github/codeql-action from 4.36.1 to 4.36.2 (#782)

    • 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

    Other

    • Release v1.10.11.21
    Downloads
  • v0.6.0 df6f2f8d71

    v0.6.0
    All checks were successful
    Release / Check if release needed (push) Successful in 5s
    Release / Release (push) Successful in 2m9s
    Stable

    Wuast94 released this 2026-06-07 15:15:25 +02:00 | 33 commits to pgsql since this release

    Bug Fixes

    • 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 legacy pgsql fingerprint cache

    Features

    • Native PostgreSQL provider for Intro Skipper

    • Initial pgsql plugin release

    • Exclude Jellyfin framework assemblies from plugin package

    • Adopt upstream cache dashboard for pgsql

    Miscellaneous

    • Bump Microsoft.NET.Test.Sdk from 18.4.0 to 18.5.1 (#759)

    • Bump github/codeql-action from 4.35.2 to 4.35.3 (#758)

    • Bump github/codeql-action from 4.35.3 to 4.35.4 (#764)

    • Bump coverlet.collector from 10.0.0 to 10.0.1 (#766)

    • Bump github/codeql-action from 4.35.4 to 4.35.5 (#765)

    • Bump github/codeql-action from 4.35.5 to 4.36.0 (#770)

    • Bump Microsoft.NET.Test.Sdk from 18.5.1 to 18.6.0 (#775)

    • Bump github/codeql-action from 4.36.0 to 4.36.1 (#774)

    • Update deps

    • 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

    Other

    • Avoid SQLite param limit in CleanTimestampsAsync

    Prevent exceeding SQLite parameter limits by batching deletions. Introduces SqliteParameterBatchSize (500) and updates CleanTimestampsAsync to load distinct segment episode IDs, compute stale IDs, and delete them in chunks. Adds a test (CleanTimestampsAsync_DoesNotExceedSqliteVariableLimit_WhenEpisodeListIsLarge) that creates a large episode set (~33k), verifies only retained segments remain, and includes helper logic to clean up temporary SQLite files.

    • Migrate legacy fingerprint cache to DB (#754)

    Co-authored-by: rlauuzo 46294892+rlauuzo@users.noreply.github.com

    • Release v1.10.11.19

    • Migrate all legacy detection cache files (#755)

    • Extend legacy cache migration to silence/keyframes/blackframes

    Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

    • Rename legacy detection cache migration

    Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

    • Use actual legacy cache paths during migration

    Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

    • Simplify legacy detection cache migration helpers

    Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

    • Reduce legacy migration log noise

    Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

    • Parse legacy detection cache files once

    Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

    • Optimize legacy detection cache scan

    Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

    • Simplify legacy detection filename parsing

    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>

    • Cap AnalysisPercent at 50 (#752)
    • Cap AnalysisPercent at 50 to prevent excessive processing

    Co-authored-by: rlauuzo 46294892+rlauuzo@users.noreply.github.com

    • Clamp AnalysisPercent lower bound

    Co-authored-by: rlauuzo 46294892+rlauuzo@users.noreply.github.com

    • Centralize AnalysisPercent bounds

    Co-authored-by: rlauuzo 46294892+rlauuzo@users.noreply.github.com

    • Centralize analysis setting defaults

    Co-authored-by: rlauuzo 46294892+rlauuzo@users.noreply.github.com

    • Inline SQLite PRAGMA command text

    Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>


    Co-authored-by: rlauuzo 46294892+rlauuzo@users.noreply.github.com
    Co-authored-by: Kilian von Pflugk github@jumoog.io
    Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

    • Fix credits analysis failures on large seasons and add intro/credits overlap guard (#757)
    • Fix 1000-episode analysis, add intro/credits overlap guard, and tests

    Agent-Logs-Url: https://github.com/intro-skipper/intro-skipper/sessions/e39b4730-0be1-4ce7-8a6f-fe5f3bd0741a

    Co-authored-by: AbandonedCart 1173913+AbandonedCart@users.noreply.github.com

    • Merge three UpdateTimestampAsync tests into a single Theory

    Agent-Logs-Url: https://github.com/intro-skipper/intro-skipper/sessions/e39b4730-0be1-4ce7-8a6f-fe5f3bd0741a

    Co-authored-by: AbandonedCart 1173913+AbandonedCart@users.noreply.github.com

    • Potential fix for pull request finding 'Call to 'System.IO.Path.Combine' may silently drop its earlier arguments'

    Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

    • Potential fix for pull request finding 'Inefficient use of ContainsKey'

    Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

    • Potential fix for pull request finding 'Call to 'System.IO.Path.Combine' may silently drop its earlier arguments'

    Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

    • Potential fix for pull request finding 'Call to 'System.IO.Path.Combine' may silently drop its earlier arguments'

    Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

    • Apply suggestions from code review

    Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

    • Potential fix for pull request finding 'Call to 'System.IO.Path.Combine' may silently drop its earlier arguments'

    Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>


    Co-authored-by: copilot-swe-agent[bot] 198982749+Copilot@users.noreply.github.com
    Co-authored-by: AbandonedCart 1173913+AbandonedCart@users.noreply.github.com
    Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

    • Update branding with a more "fitting" color scheme (#768)
    • Some mildly modern refreshed branding

    • Add matching icon assets

    • fix icon centering and update SVG file

    • Update README.md to use current logo

    • Use hashes for analysis state and probe audio time (#767)

    • Use hashes for analysis state and probe audio time

    Added targeted config hashes for analysis results and detection cache entries.
    Stale automatic segments are cleaned and reanalyzed when relevant settings change.
    User/editor-provided segments are still preserved and still override analysis.
    Added optional ProbeAudioDuration setting using ffprobe so credits fingerprinting can use actual audio duration instead of inflated container runtime.
    Added the dashboard toggle under FFmpeg settings.
    Removed the old “settings changed means globally AnalyzeAgain” behavior in favor of hash-based freshness.

    • Fix error CS1620 and error SA1122

    • Patched ConfigHasher.cs so invariant formatting helper receives separate FormattableString parts

    • Update IntroSkipper/FFmpegWrapper.cs

    Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

    • OnSettingsChanged now updates _config and sets Plugin.Instance.AnalyzeAgain = true again

    • Potential fix for pull request finding 'Call to 'System.IO.Path.Combine' may silently drop its earlier arguments'

    Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

    • Update IntroSkipper/FFmpegWrapper.cs

    Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

    • Revert "Potential fix for pull request finding 'Call to 'System.IO.Path.Combine' may silently drop its earlier arguments'"

    This reverts commit 2cbfec7f1d29c3abf0372e875ae6b57c623e3637.

    • Update IntroSkipper/FFmpegWrapper.cs

    Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

    • TryReadJsonCache now accepts rows with an empty ConfigHash as legacy-compatible,

    • HasCachedFingerprint again treats empty ConfigHash rows as valid legacy DB cache entries


    Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
    Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

    • [skip actions] update copyright headers to SPDX format across all files

    • Release v1.10.11.20

    • Fix ConfigHash and migrations (including legacy) (#777)

    • Add ConfigHash legacy schema compatibility handling

    • Backfill missing ConfigHash columns for legacy SQLite schemas

    • Potential fix for pull request finding 'Generic catch clause'

    Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

    • Address code review: generalize ColumnExists and fix connection lifecycle in EnsureConfigHashColumns

    • Fix formatted string in a SQL statement

    • Avoid hardcoding table-specific PRAGMA statements in ColumnExists

    • Fix the security issue that was reintroduced

    • Improve migrations for startup reliability

    • Fix the reintroduced reintroduced security issue

    • Applied the CI fix and the magic-number cleanup.

    • Migration artifacts no longer reference AnalysisMode or IntroSkipper.Data


    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: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
    Co-authored-by: TwistedUmbrellaX twistedumbrella@gmail.com

    • Fix legacy database initialization order (#780)
    • Fix legacy database initialization order

    • Document legacy DB initialization order

    Downloads
  • v0.5.2 7aae7f7245

    v0.5.2
    All checks were successful
    Release / Check if release needed (push) Successful in 4s
    Release / Release (push) Successful in 1m29s
    Stable

    Wuast94 released this 2026-05-03 01:12:16 +02:00 | 52 commits to pgsql since this release

    Bug Fixes

    • Migrate legacy pgsql fingerprint cache

    Other

    • Avoid SQLite param limit in CleanTimestampsAsync

    Prevent exceeding SQLite parameter limits by batching deletions. Introduces SqliteParameterBatchSize (500) and updates CleanTimestampsAsync to load distinct segment episode IDs, compute stale IDs, and delete them in chunks. Adds a test (CleanTimestampsAsync_DoesNotExceedSqliteVariableLimit_WhenEpisodeListIsLarge) that creates a large episode set (~33k), verifies only retained segments remain, and includes helper logic to clean up temporary SQLite files.

    • Migrate legacy fingerprint cache to DB (#754)

    Co-authored-by: rlauuzo 46294892+rlauuzo@users.noreply.github.com

    • Release v1.10.11.19
    Downloads
  • v0.5.1 01eee02064

    v0.5.1
    All checks were successful
    Release / Check if release needed (push) Successful in 4s
    Release / Release (push) Successful in 1m23s
    Stable

    Wuast94 released this 2026-05-02 15:52:36 +02:00 | 57 commits to pgsql since this release

    Bug Fixes

    • Use pgsql plugin id in dashboard
    Downloads
  • v0.5.0 5011f2315f

    v0.5.0
    All checks were successful
    Release / Check if release needed (push) Successful in 4s
    Release / Release (push) Successful in 1m28s
    Stable

    Wuast94 released this 2026-05-02 15:43:07 +02:00 | 58 commits to pgsql since this release

    Bug Fixes

    • Re-analyze segments on settings change (#735)

    • Display full 4-part plugin version string

    • Fix

    • Fix2

    • Fix3

    • Use dotnet publish to include all runtime dependencies

    • Exclude design-time DLLs and enable dynamic loading

    • Db

    • Db2

    • Db3

    • Db4

    • Db5

    Features

    • Enhanced binary caching mechanism (#726)

    • Native PostgreSQL provider for Intro Skipper

    • Initial pgsql plugin release

    • Exclude Jellyfin framework assemblies from plugin package

    • Adopt upstream cache dashboard for pgsql

    Miscellaneous

    • Bump signpath/github-action-submit-signing-request from 2.0 to 2.1 (#732)

    • Bump Microsoft.NET.Test.Sdk from 18.3.0 to 18.4.0 (#733)

    • Update dashboard build artifacts

    • Update dashboard build artifacts

    • Update vite and related dependencies to version 8.0.8

    • Bump coverlet.collector from 8.0.1 to 10.0.0 (#744)

    • Bump github/codeql-action from 4.35.1 to 4.35.2 (#742)

    • Bump signpath/github-action-submit-signing-request (#743)

    • Replace analyzer filter logic with priority-based chain (#745)

    • Scope MediaSegments filter to itemId actions via convention

    • 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

    Other

    • Update README disclaimer to clarify data extraction and ownership risks (#729)

    Agent-Logs-Url: https://github.com/intro-skipper/intro-skipper/sessions/ee5e5ac8-a1a5-4ed4-ae0a-f7dccb838003

    Co-authored-by: copilot-swe-agent[bot] 198982749+Copilot@users.noreply.github.com
    Co-authored-by: AbandonedCart 1173913+AbandonedCart@users.noreply.github.com

    • Tighten README disclaimer wording per code review feedback (#730)

    Agent-Logs-Url: https://github.com/intro-skipper/intro-skipper/sessions/478ce14a-e660-4945-98a3-d608390b7b83

    Co-authored-by: copilot-swe-agent[bot] 198982749+Copilot@users.noreply.github.com
    Co-authored-by: AbandonedCart 1173913+AbandonedCart@users.noreply.github.com

    • Route DetectSegmentsTask through IMediaSegmentProvider (#731)
    • Route scheduled analysis through IMediaSegmentProvider; trigger Jellyfin extraction task on completion

    Agent-Logs-Url: https://github.com/intro-skipper/intro-skipper/sessions/c55336d3-8699-4e9e-b7ce-2839a53f8c94

    Co-authored-by: AbandonedCart 1173913+AbandonedCart@users.noreply.github.com

    • Update BaseItemAnalyzerTask.cs

    • Update PluginConfiguration.cs

    • Remove UpdateMediaSegments overlap with pushToJellyfin in analysis path; drop dead log method

    Agent-Logs-Url: https://github.com/intro-skipper/intro-skipper/sessions/8b2e5d52-1948-44e5-a28c-f0271c902a6b

    Co-authored-by: AbandonedCart 1173913+AbandonedCart@users.noreply.github.com

    • Add diagnostic logs for extraction task not found / not idle in DetectSegmentsTask

    Agent-Logs-Url: https://github.com/intro-skipper/intro-skipper/sessions/5f4bdd76-94ba-4127-b140-6410f8df3998

    Co-authored-by: AbandonedCart 1173913+AbandonedCart@users.noreply.github.com

    • Update BaseItemAnalyzerTask.cs

    It's not actually user facing, but this will silence review


    Co-authored-by: copilot-swe-agent[bot] 198982749+Copilot@users.noreply.github.com
    Co-authored-by: AbandonedCart 1173913+AbandonedCart@users.noreply.github.com

    • Fix scheduled task leaving stale segments after analysis (#734)

    Remove pushToJellyfin parameter from BaseItemAnalyzerTask.AnalyzeItemsAsync and
    the UpdateMediaSegments config gate from the analysis push path.

    Previously, DetectSegmentsTask passed pushToJellyfin: false and relied on
    Jellyfin's TaskExtractMediaSegments to pull updated segments. This approach
    could silently fail if the task wasn't found or wasn't idle, leaving users with
    stale segments after analysis.

    Now all callers (scheduled task, automatic task, ScanSeason) push newly-analyzed
    segments directly via UpdateMediaSegmentsAsync immediately after analysis,
    consistent with how the dashboard's ScanSeason option works. The Jellyfin
    extraction task trigger is kept as an additional sync for already-analyzed items.

    Agent-Logs-Url: https://github.com/intro-skipper/intro-skipper/sessions/b88f13fa-b316-42ed-81c2-fd76edf43fb7

    Co-authored-by: copilot-swe-agent[bot] 198982749+Copilot@users.noreply.github.com
    Co-authored-by: AbandonedCart 1173913+AbandonedCart@users.noreply.github.com

    • Respect config flag when updating media segments (#736)

    Gate the media segment update behind the _config.UpdateMediaSegments option. The code now checks both updateMediaSegments and the configuration flag before calling UpdateMediaSegmentsAsync, preventing unwanted updates when the feature is disabled in settings.

    • Add web dashboard and CI pnpm/node setup (#737)

    Co-authored-by: Kilian von Pflugk github@jumoog.io

    • Remove Jellyfin SDK; use direct API calls

    Remove the @jellyfin/sdk dependency (package.json + pnpm-lock.yaml) and refactor jellyfin-client to call the server via a getJson helper instead of the SDK. Add lightweight Jellyfin response types to types.ts (library/media/season/episode response shapes) and update getLibraries/getShowsInLibrary/getSeasons/getEpisodes to build query URLs, parse the simplified responses, and handle missing data. This reduces dependency surface and simplifies HTTP handling while preserving existing functionality.

    • Rename dashboard assets to introskipper.*

    • fix(web): log errors in jellyfin-client fetch helpers

    • Reformat web files for consistent indentation

    • Refresh anime Preview segment when credits shift on re-analyze (#741)
    • fix: refresh anime Preview segment when credits shift

    The anime-preview helper short-circuited whenever any valid Preview row
    existed, so when #735's AnalyzeAgain path re-analyzed Credits after a
    settings change the stale Preview (oldCreditsEnd → duration) was kept
    instead of being rewritten to the new credits.End.

    Extract the decision into a pure ComputeAnimePreviewFromCredits helper
    and skip only when an existing Preview's Start is within 0.5 s of the
    current credits.End (chromaprint quantises to ~0.124 s, so sub-second
    drift is noise). Also thread a guarded Plugin local through the call
    chain so AnalyzeItemsAsync no longer relies on Plugin.Instance!.

    Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com

    • Address PR #741 review: respect user-provided Preview, inclusive tolerance
    • Skip the anime preview path entirely when the episode already has a
      user-provided Preview segment. UpdateTimestampAsync silently no-ops in
      that case, so the previous code emitted a misleading "Created anime
      preview" log and marked the episode Analyzed without a write
      (Copilot review feedback).
    • Switch tolerance comparison from < to <= so an exact 0.5 s drift is
      treated as equal, matching the doc text (Sourcery + Copilot feedback).
    • Add a boundary test for the inclusive comparison.

    Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com

    • Also refresh anime Preview when episode duration changes

    Copilot review on PR #741: comparing only Preview.Start vs credits.End
    left a stale Preview.End if the episode file was replaced (different
    cut, file swap) and credits.End happened to match. Add a parallel
    tolerance check on existing.End vs the current episodeDuration.

    Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com


    Co-authored-by: Claude Opus 4.7 noreply@anthropic.com
    Co-authored-by: TwistedUmbrellaX 1173913+AbandonedCart@users.noreply.github.com

    • Refactor BlackFrameAltAnalyzer: density gating, boundary refinement fix, and RefineCreditsBoundary toggle (#748)
    • fix: use preceding keyframe for RefineBoundary probe range

    FindBoundaryKeyframeTimes now returns the immediately preceding keyframe
    regardless of its black percentage, instead of searching backward for the
    last non-black keyframe. On dark shows where most frames exceed the black
    threshold, the old behavior produced overly wide probe ranges that could
    undo the transition-frame correction from DetectCreditScenes.

    Also renamed lastNonBlackTime to lastKeyframeTime throughout the boundary
    refinement pipeline (FindBoundaryKeyframeTimes, RefineBoundary,
    ConvertProbeTimestamp) for consistency.

    • feat: add RefineCreditsBoundary config option

    New toggle (default: true) allows users to disable frame-level boundary
    refinement in the alternative black frame analyzer, falling back to
    keyframe-only accuracy for faster analysis.

    • Update IntroSkipper.csproj

    • Add blackframe-alt fingerprint test files

    Add three new fingerprint files to IntroSkipper.Tests/fingerprints: blackframe-alt-3, blackframe-alt-4, and blackframe-alt-5. Each file contains parsed blackframe output used as test data for intro-skipping detection logic.

    • feat: add RefineCreditsBoundary toggle to Black Frame UI tab

    Visible only when the alternative black frame analyzer is enabled.
    Allows users to disable frame-level boundary refinement.

    • refactor: reuse production parser in tests, document searchStart invariants

    Address PR review feedback:

    • TestBlackFrames.ParseFingerprintFile now delegates to FFmpegWrapper.ParseBlackFrame instead of duplicating the blackframe regex

    • FFmpegWrapper.ParseBlackFrame changed from private to internal (InternalsVisibleTo already configured)

    • Added XML docs to HasMinimumBlackFrameDensity explaining searchStart contract and monotonic-advance invariant

    • Added inline comments at each searchStart usage site in DetectCreditScenes (density gating, merge pass, transition-frame search)

    • fix: tighten BlackFrameAltAnalyzer boundary refinement
    • keep RefineCreditsBoundary enabled by default
    • probe boundary refinement using a dynamic minimum threshold:
      min(scene start frame percentage, sceneChange)
    • reject probe results at the preceding keyframe
    • reject probe results after the transition-selected scene start
    • add regression tests for probe threshold selection and refinement window validation
    • Reject rooted fingerprint file paths

    • Add boundary refinement checks and tests

    • Remove unused using directives

    Clean up unused using directives across the project to reduce compiler warnings and improve code readability. Many redundant System., Collections., Linq, Threading, IO and related usings were removed from analyzers, controllers, data models, DB context, managers, scheduled tasks and services. No logic or behavior changes intended.

    • Target ES2018 for web dashboard build (#750)
    • Target ES2018 for web dashboard bundle to ensure broader compatibility with older environments

    Co-authored-by: rlauuzo 46294892+rlauuzo@users.noreply.github.com

    • Use mutating reducer for cached shows

    Co-authored-by: rlauuzo 46294892+rlauuzo@users.noreply.github.com


    Co-authored-by: rlauuzo 46294892+rlauuzo@users.noreply.github.com

    • Fix credits analyzer ordering

    Co-authored-by: rlauuzo 46294892+rlauuzo@users.noreply.github.com

    • Revert "Fix credits analyzer ordering"

    This reverts commit c62e910bfb.

    • Revert "Target ES2018 for web dashboard build (#750)"

    This reverts commit 4f13cf7c73.

    • [skip actions] update copyright headers to SPDX format across all files

    • [skip actions] update copyright headers to SPDX format across all files

    • Release v1.10.11.18

    Downloads
  • v0.4.4 a688b409dd

    v0.4.4
    All checks were successful
    Release / Check if release needed (push) Successful in 5s
    Release / Release (push) Successful in 1m2s
    Stable

    Wuast94 released this 2026-04-12 01:01:53 +02:00 | 88 commits to pgsql since this release

    Bug Fixes

    • Db3

    • Db4

    • Db5

    Downloads
  • v0.4.3 93e1a7db85

    v0.4.3
    All checks were successful
    Release / Check if release needed (push) Successful in 4s
    Release / Release (push) Successful in 59s
    Stable

    Wuast94 released this 2026-04-12 00:34:29 +02:00 | 91 commits to pgsql since this release

    Bug Fixes

    • Db2
    Downloads
  • v0.4.2 ac23dc20bc

    v0.4.2
    All checks were successful
    Release / Check if release needed (push) Successful in 3s
    Release / Release (push) Successful in 1m2s
    Stable

    Wuast94 released this 2026-04-12 00:18:01 +02:00 | 92 commits to pgsql since this release

    Bug Fixes

    • Db
    Downloads