Implement TA-> JF playlist sync scheduled task
This commit is contained in:
@@ -14,6 +14,7 @@ using MediaBrowser.Common.Plugins;
|
|||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.TV;
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Controller.Playlists;
|
||||||
using MediaBrowser.Controller.Session;
|
using MediaBrowser.Controller.Session;
|
||||||
using MediaBrowser.Model.Plugins;
|
using MediaBrowser.Model.Plugins;
|
||||||
using MediaBrowser.Model.Serialization;
|
using MediaBrowser.Model.Serialization;
|
||||||
@@ -41,6 +42,7 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata
|
|||||||
/// <param name="taskManager">Instance of the <see cref="ITaskManager"/> interface.</param>
|
/// <param name="taskManager">Instance of the <see cref="ITaskManager"/> interface.</param>
|
||||||
/// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
|
/// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
|
||||||
/// <param name="userDataManager">Instance of the <see cref="IUserDataManager"/> interface.</param>
|
/// <param name="userDataManager">Instance of the <see cref="IUserDataManager"/> interface.</param>
|
||||||
|
/// <param name="playlistManager">Instance of the <see cref="IPlaylistManager"/> interface.</param>
|
||||||
public Plugin(
|
public Plugin(
|
||||||
IApplicationPaths applicationPaths,
|
IApplicationPaths applicationPaths,
|
||||||
IXmlSerializer xmlSerializer,
|
IXmlSerializer xmlSerializer,
|
||||||
@@ -49,7 +51,8 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata
|
|||||||
ILibraryManager libraryManager,
|
ILibraryManager libraryManager,
|
||||||
ITaskManager taskManager,
|
ITaskManager taskManager,
|
||||||
IUserManager userManager,
|
IUserManager userManager,
|
||||||
IUserDataManager userDataManager)
|
IUserDataManager userDataManager,
|
||||||
|
IPlaylistManager playlistManager)
|
||||||
: base(applicationPaths, xmlSerializer)
|
: base(applicationPaths, xmlSerializer)
|
||||||
{
|
{
|
||||||
Instance = this;
|
Instance = this;
|
||||||
@@ -68,6 +71,7 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata
|
|||||||
userDataManager.UserDataSaved += OnWatchedStatusChange;
|
userDataManager.UserDataSaved += OnWatchedStatusChange;
|
||||||
|
|
||||||
var taToJellyfinProgressSyncTask = new TAToJellyfinProgressSyncTask(logger, libraryManager, userManager, userDataManager);
|
var taToJellyfinProgressSyncTask = new TAToJellyfinProgressSyncTask(logger, libraryManager, userManager, userDataManager);
|
||||||
|
var taToJellyfinPlaylistsSyncTask = new TAToJellyfinPlaylistsSyncTask(logger, libraryManager, userManager, playlistManager);
|
||||||
var jfToTubearchivistProgressSyncTask = new JFToTubearchivistProgressSyncTask(logger, libraryManager, userManager, userDataManager);
|
var jfToTubearchivistProgressSyncTask = new JFToTubearchivistProgressSyncTask(logger, libraryManager, userManager, userDataManager);
|
||||||
var isTAJFTaskPresent = taskManager.ScheduledTasks.Any(t => t.Name.Equals(taToJellyfinProgressSyncTask.Name, StringComparison.Ordinal));
|
var isTAJFTaskPresent = taskManager.ScheduledTasks.Any(t => t.Name.Equals(taToJellyfinProgressSyncTask.Name, StringComparison.Ordinal));
|
||||||
if (Instance!.Configuration.TAJFSync && !isTAJFTaskPresent)
|
if (Instance!.Configuration.TAJFSync && !isTAJFTaskPresent)
|
||||||
@@ -75,6 +79,10 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata
|
|||||||
logger.LogInformation("Queueing task {TaskName}.", taToJellyfinProgressSyncTask.Name);
|
logger.LogInformation("Queueing task {TaskName}.", taToJellyfinProgressSyncTask.Name);
|
||||||
taskManager.AddTasks([taToJellyfinProgressSyncTask]);
|
taskManager.AddTasks([taToJellyfinProgressSyncTask]);
|
||||||
taskManager.Execute<TAToJellyfinProgressSyncTask>();
|
taskManager.Execute<TAToJellyfinProgressSyncTask>();
|
||||||
|
|
||||||
|
logger.LogInformation("Queueing task {TaskName}.", taToJellyfinPlaylistsSyncTask.Name);
|
||||||
|
taskManager.AddTasks([taToJellyfinProgressSyncTask]);
|
||||||
|
taskManager.Execute<TAToJellyfinProgressSyncTask>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var isJFTATaskPresent = taskManager.ScheduledTasks.Any(t => t.Name.Equals(jfToTubearchivistProgressSyncTask.Name, StringComparison.Ordinal));
|
var isJFTATaskPresent = taskManager.ScheduledTasks.Any(t => t.Name.Equals(jfToTubearchivistProgressSyncTask.Name, StringComparison.Ordinal));
|
||||||
|
|||||||
@@ -0,0 +1,189 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
|
using Jellyfin.Plugin.TubeArchivistMetadata.TubeArchivist;
|
||||||
|
using Jellyfin.Plugin.TubeArchivistMetadata.Utilities;
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Controller.Playlists;
|
||||||
|
using MediaBrowser.Model.Dto;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.Playlists;
|
||||||
|
using MediaBrowser.Model.Tasks;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace Jellyfin.Plugin.TubeArchivistMetadata.Tasks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Task to sync TubeArchivist playback progresses to Jellyfin.
|
||||||
|
/// </summary>
|
||||||
|
public class TAToJellyfinPlaylistsSyncTask : IScheduledTask
|
||||||
|
{
|
||||||
|
private readonly ILogger<Plugin> _logger;
|
||||||
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
private readonly IUserManager _userManager;
|
||||||
|
private readonly IPlaylistManager _playlistManager;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="TAToJellyfinPlaylistsSyncTask"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="logger">Logger.</param>
|
||||||
|
/// <param name="libraryManager">Library manager.</param>
|
||||||
|
/// <param name="userManager">User manager.</param>
|
||||||
|
/// <param name="playlistManager">Playlists manager.</param>
|
||||||
|
public TAToJellyfinPlaylistsSyncTask(ILogger<Plugin> logger, ILibraryManager libraryManager, IUserManager userManager, IPlaylistManager playlistManager)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_libraryManager = libraryManager;
|
||||||
|
_userManager = userManager;
|
||||||
|
_playlistManager = playlistManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public string Name => "TAToJellyfinPlaylistsSyncTask";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public string Description => "This tasks syncs TubeArchivist playlists to Jellyfin";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public string Category => "TubeArchivistMetadata";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public string Key => "TAToJellyfinPlaylistsSyncTask";
|
||||||
|
|
||||||
|
private int CountTotalVideos(ISet<TubeArchivist.Playlist> taPlaylists)
|
||||||
|
{
|
||||||
|
var totalEntries = 0;
|
||||||
|
foreach (var taPlaylist in taPlaylists)
|
||||||
|
{
|
||||||
|
totalEntries += taPlaylist.Entries.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
progress.Report(0);
|
||||||
|
if (Plugin.Instance!.Configuration.TAJFSync)
|
||||||
|
{
|
||||||
|
var start = DateTime.Now;
|
||||||
|
_logger.LogInformation("Starting TubeArchivist->Jellyfin playlists synchronization.");
|
||||||
|
var taApi = TubeArchivistApi.GetInstance();
|
||||||
|
_logger.LogInformation("Getting TubeArchivist playlists");
|
||||||
|
var taPlaylists = await taApi.GetPlaylists().ConfigureAwait(true);
|
||||||
|
_logger.LogInformation("Received playlists:\n{Playlists}", taPlaylists);
|
||||||
|
if (taPlaylists != null)
|
||||||
|
{
|
||||||
|
var totalVideosCount = CountTotalVideos(taPlaylists);
|
||||||
|
var processedVideosCount = 0;
|
||||||
|
foreach (var jfUsername in Plugin.Instance!.Configuration.GetJFUsernamesToArray())
|
||||||
|
{
|
||||||
|
var user = _userManager.GetUserByName(jfUsername);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("{Message}", $"Jellyfin user with username {jfUsername} not found");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var userPlaylists = _playlistManager.GetPlaylists(user.Id);
|
||||||
|
|
||||||
|
foreach (var taPlaylist in taPlaylists)
|
||||||
|
{
|
||||||
|
var playlistName = taPlaylist.Type == PlaylistType.Regular ? $"{taPlaylist.Name} - {taPlaylist.Channel} ({taPlaylist.Id})" : $"{taPlaylist.Name} ({taPlaylist.Id})";
|
||||||
|
var userPlaylist = userPlaylists.Where(up => up.Name == playlistName).FirstOrDefault();
|
||||||
|
|
||||||
|
var jfEntryIds = new List<Guid>();
|
||||||
|
var currentPlaylistVideos = 0;
|
||||||
|
foreach (var taEntry in taPlaylist.Entries)
|
||||||
|
{
|
||||||
|
currentPlaylistVideos++;
|
||||||
|
var taEntryStr = $"{taEntry.Uploader} - {taEntry.Title} ({taEntry.YoutubeId}) in playlist {playlistName}";
|
||||||
|
if (!taEntry.IsDownloaded)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("The entry {TAEntry} was skipped because has not been downloaded by TubeArchivist", taEntryStr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var jfEntry = _libraryManager.GetItemList(new InternalItemsQuery
|
||||||
|
{
|
||||||
|
HasAnyProviderId = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
Constants.ProviderName, taEntry.YoutubeId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).FirstOrDefault();
|
||||||
|
|
||||||
|
if (jfEntry != null)
|
||||||
|
{
|
||||||
|
jfEntryIds.Add(jfEntry.Id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogWarning("The relative video for {TAEntry} was not found on Jellyfin", taEntryStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userPlaylist != null)
|
||||||
|
{
|
||||||
|
var updateRequest = new PlaylistUpdateRequest
|
||||||
|
{
|
||||||
|
Id = userPlaylist.Id,
|
||||||
|
UserId = user.Id,
|
||||||
|
Name = playlistName,
|
||||||
|
Ids = jfEntryIds
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = _playlistManager.UpdatePlaylist(updateRequest);
|
||||||
|
_logger.LogInformation("Updated playlist {PlaylistName} with id {Id}", playlistName, result.Id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var creationRequest = new PlaylistCreationRequest
|
||||||
|
{
|
||||||
|
Name = playlistName,
|
||||||
|
ItemIdList = jfEntryIds,
|
||||||
|
MediaType = MediaType.Video,
|
||||||
|
UserId = user.Id
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await _playlistManager.CreatePlaylist(creationRequest).ConfigureAwait(true);
|
||||||
|
_logger.LogInformation("Created playlist {PlaylistName} with id {Id}", playlistName, result.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
processedVideosCount += currentPlaylistVideos;
|
||||||
|
progress.Report(processedVideosCount * 100 / totalVideosCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation("Time elapsed: {Time}", DateTime.Now - start);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogInformation("TubeArchivist->Jellyfin playback synchronization is currently disabled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
progress.Report(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
[
|
||||||
|
new TaskTriggerInfo
|
||||||
|
{
|
||||||
|
Type = TaskTriggerInfo.TriggerInterval,
|
||||||
|
IntervalTicks = TimeSpan.FromSeconds(Plugin.Instance!.Configuration.TAJFTaskInterval).Ticks
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user