intro-skipper/IntroSkipper/Providers/SegmentProvider.cs
rlauuzo 6ccf002e51
Recaps and Previews Support (#357)
* Recaps and Previews Support

* Add draft UI of preview / recap edit

* remove intro/credit tasks

* Update configPage.html

* rename task

* Reorganize settings by relation

* More standardized formatting

* Some additional formatting

* fix a typo

* Update configPage.html

* Allow missing recap / prview data

* More risk to corrupt than benefit

* Update TimeStamps.cs

* Update PluginConfiguration.cs

* Update configPage.html

* Update PluginConfiguration.cs

* Add chapter regex to settings

* Move all UI into UI section

* Move ending seconds with similar

* Add default

* fixes

* Update SkipIntroController.cs

* Autoskip all segments

* Check if adjacent segment

* Update AutoSkip.cs

* Update AutoSkip.cs

* Settings apply to all segment types

* Update SegmentProvider

* Update configPage.html

Whoops

* Update Plugin.cs

* Update AutoSkip.cs

* Let’s call it missing instead

* Update BaseItemAnalyzerTask.cs

* Update BaseItemAnalyzerTask.cs

* Update BaseItemAnalyzerTask.cs

* Move "select" all below list

* Clarify button wording

* Update configPage.html

* Nope, long client list will hide it

* Simplify wording

* Update QueuedEpisode.cs

* fix unit test for ffmpeg7

* Add migration

* Restore DataContract

* update

* Update configPage.html

* remove analyzed status

* Update AutoSkip.cs

* Update configPage.html typo

* Store analyzed items in seasoninfo

* Update VisualizationController.cs

* update

* Update IntroSkipperDbContext.cs

* Add preview / recap delete

* This keeps changing itself

* Update SkipIntroController.cs

* Rather add it to be removed

---------

Co-authored-by: rlauu <46294892+rlauu@users.noreply.github.com>
Co-authored-by: TwistedUmbrellaX <1173913+AbandonedCart@users.noreply.github.com>
Co-authored-by: Kilian von Pflugk <github@jumoog.io>
2024-11-21 09:42:55 -05:00

91 lines
3.4 KiB
C#

// Copyright (C) 2024 Intro-Skipper contributors <intro-skipper.org>
// SPDX-License-Identifier: GPL-3.0-only.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using IntroSkipper.Data;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Model;
using MediaBrowser.Model.MediaSegments;
namespace IntroSkipper.Providers
{
/// <summary>
/// Introskipper media segment provider.
/// </summary>
public class SegmentProvider : IMediaSegmentProvider
{
/// <inheritdoc/>
public string Name => Plugin.Instance!.Name;
/// <inheritdoc/>
public Task<IReadOnlyList<MediaSegmentDto>> GetMediaSegments(MediaSegmentGenerationRequest request, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(request);
ArgumentNullException.ThrowIfNull(Plugin.Instance);
var segments = new List<MediaSegmentDto>();
var remainingTicks = Plugin.Instance.Configuration.RemainingSecondsOfIntro * TimeSpan.TicksPerSecond;
var itemSegments = Plugin.Instance.GetTimestamps(request.ItemId);
var runTimeTicks = Plugin.Instance.GetItem(request.ItemId)?.RunTimeTicks ?? 0;
// Define mappings between AnalysisMode and MediaSegmentType
var segmentMappings = new List<(AnalysisMode Mode, MediaSegmentType Type)>
{
(AnalysisMode.Introduction, MediaSegmentType.Intro),
(AnalysisMode.Recap, MediaSegmentType.Recap),
(AnalysisMode.Preview, MediaSegmentType.Preview),
(AnalysisMode.Credits, MediaSegmentType.Outro)
};
foreach (var (mode, type) in segmentMappings)
{
if (itemSegments.TryGetValue(mode, out var segment) && segment.Valid)
{
long startTicks = (long)(segment.Start * TimeSpan.TicksPerSecond);
long endTicks = CalculateEndTicks(mode, segment, runTimeTicks, remainingTicks);
segments.Add(new MediaSegmentDto
{
StartTicks = startTicks,
EndTicks = endTicks,
ItemId = request.ItemId,
Type = type
});
}
}
return Task.FromResult<IReadOnlyList<MediaSegmentDto>>(segments);
}
/// <summary>
/// Calculates the end ticks based on the segment type and runtime.
/// </summary>
private static long CalculateEndTicks(AnalysisMode mode, Segment segment, long runTimeTicks, long remainingTicks)
{
long endTicks = (long)(segment.End * TimeSpan.TicksPerSecond);
if (mode is AnalysisMode.Preview or AnalysisMode.Credits)
{
if (runTimeTicks > 0 && runTimeTicks < endTicks + TimeSpan.TicksPerSecond)
{
return Math.Max(runTimeTicks, endTicks);
}
return endTicks - remainingTicks;
}
return endTicks - remainingTicks;
}
/// <inheritdoc/>
public ValueTask<bool> Supports(BaseItem item) => ValueTask.FromResult(item is Episode or Movie);
}
}