6ccf002e51
* 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>
91 lines
3.4 KiB
C#
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);
|
|
}
|
|
}
|