Merge pull request #49 from tubearchivist/bugfix/sync-usernames

JF->TA Sync fix
This commit is contained in:
DarkFighterLuke
2025-05-26 23:43:57 +02:00
committed by GitHub
2 changed files with 107 additions and 103 deletions
@@ -28,6 +28,7 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata
public class Plugin : BasePlugin<PluginConfiguration>, IHasWebPages public class Plugin : BasePlugin<PluginConfiguration>, IHasWebPages
{ {
private readonly IUserManager _userManager; private readonly IUserManager _userManager;
private readonly IUserDataManager _userDataManager;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Plugin"/> class. /// Initializes a new instance of the <see cref="Plugin"/> class.
@@ -63,6 +64,7 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata
sessionManager.PlaybackProgress += OnPlaybackProgress; sessionManager.PlaybackProgress += OnPlaybackProgress;
LibraryManager = libraryManager; LibraryManager = libraryManager;
_userManager = userManager; _userManager = userManager;
_userDataManager = userDataManager;
userDataManager.UserDataSaved += OnWatchedStatusChange; userDataManager.UserDataSaved += OnWatchedStatusChange;
var taToJellyfinProgressSyncTask = new TAToJellyfinProgressSyncTask(logger, libraryManager, userManager, userDataManager); var taToJellyfinProgressSyncTask = new TAToJellyfinProgressSyncTask(logger, libraryManager, userManager, userDataManager);
@@ -173,7 +175,8 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata
{ {
if (Instance!.Configuration.JFTASync && eventArgs.Users.Any(u => Instance!.Configuration.JFUsernameFrom.Equals(u.Username, StringComparison.Ordinal))) if (Instance!.Configuration.JFTASync && eventArgs.Users.Any(u => Instance!.Configuration.JFUsernameFrom.Equals(u.Username, StringComparison.Ordinal)))
{ {
BaseItem? channel = LibraryManager.GetItemById(eventArgs.Item.ParentId); BaseItem? season = LibraryManager.GetItemById(eventArgs.Item.ParentId);
BaseItem? channel = LibraryManager.GetItemById(season!.ParentId);
BaseItem? collection = LibraryManager.GetItemById(channel!.ParentId); BaseItem? collection = LibraryManager.GetItemById(channel!.ParentId);
if (collection?.Name.ToLower(CultureInfo.CurrentCulture) == Instance?.Configuration.CollectionTitle.ToLower(CultureInfo.CurrentCulture) && eventArgs.PlaybackPositionTicks != null) if (collection?.Name.ToLower(CultureInfo.CurrentCulture) == Instance?.Configuration.CollectionTitle.ToLower(CultureInfo.CurrentCulture) && eventArgs.PlaybackPositionTicks != null)
{ {
@@ -224,6 +227,17 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata
{ {
Logger.LogCritical("POST /watched returned {StatusCode} for item {ItemName} ({VideoYTId}) with watched status {IsPlayed}", statusCode, eventArgs.Item.Name, itemYTId, isPlayed); Logger.LogCritical("POST /watched returned {StatusCode} for item {ItemName} ({VideoYTId}) with watched status {IsPlayed}", statusCode, eventArgs.Item.Name, itemYTId, isPlayed);
} }
if (eventArgs.Item is Episode)
{
var progress = _userDataManager.GetUserData(user, eventArgs.Item).PlaybackPositionTicks / TimeSpan.TicksPerSecond;
var videoId = Utils.GetVideoNameFromPath(eventArgs.Item.Path);
statusCode = await TubeArchivistApi.GetInstance().SetProgress(videoId, progress).ConfigureAwait(true);
if (statusCode != System.Net.HttpStatusCode.OK)
{
Logger.LogCritical("{Message}", $"POST /video/{videoId}/progress returned {statusCode} for video {eventArgs.Item.Name} with progress {progress} seconds");
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Data.Enums; using Jellyfin.Data.Enums;
@@ -45,7 +46,7 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Tasks
public string Name => "JFToTubeArchivistProgressSyncTask"; public string Name => "JFToTubeArchivistProgressSyncTask";
/// <inheritdoc/> /// <inheritdoc/>
public string Description => "This tasks syncs TubeArchivist playback progresses to Jellyfin"; public string Description => "This tasks syncs Jellyfin playback progresses to TubeArchivist";
/// <inheritdoc/> /// <inheritdoc/>
public string Category => "TubeArchivistMetadata"; public string Category => "TubeArchivistMetadata";
@@ -63,54 +64,52 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Tasks
_logger.LogInformation("Starting Jellyfin->TubeArchivist playback progresses synchronization."); _logger.LogInformation("Starting Jellyfin->TubeArchivist playback progresses synchronization.");
var taApi = TubeArchivistApi.GetInstance(); var taApi = TubeArchivistApi.GetInstance();
var videosCount = 0; var videosCount = 0;
foreach (var jfUsername in Plugin.Instance!.Configuration.GetJFUsernamesToArray()) var jfUsername = Plugin.Instance!.Configuration.JFUsernameFrom;
var user = _userManager.GetUserByName(jfUsername);
if (user == null)
{ {
var user = _userManager.GetUserByName(jfUsername); _logger.LogInformation("{Message}", $"Jellyfin user with username {jfUsername} not found");
if (user == null) return;
{ }
_logger.LogInformation("{Message}", $"Jellyfin user with username {jfUsername} not found");
continue;
}
var collectionItem = _libraryManager.GetItemList(new InternalItemsQuery var collectionItem = _libraryManager.GetItemList(new InternalItemsQuery
{ {
Name = Plugin.Instance?.Configuration.CollectionTitle, Name = Plugin.Instance?.Configuration.CollectionTitle,
IncludeItemTypes = new[] { BaseItemKind.CollectionFolder } IncludeItemTypes = new[] { BaseItemKind.CollectionFolder }
}).FirstOrDefault(); }).FirstOrDefault();
if (collectionItem == null) if (collectionItem == null)
{
var message = $"Collection '{Plugin.Instance?.Configuration.CollectionTitle}' not found.";
_logger.LogCritical("{Message}", message);
}
else
{
var collection = (CollectionFolder)collectionItem;
var channels = collection.GetChildren(user, false, new InternalItemsQuery
{ {
var message = $"Collection '{Plugin.Instance?.Configuration.CollectionTitle}' not found."; IncludeItemTypes = new[] { BaseItemKind.Series }
_logger.LogCritical("{Message}", message); });
} _logger.LogInformation("Analyzing collection {Id} with name {Name}", collectionItem.Id, collectionItem.Name);
else _logger.LogDebug("Found {Message} channels", channels.Count);
foreach (Series channel in channels)
{ {
var collection = (CollectionFolder)collectionItem; var channelYTId = Utils.GetChannelNameFromPath(channel.Path);
var channels = collection.GetChildren(user, false, new InternalItemsQuery var years = channel.GetChildren(user, false, new InternalItemsQuery
{ {
IncludeItemTypes = new[] { BaseItemKind.Series } IncludeItemTypes = new[] { BaseItemKind.Season }
}); });
_logger.LogInformation("Analyzing collection {Id} with name {Name}", collectionItem.Id, collectionItem.Name); _logger.LogDebug("Found {Years} years in channel {ChannelName}", years.Count, channel.Name);
_logger.LogDebug("Found {Message} channels", channels.Count);
foreach (Series channel in channels) foreach (Season year in years)
{ {
var channelYTId = Utils.GetChannelNameFromPath(channel.Path); var videos = year.GetChildren(user, false, new InternalItemsQuery
var years = channel.GetChildren(user, false, new InternalItemsQuery
{ {
IncludeItemTypes = new[] { BaseItemKind.Season } IncludeItemTypes = new[] { BaseItemKind.Episode }
}); });
_logger.LogDebug("Found {Years} years in channel {ChannelName}", years.Count, channel.Name); _logger.LogDebug("Found {Videos} videos in year {YearName} of the channel {ChannelName}", videos.Count, year.Name, channel.Name);
videosCount += videos.Count;
foreach (Season year in years)
{
var videos = year.GetChildren(user, false, new InternalItemsQuery
{
IncludeItemTypes = new[] { BaseItemKind.Episode }
});
_logger.LogDebug("Found {Videos} videos in year {YearName} of the channel {ChannelName}", videos.Count, year.Name, channel.Name);
videosCount += videos.Count;
}
} }
} }
} }
@@ -118,91 +117,82 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Tasks
_logger.LogInformation("Found a total of {VideosCount} videos", videosCount); _logger.LogInformation("Found a total of {VideosCount} videos", videosCount);
var processedVideosCount = 0; var processedVideosCount = 0;
foreach (var jfUsername in Plugin.Instance!.Configuration.GetJFUsernamesToArray()) if (collectionItem == null)
{ {
var user = _userManager.GetUserByName(jfUsername); var message = $"Collection '{Plugin.Instance?.Configuration.CollectionTitle}' not found.";
if (user == null) _logger.LogCritical("{Message}", message);
}
else
{
var collection = (CollectionFolder)collectionItem;
var channels = collection.GetChildren(user, false, new InternalItemsQuery
{ {
_logger.LogInformation("{Message}", $"Jellyfin user with username {jfUsername} not found"); IncludeItemTypes = new[] { BaseItemKind.Series }
continue; });
}
var collectionItem = _libraryManager.GetItemList(new InternalItemsQuery foreach (Series channel in channels)
{ {
Name = Plugin.Instance?.Configuration.CollectionTitle, var channelYTId = Utils.GetChannelNameFromPath(channel.Path);
IncludeItemTypes = new[] { BaseItemKind.CollectionFolder } var isChannelWatched = false;
}).FirstOrDefault(); var isChannelCheckedForWatched = false;
var years = channel.GetChildren(user, false, new InternalItemsQuery
if (collectionItem == null)
{
var message = $"Collection '{Plugin.Instance?.Configuration.CollectionTitle}' not found.";
_logger.LogCritical("{Message}", message);
}
else
{
var collection = (CollectionFolder)collectionItem;
var channels = collection.GetChildren(user, false, new InternalItemsQuery
{ {
IncludeItemTypes = new[] { BaseItemKind.Series } IncludeItemTypes = new[] { BaseItemKind.Season }
}); });
foreach (Series channel in channels) foreach (Season year in years)
{ {
var channelYTId = Utils.GetChannelNameFromPath(channel.Path); var videos = year.GetChildren(user, false, new InternalItemsQuery
var isChannelWatched = false;
var isChannelCheckedForWatched = false;
var years = channel.GetChildren(user, false, new InternalItemsQuery
{ {
IncludeItemTypes = new[] { BaseItemKind.Season } IncludeItemTypes = new[] { BaseItemKind.Episode }
}); });
videosCount += videos.Count;
foreach (Season year in years) foreach (Episode video in videos)
{ {
var videos = year.GetChildren(user, false, new InternalItemsQuery var videoYTId = Utils.GetVideoNameFromPath(video.Path);
{ _logger.LogInformation("{VideoYtId}", videoYTId);
IncludeItemTypes = new[] { BaseItemKind.Episode } HttpStatusCode statusCode;
});
videosCount += videos.Count;
foreach (Episode video in videos) if (!isChannelCheckedForWatched && channel.IsPlayed(user))
{ {
var videoYTId = Utils.GetVideoNameFromPath(video.Path); var isChannelPlayed = channel.IsPlayed(user);
var playbackProgress = _userDataManager.GetUserData(user, video).PlaybackPositionTicks / TimeSpan.TicksPerSecond; statusCode = await taApi.SetWatchedStatus(channelYTId, isChannelPlayed).ConfigureAwait(true);
var statusCode = await taApi.SetProgress(videoYTId, playbackProgress).ConfigureAwait(true);
if (statusCode != System.Net.HttpStatusCode.OK) if (statusCode != System.Net.HttpStatusCode.OK)
{ {
_logger.LogCritical("{Message}", $"POST /video/{videoYTId}/progress returned {statusCode} for video {video.Name} with progress {progress} seconds"); _logger.LogCritical("{Message}", $"POST /watched returned {statusCode} for channel {channel.Name} ({channelYTId}) with wacthed status {isChannelPlayed}");
} }
else
if (!isChannelCheckedForWatched && channel.IsPlayed(user))
{ {
var isChannelPlayed = channel.IsPlayed(user); isChannelWatched = true;
statusCode = await taApi.SetWatchedStatus(channelYTId, isChannelPlayed).ConfigureAwait(true);
if (statusCode != System.Net.HttpStatusCode.OK)
{
_logger.LogCritical("{Message}", $"POST /watched returned {statusCode} for channel {channel.Name} ({channelYTId}) with wacthed status {isChannelPlayed}");
}
else
{
isChannelWatched = true;
}
isChannelCheckedForWatched = true;
} }
if (!isChannelWatched) isChannelCheckedForWatched = true;
{
var isVideoPlayed = video.IsPlayed(user);
statusCode = await taApi.SetWatchedStatus(videoYTId, isVideoPlayed).ConfigureAwait(true);
if (statusCode != System.Net.HttpStatusCode.OK)
{
_logger.LogCritical("{Message}", $"POST /watched returned {statusCode} for video {video.Name} ({videoYTId}) with wacthed status {isVideoPlayed}");
}
}
processedVideosCount++;
progress.Report(processedVideosCount * 100 / videosCount);
} }
if (!isChannelWatched)
{
var isVideoPlayed = video.IsPlayed(user);
statusCode = await taApi.SetWatchedStatus(videoYTId, isVideoPlayed).ConfigureAwait(true);
if (statusCode != System.Net.HttpStatusCode.OK)
{
_logger.LogCritical("{Message}", $"POST /watched returned {statusCode} for video {video.Name} ({videoYTId}) with wacthed status {isVideoPlayed}");
}
_logger.LogInformation("{Message}", isVideoPlayed);
if (!isVideoPlayed)
{
var playbackProgress = _userDataManager.GetUserData(user, video).PlaybackPositionTicks / TimeSpan.TicksPerSecond;
statusCode = await taApi.SetProgress(videoYTId, playbackProgress).ConfigureAwait(true);
if (statusCode != System.Net.HttpStatusCode.OK)
{
_logger.LogCritical("{Message}", $"POST /video/{videoYTId}/progress returned {statusCode} for video {video.Name} with progress {progress} seconds");
}
}
}
processedVideosCount++;
progress.Report(processedVideosCount * 100 / videosCount);
} }
} }
} }