select autoskip clients (#277)
Co-authored-by: rlauu <46294892+rlauu@users.noreply.github.com>
This commit is contained in:
parent
899d5e1914
commit
d428efb1f2
@ -1,10 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using ConfusedPolarBear.Plugin.IntroSkipper.Configuration;
|
||||
using ConfusedPolarBear.Plugin.IntroSkipper.Data;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Session;
|
||||
@ -21,32 +21,25 @@ namespace ConfusedPolarBear.Plugin.IntroSkipper;
|
||||
/// Automatically skip past introduction sequences.
|
||||
/// Commands clients to seek to the end of the intro as soon as they start playing it.
|
||||
/// </summary>
|
||||
public class AutoSkip : IHostedService, IDisposable
|
||||
/// <remarks>
|
||||
/// Initializes a new instance of the <see cref="AutoSkip"/> class.
|
||||
/// </remarks>
|
||||
/// <param name="userDataManager">User data manager.</param>
|
||||
/// <param name="sessionManager">Session manager.</param>
|
||||
/// <param name="logger">Logger.</param>
|
||||
public class AutoSkip(
|
||||
IUserDataManager userDataManager,
|
||||
ISessionManager sessionManager,
|
||||
ILogger<AutoSkip> logger) : IHostedService, IDisposable
|
||||
{
|
||||
private readonly object _sentSeekCommandLock = new();
|
||||
|
||||
private ILogger<AutoSkip> _logger;
|
||||
private IUserDataManager _userDataManager;
|
||||
private ISessionManager _sessionManager;
|
||||
private ILogger<AutoSkip> _logger = logger;
|
||||
private IUserDataManager _userDataManager = userDataManager;
|
||||
private ISessionManager _sessionManager = sessionManager;
|
||||
private Timer _playbackTimer = new(1000);
|
||||
private Dictionary<string, bool> _sentSeekCommand;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AutoSkip"/> class.
|
||||
/// </summary>
|
||||
/// <param name="userDataManager">User data manager.</param>
|
||||
/// <param name="sessionManager">Session manager.</param>
|
||||
/// <param name="logger">Logger.</param>
|
||||
public AutoSkip(
|
||||
IUserDataManager userDataManager,
|
||||
ISessionManager sessionManager,
|
||||
ILogger<AutoSkip> logger)
|
||||
{
|
||||
_userDataManager = userDataManager;
|
||||
_sessionManager = sessionManager;
|
||||
_logger = logger;
|
||||
_sentSeekCommand = new Dictionary<string, bool>();
|
||||
}
|
||||
private Dictionary<string, bool> _sentSeekCommand = [];
|
||||
private HashSet<string> _clientList = [];
|
||||
|
||||
private void AutoSkipChanged(object? sender, BasePluginConfiguration e)
|
||||
{
|
||||
@ -54,6 +47,7 @@ public class AutoSkip : IHostedService, IDisposable
|
||||
var newState = configuration.AutoSkip;
|
||||
_logger.LogDebug("Setting playback timer enabled to {NewState}", newState);
|
||||
_playbackTimer.Enabled = newState;
|
||||
_clientList = [.. configuration.ClientList.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)];
|
||||
}
|
||||
|
||||
private void UserDataManager_UserDataSaved(object? sender, UserDataSaveEventArgs e)
|
||||
@ -111,19 +105,8 @@ public class AutoSkip : IHostedService, IDisposable
|
||||
|
||||
private void PlaybackTimer_Elapsed(object? sender, ElapsedEventArgs e)
|
||||
{
|
||||
foreach (var session in _sessionManager.Sessions)
|
||||
foreach (var session in _sessionManager.Sessions.Where(s => _clientList.Contains(s.Client, StringComparer.OrdinalIgnoreCase)))
|
||||
{
|
||||
if (WarningManager.HasFlag(PluginWarning.UnableToAddSkipButton))
|
||||
{
|
||||
_logger.LogTrace("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;
|
||||
|
@ -1,10 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using ConfusedPolarBear.Plugin.IntroSkipper.Configuration;
|
||||
using ConfusedPolarBear.Plugin.IntroSkipper.Data;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Session;
|
||||
@ -21,32 +21,25 @@ namespace ConfusedPolarBear.Plugin.IntroSkipper;
|
||||
/// Automatically skip past credit sequences.
|
||||
/// Commands clients to seek to the end of the credits as soon as they start playing it.
|
||||
/// </summary>
|
||||
public class AutoSkipCredits : IHostedService, IDisposable
|
||||
/// <remarks>
|
||||
/// Initializes a new instance of the <see cref="AutoSkipCredits"/> class.
|
||||
/// </remarks>
|
||||
/// <param name="userDataManager">User data manager.</param>
|
||||
/// <param name="sessionManager">Session manager.</param>
|
||||
/// <param name="logger">Logger.</param>
|
||||
public class AutoSkipCredits(
|
||||
IUserDataManager userDataManager,
|
||||
ISessionManager sessionManager,
|
||||
ILogger<AutoSkipCredits> logger) : IHostedService, IDisposable
|
||||
{
|
||||
private readonly object _sentSeekCommandLock = new();
|
||||
|
||||
private ILogger<AutoSkipCredits> _logger;
|
||||
private IUserDataManager _userDataManager;
|
||||
private ISessionManager _sessionManager;
|
||||
private ILogger<AutoSkipCredits> _logger = logger;
|
||||
private IUserDataManager _userDataManager = userDataManager;
|
||||
private ISessionManager _sessionManager = sessionManager;
|
||||
private Timer _playbackTimer = new(1000);
|
||||
private Dictionary<string, bool> _sentSeekCommand;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AutoSkipCredits"/> class.
|
||||
/// </summary>
|
||||
/// <param name="userDataManager">User data manager.</param>
|
||||
/// <param name="sessionManager">Session manager.</param>
|
||||
/// <param name="logger">Logger.</param>
|
||||
public AutoSkipCredits(
|
||||
IUserDataManager userDataManager,
|
||||
ISessionManager sessionManager,
|
||||
ILogger<AutoSkipCredits> logger)
|
||||
{
|
||||
_userDataManager = userDataManager;
|
||||
_sessionManager = sessionManager;
|
||||
_logger = logger;
|
||||
_sentSeekCommand = new Dictionary<string, bool>();
|
||||
}
|
||||
private Dictionary<string, bool> _sentSeekCommand = [];
|
||||
private HashSet<string> _clientList = [];
|
||||
|
||||
private void AutoSkipCreditChanged(object? sender, BasePluginConfiguration e)
|
||||
{
|
||||
@ -54,6 +47,7 @@ public class AutoSkipCredits : IHostedService, IDisposable
|
||||
var newState = configuration.AutoSkipCredits;
|
||||
_logger.LogDebug("Setting playback timer enabled to {NewState}", newState);
|
||||
_playbackTimer.Enabled = newState;
|
||||
_clientList = [.. configuration.ClientList.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)];
|
||||
}
|
||||
|
||||
private void UserDataManager_UserDataSaved(object? sender, UserDataSaveEventArgs e)
|
||||
@ -111,19 +105,8 @@ public class AutoSkipCredits : IHostedService, IDisposable
|
||||
|
||||
private void PlaybackTimer_Elapsed(object? sender, ElapsedEventArgs e)
|
||||
{
|
||||
foreach (var session in _sessionManager.Sessions)
|
||||
foreach (var session in _sessionManager.Sessions.Where(s => _clientList.Contains(s.Client, StringComparer.OrdinalIgnoreCase)))
|
||||
{
|
||||
if (WarningManager.HasFlag(PluginWarning.UnableToAddSkipButton))
|
||||
{
|
||||
_logger.LogTrace("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;
|
||||
|
@ -29,6 +29,11 @@ public class PluginConfiguration : BasePluginConfiguration
|
||||
/// </summary>
|
||||
public string SelectedLibraries { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the list of client to auto skip for.
|
||||
/// </summary>
|
||||
public string ClientList { get; set; } = "Android TV, Kodi";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to scan for intros during a scheduled task.
|
||||
/// </summary>
|
||||
|
@ -398,6 +398,14 @@
|
||||
<br />
|
||||
</div>
|
||||
|
||||
<details id="AutoSkipClientList" style="padding-bottom: 1em;">
|
||||
<summary>Auto Skip Client List</summary>
|
||||
<br />
|
||||
<div class="checkboxList paperList" style="padding:.5em 1em"></div>
|
||||
<label class="inputLabel" for="ClientList"></label>
|
||||
<input id="ClientList" type="hidden" is="emby-input" />
|
||||
</details>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label class="emby-checkbox-label">
|
||||
<input id="SkipButtonVisible" type="checkbox" is="emby-checkbox" />
|
||||
@ -699,6 +707,7 @@
|
||||
// analysis
|
||||
"MaxParallelism",
|
||||
"SelectedLibraries",
|
||||
"ClientList",
|
||||
"AnalysisPercent",
|
||||
"AnalysisLengthLimit",
|
||||
"MinimumIntroDuration",
|
||||
@ -758,12 +767,13 @@
|
||||
var autoSkip = document.querySelector("input#AutoSkip");
|
||||
var skipFirstEpisode = document.querySelector("div#divSkipFirstEpisode");
|
||||
var secondsOfIntroStartToPlay = document.querySelector("div#divSecondsOfIntroStartToPlay");
|
||||
var autoSkipClientList = document.getElementById("AutoSkipClientList");
|
||||
var secondsOfCreditsStartToPlay = document.querySelector("div#divSecondsOfCreditsStartToPlay");
|
||||
var autoSkipNotificationText = document.querySelector("div#divAutoSkipNotificationText");
|
||||
var autoSkipCredits = document.querySelector("input#AutoSkipCredits");
|
||||
var autoSkipCreditsNotificationText = document.querySelector("div#divAutoSkipCreditsNotificationText");
|
||||
|
||||
async function autoSkipChanged() {
|
||||
function autoSkipChanged() {
|
||||
if (autoSkip.checked) {
|
||||
skipFirstEpisode.style.display = 'unset';
|
||||
autoSkipNotificationText.style.display = 'unset';
|
||||
@ -773,11 +783,12 @@
|
||||
autoSkipNotificationText.style.display = 'none';
|
||||
secondsOfIntroStartToPlay.style.display = 'none';
|
||||
}
|
||||
clientListVisible();
|
||||
}
|
||||
|
||||
autoSkip.addEventListener("change", autoSkipChanged);
|
||||
|
||||
async function autoSkipCreditsChanged() {
|
||||
function autoSkipCreditsChanged() {
|
||||
if (autoSkipCredits.checked) {
|
||||
autoSkipCreditsNotificationText.style.display = 'unset';
|
||||
secondsOfCreditsStartToPlay.style.display = 'unset';
|
||||
@ -785,10 +796,57 @@
|
||||
autoSkipCreditsNotificationText.style.display = 'none';
|
||||
secondsOfCreditsStartToPlay.style.display = 'none';
|
||||
}
|
||||
clientListVisible();
|
||||
}
|
||||
|
||||
autoSkipCredits.addEventListener("change", autoSkipCreditsChanged);
|
||||
|
||||
function clientListVisible() {
|
||||
if (autoSkip.checked || autoSkipCredits.checked) {
|
||||
autoSkipClientList.style.display = 'unset';
|
||||
autoSkipClientList.style.width = '100%';
|
||||
} else {
|
||||
autoSkipClientList.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
async function getDeviceList() {
|
||||
const response = await getJson("Devices");
|
||||
const devices = [...new Set(response.Items.map(item => item.AppName))];
|
||||
return devices;
|
||||
}
|
||||
|
||||
function updateClientList() {
|
||||
document.getElementById('ClientList').value = Array.from(
|
||||
autoSkipClientList.querySelectorAll('input[type="checkbox"]:checked')
|
||||
).map(checkbox => checkbox.nextElementSibling.textContent).join(', ');
|
||||
}
|
||||
|
||||
async function generateAutoSkipClientList() {
|
||||
var devices = await getDeviceList();
|
||||
var deviceList = document.getElementById('ClientList').value;
|
||||
var checkedDevices = deviceList ? deviceList.split(', ') : [];
|
||||
|
||||
var checkboxListHtml = devices.map(function(device) {
|
||||
var id = 'chk' + device.replace(/\s+/g, '');
|
||||
var isChecked = checkedDevices.includes(device) ? 'checked' : '';
|
||||
return '<label class="emby-checkbox-label">' +
|
||||
'<input type="checkbox" is="emby-checkbox" id="' + id + '" ' + isChecked + '>' +
|
||||
'<span class="checkboxLabel">' + device + '</span>' +
|
||||
'</label>';
|
||||
}).join('');
|
||||
|
||||
var checkboxList = autoSkipClientList.querySelector('.checkboxList.paperList');
|
||||
checkboxList.innerHTML = checkboxListHtml;
|
||||
|
||||
var checkboxes = checkboxList.querySelectorAll('input[type="checkbox"]');
|
||||
for (var i = 0; i < checkboxes.length; i++) {
|
||||
checkboxes[i].addEventListener('change', function() {
|
||||
updateClientList();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var persistSkip = document.querySelector("input#PersistSkipButton");
|
||||
var showAdjustment = document.querySelector("div#divShowPromptAdjustment");
|
||||
var hideAdjustment = document.querySelector("div#divHidePromptAdjustment");
|
||||
@ -976,7 +1034,6 @@
|
||||
document.querySelector("#editRightIntroEpisodeEnd").value = setTime(Math.round(rightEpisodeJson.Introduction.IntroEnd));
|
||||
document.querySelector("#editRightCreditEpisodeStart").value = setTime(Math.round(rightEpisodeJson.Credits.IntroStart));
|
||||
document.querySelector("#editRightCreditEpisodeEnd").value = setTime(Math.round(rightEpisodeJson.Credits.IntroEnd));
|
||||
|
||||
}
|
||||
|
||||
// adds an item to a dropdown
|
||||
@ -1143,6 +1200,7 @@
|
||||
autoSkipChanged();
|
||||
autoSkipCreditsChanged();
|
||||
persistSkipChanged();
|
||||
generateAutoSkipClientList();
|
||||
|
||||
Dashboard.hideLoadingMsg();
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user