From 88003edb219464af75796b7f1469cadc56e76860 Mon Sep 17 00:00:00 2001 From: Kilian von Pflugk Date: Sat, 31 Aug 2024 16:48:31 +0000 Subject: [PATCH] automatic skip only for Apps without Skip Button (#208) --- .../TestWarnings.cs | 16 +++++- .../AutoSkip.cs | 11 ++++ .../AutoSkipCredits.cs | 11 ++++ .../Configuration/configPage.html | 10 ++-- .../Data/Intro.cs | 39 -------------- .../Data/IntroWithMetadata.cs | 40 +++++++++++++++ .../Data/PluginWarning.cs | 34 ------------- .../Data/TimeRange.cs | 49 ------------------ .../Data/TimeRangeHelpers.cs | 51 +++++++++++++++++++ .../Data/WarningManager.cs | 45 ++++++++++++++++ .../GlobalSuppressions.cs | 10 ---- 11 files changed, 177 insertions(+), 139 deletions(-) create mode 100644 ConfusedPolarBear.Plugin.IntroSkipper/Data/IntroWithMetadata.cs create mode 100644 ConfusedPolarBear.Plugin.IntroSkipper/Data/TimeRangeHelpers.cs create mode 100644 ConfusedPolarBear.Plugin.IntroSkipper/Data/WarningManager.cs delete mode 100644 ConfusedPolarBear.Plugin.IntroSkipper/GlobalSuppressions.cs diff --git a/ConfusedPolarBear.Plugin.IntroSkipper.Tests/TestWarnings.cs b/ConfusedPolarBear.Plugin.IntroSkipper.Tests/TestWarnings.cs index ac3f246..278de86 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper.Tests/TestWarnings.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper.Tests/TestWarnings.cs @@ -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)); + } } diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/AutoSkip.cs b/ConfusedPolarBear.Plugin.IntroSkipper/AutoSkip.cs index 930c194..13a3b6c 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/AutoSkip.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/AutoSkip.cs @@ -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; diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/AutoSkipCredits.cs b/ConfusedPolarBear.Plugin.IntroSkipper/AutoSkipCredits.cs index 0a5db9b..1c04365 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/AutoSkipCredits.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/AutoSkipCredits.cs @@ -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; diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html index 0e35aa4..b3db713 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/configPage.html @@ -347,9 +347,8 @@
- If checked, intros will be automatically skipped. If you access Jellyfin through a - reverse proxy, it must be configured to proxy web - sockets.
+ 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.
@@ -383,9 +382,8 @@
- If checked, credits will be automatically skipped. If you access Jellyfin through a - reverse proxy, it must be configured to proxy web - sockets.
+ 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.
diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Data/Intro.cs b/ConfusedPolarBear.Plugin.IntroSkipper/Data/Intro.cs index b1761e5..9c8985f 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/Data/Intro.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Data/Intro.cs @@ -106,42 +106,3 @@ public class Intro return string.Format(CultureInfo.InvariantCulture, "{0} {1} {2}", start, end, (int)action); } } - -/// -/// An Intro class with episode metadata. Only used in end to end testing programs. -/// -public class IntroWithMetadata : Intro -{ - /// - /// Initializes a new instance of the class. - /// - /// Series name. - /// Season number. - /// Episode title. - /// Intro timestamps. - 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; - } - - /// - /// Gets or sets the series name of the TV episode associated with this intro. - /// - public string Series { get; set; } - - /// - /// Gets or sets the season number of the TV episode associated with this intro. - /// - public int Season { get; set; } - - /// - /// Gets or sets the title of the TV episode associated with this intro. - /// - public string Title { get; set; } -} diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Data/IntroWithMetadata.cs b/ConfusedPolarBear.Plugin.IntroSkipper/Data/IntroWithMetadata.cs new file mode 100644 index 0000000..efafa68 --- /dev/null +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Data/IntroWithMetadata.cs @@ -0,0 +1,40 @@ +namespace ConfusedPolarBear.Plugin.IntroSkipper; + +/// +/// An Intro class with episode metadata. Only used in end to end testing programs. +/// +public class IntroWithMetadata : Intro +{ + /// + /// Initializes a new instance of the class. + /// + /// Series name. + /// Season number. + /// Episode title. + /// Intro timestamps. + 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; + } + + /// + /// Gets or sets the series name of the TV episode associated with this intro. + /// + public string Series { get; set; } + + /// + /// Gets or sets the season number of the TV episode associated with this intro. + /// + public int Season { get; set; } + + /// + /// Gets or sets the title of the TV episode associated with this intro. + /// + public string Title { get; set; } +} diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Data/PluginWarning.cs b/ConfusedPolarBear.Plugin.IntroSkipper/Data/PluginWarning.cs index 4103c77..325514e 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/Data/PluginWarning.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Data/PluginWarning.cs @@ -28,37 +28,3 @@ public enum PluginWarning /// IncompatibleFFmpegBuild = 4, } - -/// -/// Warning manager. -/// -public static class WarningManager -{ - private static PluginWarning warnings; - - /// - /// Set warning. - /// - /// Warning. - public static void SetFlag(PluginWarning warning) - { - warnings |= warning; - } - - /// - /// Clear warnings. - /// - public static void Clear() - { - warnings = PluginWarning.None; - } - - /// - /// Get warnings. - /// - /// Warnings. - public static string GetWarnings() - { - return warnings.ToString(); - } -} diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Data/TimeRange.cs b/ConfusedPolarBear.Plugin.IntroSkipper/Data/TimeRange.cs index 451df2f..6223891 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/Data/TimeRange.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Data/TimeRange.cs @@ -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 - -/// -/// Time range helpers. -/// -public static class TimeRangeHelpers -{ - /// - /// Finds the longest contiguous time range. - /// - /// Sorted timestamps to search. - /// Maximum distance permitted between contiguous timestamps. - /// The longest contiguous time range (if one was found), or null (if none was found). - public static TimeRange? FindContiguous(double[] times, double maximumDistance) - { - if (times.Length == 0) - { - return null; - } - - Array.Sort(times); - - var ranges = new List(); - 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; - } -} diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Data/TimeRangeHelpers.cs b/ConfusedPolarBear.Plugin.IntroSkipper/Data/TimeRangeHelpers.cs new file mode 100644 index 0000000..1ab8196 --- /dev/null +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Data/TimeRangeHelpers.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; + +namespace ConfusedPolarBear.Plugin.IntroSkipper; +#pragma warning restore CA1036 + +/// +/// Time range helpers. +/// +public static class TimeRangeHelpers +{ + /// + /// Finds the longest contiguous time range. + /// + /// Sorted timestamps to search. + /// Maximum distance permitted between contiguous timestamps. + /// The longest contiguous time range (if one was found), or null (if none was found). + public static TimeRange? FindContiguous(double[] times, double maximumDistance) + { + if (times.Length == 0) + { + return null; + } + + Array.Sort(times); + + var ranges = new List(); + 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; + } +} diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Data/WarningManager.cs b/ConfusedPolarBear.Plugin.IntroSkipper/Data/WarningManager.cs new file mode 100644 index 0000000..1f01a7a --- /dev/null +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Data/WarningManager.cs @@ -0,0 +1,45 @@ +namespace ConfusedPolarBear.Plugin.IntroSkipper; + +/// +/// Warning manager. +/// +public static class WarningManager +{ + private static PluginWarning warnings; + + /// + /// Set warning. + /// + /// Warning. + public static void SetFlag(PluginWarning warning) + { + warnings |= warning; + } + + /// + /// Clear warnings. + /// + public static void Clear() + { + warnings = PluginWarning.None; + } + + /// + /// Get warnings. + /// + /// Warnings. + public static string GetWarnings() + { + return warnings.ToString(); + } + + /// + /// Check if a specific warning flag is set. + /// + /// Warning flag to check. + /// True if the flag is set, otherwise false. + public static bool HasFlag(PluginWarning warning) + { + return (warnings & warning) == warning; + } +} diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/GlobalSuppressions.cs b/ConfusedPolarBear.Plugin.IntroSkipper/GlobalSuppressions.cs deleted file mode 100644 index 2967ca7..0000000 --- a/ConfusedPolarBear.Plugin.IntroSkipper/GlobalSuppressions.cs +++ /dev/null @@ -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")]