automatic skip only for Apps without Skip Button (#208)
This commit is contained in:
parent
1a13ef1a37
commit
88003edb21
@ -17,6 +17,7 @@ public class TestFlags
|
||||
WarningManager.Clear();
|
||||
WarningManager.SetFlag(PluginWarning.UnableToAddSkipButton);
|
||||
Assert.Equal("UnableToAddSkipButton", WarningManager.GetWarnings());
|
||||
Assert.True(WarningManager.HasFlag(PluginWarning.UnableToAddSkipButton));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -26,9 +27,22 @@ public class TestFlags
|
||||
WarningManager.SetFlag(PluginWarning.UnableToAddSkipButton);
|
||||
WarningManager.SetFlag(PluginWarning.InvalidChromaprintFingerprint);
|
||||
WarningManager.SetFlag(PluginWarning.InvalidChromaprintFingerprint);
|
||||
|
||||
Assert.True(WarningManager.HasFlag(PluginWarning.UnableToAddSkipButton) && WarningManager.HasFlag(PluginWarning.InvalidChromaprintFingerprint));
|
||||
Assert.Equal(
|
||||
"UnableToAddSkipButton, InvalidChromaprintFingerprint",
|
||||
WarningManager.GetWarnings());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestHasFlag()
|
||||
{
|
||||
WarningManager.Clear();
|
||||
Assert.True(WarningManager.HasFlag(PluginWarning.None));
|
||||
Assert.False(WarningManager.HasFlag(PluginWarning.UnableToAddSkipButton) && WarningManager.HasFlag(PluginWarning.InvalidChromaprintFingerprint));
|
||||
WarningManager.SetFlag(PluginWarning.UnableToAddSkipButton);
|
||||
WarningManager.SetFlag(PluginWarning.InvalidChromaprintFingerprint);
|
||||
Assert.True(WarningManager.HasFlag(PluginWarning.UnableToAddSkipButton) && WarningManager.HasFlag(PluginWarning.InvalidChromaprintFingerprint));
|
||||
Assert.False(WarningManager.HasFlag(PluginWarning.IncompatibleFFmpegBuild));
|
||||
Assert.True(WarningManager.HasFlag(PluginWarning.None));
|
||||
}
|
||||
}
|
||||
|
@ -112,6 +112,17 @@ public class AutoSkip : IHostedService, IDisposable
|
||||
{
|
||||
foreach (var session in _sessionManager.Sessions)
|
||||
{
|
||||
if (WarningManager.HasFlag(PluginWarning.UnableToAddSkipButton))
|
||||
{
|
||||
_logger.LogInformation("using autoskip to skip the intro because the injection of the skip button failed");
|
||||
}
|
||||
|
||||
// only need for official Android TV App and jellyfin-kodi
|
||||
else if (session.Client != "Android TV" || session.Client != "Kodi")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var deviceId = session.DeviceId;
|
||||
var itemId = session.NowPlayingItem.Id;
|
||||
var position = session.PlayState.PositionTicks / TimeSpan.TicksPerSecond;
|
||||
|
@ -112,6 +112,17 @@ public class AutoSkipCredits : IHostedService, IDisposable
|
||||
{
|
||||
foreach (var session in _sessionManager.Sessions)
|
||||
{
|
||||
if (WarningManager.HasFlag(PluginWarning.UnableToAddSkipButton))
|
||||
{
|
||||
_logger.LogInformation("using autoskip to skip the credits because the injection of the skip button failed");
|
||||
}
|
||||
|
||||
// only need for official Android TV App and jellyfin-kodi
|
||||
else if (session.Client != "Android TV" || session.Client != "Kodi")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var deviceId = session.DeviceId;
|
||||
var itemId = session.NowPlayingItem.Id;
|
||||
var position = session.PlayState.PositionTicks / TimeSpan.TicksPerSecond;
|
||||
|
@ -347,9 +347,8 @@
|
||||
</label>
|
||||
|
||||
<div class="fieldDescription">
|
||||
If checked, intros will be automatically skipped. If you access Jellyfin through a
|
||||
reverse proxy, it must be configured to proxy web
|
||||
sockets.<br />
|
||||
If checked, credits will be automatically skipped for Apps without Skip Button.
|
||||
If you access Jellyfin through a reverse proxy, it must be configured to proxy websockets.<br />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -383,9 +382,8 @@
|
||||
</label>
|
||||
|
||||
<div class="fieldDescription">
|
||||
If checked, credits will be automatically skipped. If you access Jellyfin through a
|
||||
reverse proxy, it must be configured to proxy web
|
||||
sockets.<br />
|
||||
If checked, credits will be automatically skipped for Apps without Skip Button.
|
||||
If you access Jellyfin through a reverse proxy, it must be configured to proxy websockets.<br />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -106,42 +106,3 @@ public class Intro
|
||||
return string.Format(CultureInfo.InvariantCulture, "{0} {1} {2}", start, end, (int)action);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An Intro class with episode metadata. Only used in end to end testing programs.
|
||||
/// </summary>
|
||||
public class IntroWithMetadata : Intro
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="IntroWithMetadata"/> class.
|
||||
/// </summary>
|
||||
/// <param name="series">Series name.</param>
|
||||
/// <param name="season">Season number.</param>
|
||||
/// <param name="title">Episode title.</param>
|
||||
/// <param name="intro">Intro timestamps.</param>
|
||||
public IntroWithMetadata(string series, int season, string title, Intro intro)
|
||||
{
|
||||
Series = series;
|
||||
Season = season;
|
||||
Title = title;
|
||||
|
||||
EpisodeId = intro.EpisodeId;
|
||||
IntroStart = intro.IntroStart;
|
||||
IntroEnd = intro.IntroEnd;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the series name of the TV episode associated with this intro.
|
||||
/// </summary>
|
||||
public string Series { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the season number of the TV episode associated with this intro.
|
||||
/// </summary>
|
||||
public int Season { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the title of the TV episode associated with this intro.
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
}
|
||||
|
@ -0,0 +1,40 @@
|
||||
namespace ConfusedPolarBear.Plugin.IntroSkipper;
|
||||
|
||||
/// <summary>
|
||||
/// An Intro class with episode metadata. Only used in end to end testing programs.
|
||||
/// </summary>
|
||||
public class IntroWithMetadata : Intro
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="IntroWithMetadata"/> class.
|
||||
/// </summary>
|
||||
/// <param name="series">Series name.</param>
|
||||
/// <param name="season">Season number.</param>
|
||||
/// <param name="title">Episode title.</param>
|
||||
/// <param name="intro">Intro timestamps.</param>
|
||||
public IntroWithMetadata(string series, int season, string title, Intro intro)
|
||||
{
|
||||
Series = series;
|
||||
Season = season;
|
||||
Title = title;
|
||||
|
||||
EpisodeId = intro.EpisodeId;
|
||||
IntroStart = intro.IntroStart;
|
||||
IntroEnd = intro.IntroEnd;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the series name of the TV episode associated with this intro.
|
||||
/// </summary>
|
||||
public string Series { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the season number of the TV episode associated with this intro.
|
||||
/// </summary>
|
||||
public int Season { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the title of the TV episode associated with this intro.
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
}
|
@ -28,37 +28,3 @@ public enum PluginWarning
|
||||
/// </summary>
|
||||
IncompatibleFFmpegBuild = 4,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Warning manager.
|
||||
/// </summary>
|
||||
public static class WarningManager
|
||||
{
|
||||
private static PluginWarning warnings;
|
||||
|
||||
/// <summary>
|
||||
/// Set warning.
|
||||
/// </summary>
|
||||
/// <param name="warning">Warning.</param>
|
||||
public static void SetFlag(PluginWarning warning)
|
||||
{
|
||||
warnings |= warning;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear warnings.
|
||||
/// </summary>
|
||||
public static void Clear()
|
||||
{
|
||||
warnings = PluginWarning.None;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get warnings.
|
||||
/// </summary>
|
||||
/// <returns>Warnings.</returns>
|
||||
public static string GetWarnings()
|
||||
{
|
||||
return warnings.ToString();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ConfusedPolarBear.Plugin.IntroSkipper;
|
||||
|
||||
@ -82,51 +81,3 @@ public class TimeRange : IComparable
|
||||
(Start < tr.End && tr.End < End);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning restore CA1036
|
||||
|
||||
/// <summary>
|
||||
/// Time range helpers.
|
||||
/// </summary>
|
||||
public static class TimeRangeHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Finds the longest contiguous time range.
|
||||
/// </summary>
|
||||
/// <param name="times">Sorted timestamps to search.</param>
|
||||
/// <param name="maximumDistance">Maximum distance permitted between contiguous timestamps.</param>
|
||||
/// <returns>The longest contiguous time range (if one was found), or null (if none was found).</returns>
|
||||
public static TimeRange? FindContiguous(double[] times, double maximumDistance)
|
||||
{
|
||||
if (times.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Array.Sort(times);
|
||||
|
||||
var ranges = new List<TimeRange>();
|
||||
var currentRange = new TimeRange(times[0], times[0]);
|
||||
|
||||
// For all provided timestamps, check if it is contiguous with its neighbor.
|
||||
for (var i = 0; i < times.Length - 1; i++)
|
||||
{
|
||||
var current = times[i];
|
||||
var next = times[i + 1];
|
||||
|
||||
if (next - current <= maximumDistance)
|
||||
{
|
||||
currentRange.End = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
ranges.Add(new TimeRange(currentRange));
|
||||
currentRange = new TimeRange(next, next);
|
||||
}
|
||||
|
||||
// Find and return the longest contiguous range.
|
||||
ranges.Sort();
|
||||
|
||||
return (ranges.Count > 0) ? ranges[0] : null;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ConfusedPolarBear.Plugin.IntroSkipper;
|
||||
#pragma warning restore CA1036
|
||||
|
||||
/// <summary>
|
||||
/// Time range helpers.
|
||||
/// </summary>
|
||||
public static class TimeRangeHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Finds the longest contiguous time range.
|
||||
/// </summary>
|
||||
/// <param name="times">Sorted timestamps to search.</param>
|
||||
/// <param name="maximumDistance">Maximum distance permitted between contiguous timestamps.</param>
|
||||
/// <returns>The longest contiguous time range (if one was found), or null (if none was found).</returns>
|
||||
public static TimeRange? FindContiguous(double[] times, double maximumDistance)
|
||||
{
|
||||
if (times.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Array.Sort(times);
|
||||
|
||||
var ranges = new List<TimeRange>();
|
||||
var currentRange = new TimeRange(times[0], times[0]);
|
||||
|
||||
// For all provided timestamps, check if it is contiguous with its neighbor.
|
||||
for (var i = 0; i < times.Length - 1; i++)
|
||||
{
|
||||
var current = times[i];
|
||||
var next = times[i + 1];
|
||||
|
||||
if (next - current <= maximumDistance)
|
||||
{
|
||||
currentRange.End = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
ranges.Add(new TimeRange(currentRange));
|
||||
currentRange = new TimeRange(next, next);
|
||||
}
|
||||
|
||||
// Find and return the longest contiguous range.
|
||||
ranges.Sort();
|
||||
|
||||
return (ranges.Count > 0) ? ranges[0] : null;
|
||||
}
|
||||
}
|
45
ConfusedPolarBear.Plugin.IntroSkipper/Data/WarningManager.cs
Normal file
45
ConfusedPolarBear.Plugin.IntroSkipper/Data/WarningManager.cs
Normal file
@ -0,0 +1,45 @@
|
||||
namespace ConfusedPolarBear.Plugin.IntroSkipper;
|
||||
|
||||
/// <summary>
|
||||
/// Warning manager.
|
||||
/// </summary>
|
||||
public static class WarningManager
|
||||
{
|
||||
private static PluginWarning warnings;
|
||||
|
||||
/// <summary>
|
||||
/// Set warning.
|
||||
/// </summary>
|
||||
/// <param name="warning">Warning.</param>
|
||||
public static void SetFlag(PluginWarning warning)
|
||||
{
|
||||
warnings |= warning;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear warnings.
|
||||
/// </summary>
|
||||
public static void Clear()
|
||||
{
|
||||
warnings = PluginWarning.None;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get warnings.
|
||||
/// </summary>
|
||||
/// <returns>Warnings.</returns>
|
||||
public static string GetWarnings()
|
||||
{
|
||||
return warnings.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if a specific warning flag is set.
|
||||
/// </summary>
|
||||
/// <param name="warning">Warning flag to check.</param>
|
||||
/// <returns>True if the flag is set, otherwise false.</returns>
|
||||
public static bool HasFlag(PluginWarning warning)
|
||||
{
|
||||
return (warnings & warning) == warning;
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
// This file is used by Code Analysis to maintain SuppressMessage
|
||||
// attributes that are applied to this project.
|
||||
// Project-level suppressions either have no target or are given
|
||||
// a specific target and scoped to a namespace, type, member, etc.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1649:File name should match first type name", Justification = "Legacy TODO", Scope = "type", Target = "~T:ConfusedPolarBear.Plugin.IntroSkipper.WarningManager")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Legacy TODO", Scope = "type", Target = "~T:ConfusedPolarBear.Plugin.IntroSkipper.IntroWithMetadata")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Legacy TODO", Scope = "type", Target = "~T:ConfusedPolarBear.Plugin.IntroSkipper.TimeRangeHelpers")]
|
Loading…
x
Reference in New Issue
Block a user