diff --git a/Shokofin/SignalR/Interfaces/IFileMatchedEventArgs.cs b/Shokofin/SignalR/Interfaces/IFileMatchedEventArgs.cs
new file mode 100644
index 00000000..d008802e
--- /dev/null
+++ b/Shokofin/SignalR/Interfaces/IFileMatchedEventArgs.cs
@@ -0,0 +1,49 @@
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+
+namespace Shokofin.SignalR.Interfaces;
+
+public interface IFileEventArgs
+{
+ ///
+ /// Shoko file id.
+ ///
+ int FileId { get; }
+
+ ///
+ /// The ID of the new import folder the event was detected in.
+ ///
+ ///
+ int ImportFolderId { get; }
+
+ ///
+ /// The relative path of the new file from the import folder base location.
+ ///
+ string RelativePath { get; }
+
+ ///
+ /// Cross references of episodes linked to this file.
+ ///
+ List CrossReferences { get; }
+
+ public class FileCrossReference
+ {
+ ///
+ /// Shoko episode id.
+ ///
+ [JsonPropertyName("EpisodeID")]
+ public int EpisodeId { get; set; }
+
+ ///
+ /// Shoko series id.
+ ///
+ [JsonPropertyName("SeriesID")]
+ public int SeriesId { get; set; }
+
+ ///
+ /// Shoko group id.
+ ///
+ [JsonPropertyName("GroupID")]
+ public int GroupId { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Shokofin/SignalR/Models/EpisodeInfoUpdatedEventArgs.cs b/Shokofin/SignalR/Models/EpisodeInfoUpdatedEventArgs.cs
index 43fccb8b..fb13d620 100644
--- a/Shokofin/SignalR/Models/EpisodeInfoUpdatedEventArgs.cs
+++ b/Shokofin/SignalR/Models/EpisodeInfoUpdatedEventArgs.cs
@@ -1,3 +1,4 @@
+using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace Shokofin.SignalR.Models;
@@ -5,20 +6,42 @@ namespace Shokofin.SignalR.Models;
public class EpisodeInfoUpdatedEventArgs
{
///
- /// Shoko episode id.
+ /// The update reason.
+ ///
+ public UpdateReason Reason { get; set; }
+ ///
+ /// The provider metadata source.
+ ///
+ [JsonPropertyName("Source")]
+ public string ProviderName { get; set; } = string.Empty;
+
+ ///
+ /// The provided metadata episode id.
///
[JsonPropertyName("EpisodeID")]
- public int EpisodeId { get; set; }
+ public int ProviderId { get; set; }
///
- /// Shoko series id.
+ /// The provided metadata series id.
///
[JsonPropertyName("SeriesID")]
- public int SeriesId { get; set; }
+ public int ProviderSeriesId { get; set; }
+
+ ///
+ /// Shoko episode ids affected by this update.
+ ///
+ [JsonPropertyName("ShokoEpisodeIDs")]
+ public List EpisodeIds { get; set; } = new();
+
+ ///
+ /// Shoko series ids affected by this update.
+ ///
+ [JsonPropertyName("ShokoSeriesIDs")]
+ public List SeriesIds { get; set; } = new();
///
- /// Shoko group id.
+ /// Shoko group ids affected by this update.
///
- [JsonPropertyName("GroupID")]
- public int GroupId { get; set; }
+ [JsonPropertyName("ShokoGroupIDs")]
+ public List GroupIds { get; set; } = new();
}
\ No newline at end of file
diff --git a/Shokofin/SignalR/Models/FileEventArgs.cs b/Shokofin/SignalR/Models/FileEventArgs.cs
index 5a4e69a1..1968d4e4 100644
--- a/Shokofin/SignalR/Models/FileEventArgs.cs
+++ b/Shokofin/SignalR/Models/FileEventArgs.cs
@@ -1,8 +1,10 @@
+using System.Collections.Generic;
using System.Text.Json.Serialization;
+using Shokofin.SignalR.Interfaces;
namespace Shokofin.SignalR.Models;
-public class FileEventArgs
+public class FileEventArgs : IFileEventArgs
{
///
/// Shoko file id.
@@ -22,4 +24,9 @@ public class FileEventArgs
///
[JsonPropertyName("RelativePath")]
public string RelativePath { get; set; } = string.Empty;
+
+ ///
+ /// Cross references of episodes linked to this file.
+ ///
+ public List CrossReferences { get; set; } = new();
}
diff --git a/Shokofin/SignalR/Models/FileMatchedEventArgs.cs b/Shokofin/SignalR/Models/FileMatchedEventArgs.cs
index f1067c66..efe4ade0 100644
--- a/Shokofin/SignalR/Models/FileMatchedEventArgs.cs
+++ b/Shokofin/SignalR/Models/FileMatchedEventArgs.cs
@@ -1,34 +1,33 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
+using Shokofin.SignalR.Interfaces;
namespace Shokofin.SignalR.Models;
-public class FileMatchedEventArgs : FileEventArgs
+public class FileMatchedEventArgsV1 : IFileEventArgs
{
///
- /// Cross references of episodes linked to this file.
+ /// Shoko file id.
///
- [JsonPropertyName("CrossRefs")]
- public List CrossReferences { get; set; } = new();
+ [JsonPropertyName("FileID")]
+ public int FileId { get; set; }
- public class FileCrossReference
- {
- ///
- /// Shoko episode id.
- ///
- [JsonPropertyName("EpisodeID")]
- public int EpisodeId { get; set; }
+ ///
+ /// The ID of the import folder the event was detected in.
+ ///
+ ///
+ [JsonPropertyName("ImportFolderID")]
+ public int ImportFolderId { get; set; }
- ///
- /// Shoko series id.
- ///
- [JsonPropertyName("SeriesID")]
- public int SeriesId { get; set; }
+ ///
+ /// The relative path of the file from the import folder base location.
+ ///
+ [JsonPropertyName("RelativePath")]
+ public string RelativePath { get; set; } = string.Empty;
- ///
- /// Shoko group id.
- ///
- [JsonPropertyName("GroupID")]
- public int GroupId { get; set; }
- }
+ ///
+ /// Cross references of episodes linked to this file.
+ ///
+ [JsonPropertyName("CrossRefs")]
+ public List CrossReferences { get; set; } = new();
}
\ No newline at end of file
diff --git a/Shokofin/SignalR/Models/FileMovedEventArgs.cs b/Shokofin/SignalR/Models/FileMovedEventArgs.cs
index b1247725..c54ee78a 100644
--- a/Shokofin/SignalR/Models/FileMovedEventArgs.cs
+++ b/Shokofin/SignalR/Models/FileMovedEventArgs.cs
@@ -3,7 +3,7 @@
namespace Shokofin.SignalR.Models;
-public class FileMovedEventArgs : IFileRelocationEventArgs
+public class FileMovedEventArgsV1 : IFileRelocationEventArgs
{
///
/// Shoko file id.
@@ -37,3 +37,18 @@ public class FileMovedEventArgs : IFileRelocationEventArgs
[JsonPropertyName("OldRelativePath")]
public string PreviousRelativePath { get; set; } = string.Empty;
}
+
+public class FileMovedEventArgs: FileEventArgs, IFileRelocationEventArgs
+{
+ ///
+ /// The ID of the old import folder the event was detected in.
+ ///
+ ///
+ [JsonPropertyName("PreviousImportFolderID")]
+ public int PreviousImportFolderId { get; set; }
+
+ ///
+ /// The relative path of the old file from the import folder base location.
+ ///
+ public string PreviousRelativePath { get; set; } = string.Empty;
+}
diff --git a/Shokofin/SignalR/Models/FileRenamedEventArgs.cs b/Shokofin/SignalR/Models/FileRenamedEventArgs.cs
index 9db248f6..997a08d2 100644
--- a/Shokofin/SignalR/Models/FileRenamedEventArgs.cs
+++ b/Shokofin/SignalR/Models/FileRenamedEventArgs.cs
@@ -3,8 +3,27 @@
namespace Shokofin.SignalR.Models;
-public class FileRenamedEventArgs : FileEventArgs, IFileRelocationEventArgs
+public class FileRenamedEventArgsV1 : IFileRelocationEventArgs
{
+ ///
+ /// Shoko file id.
+ ///
+ [JsonPropertyName("FileID")]
+ public int FileId { get; set; }
+
+ ///
+ /// The ID of the import folder the event was detected in.
+ ///
+ ///
+ [JsonPropertyName("ImportFolderID")]
+ public int ImportFolderId { get; set; }
+
+ ///
+ /// The relative path of the file from the import folder base location.
+ ///
+ [JsonPropertyName("RelativePath")]
+ public string RelativePath { get; set; } = string.Empty;
+
///
/// The new File name.
///
@@ -17,10 +36,29 @@ public class FileRenamedEventArgs : FileEventArgs, IFileRelocationEventArgs
[JsonPropertyName("OldFileName")]
public string PreviousFileName { get; set; } = string.Empty;
- public int PreviousImportFolderId { get; set; }
+
+ ///
+ public int PreviousImportFolderId => ImportFolderId;
+
+ ///
+ public string PreviousRelativePath => RelativePath[^FileName.Length] + PreviousFileName;
+}
+
+public class FileRenamedEventArgs : FileEventArgs, IFileRelocationEventArgs
+{
+ ///
+ /// The new File name.
+ ///
+ public string FileName { get; set; } = string.Empty;
///
- /// The relative path of the old file from the import folder base location.
+ /// The old file name.
///
+ public string PreviousFileName { get; set; } = string.Empty;
+
+ ///
+ public int PreviousImportFolderId => ImportFolderId;
+
+ ///
public string PreviousRelativePath => RelativePath[^FileName.Length] + PreviousFileName;
}
\ No newline at end of file
diff --git a/Shokofin/SignalR/Models/SeriesInfoUpdatedEventArgs.cs b/Shokofin/SignalR/Models/SeriesInfoUpdatedEventArgs.cs
index 7bab9b68..824d2bc1 100644
--- a/Shokofin/SignalR/Models/SeriesInfoUpdatedEventArgs.cs
+++ b/Shokofin/SignalR/Models/SeriesInfoUpdatedEventArgs.cs
@@ -1,3 +1,4 @@
+using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace Shokofin.SignalR.Models;
@@ -5,14 +6,31 @@ namespace Shokofin.SignalR.Models;
public class SeriesInfoUpdatedEventArgs
{
///
- /// Shoko series id.
+ /// The update reason.
+ ///
+ public UpdateReason Reason { get; set; }
+
+ ///
+ /// The provider metadata source.
+ ///
+ [JsonPropertyName("Source")]
+ public string ProviderName { get; set; } = string.Empty;
+
+ ///
+ /// The provided metadata series id.
///
[JsonPropertyName("SeriesID")]
- public int SeriesId { get; set; }
+ public int ProviderId { get; set; }
+
+ ///
+ /// Shoko series ids affected by this update.
+ ///
+ [JsonPropertyName("ShokoSeriesIDs")]
+ public List SeriesIds { get; set; } = new();
///
- /// Shoko group id.
+ /// Shoko group ids affected by this update.
///
- [JsonPropertyName("GroupID")]
- public int GroupId { get; set; }
+ [JsonPropertyName("ShokoGroupIDs")]
+ public List GroupIds { get; set; } = new();
}
\ No newline at end of file
diff --git a/Shokofin/SignalR/Models/UpdateReason.cs b/Shokofin/SignalR/Models/UpdateReason.cs
new file mode 100644
index 00000000..a3f003e8
--- /dev/null
+++ b/Shokofin/SignalR/Models/UpdateReason.cs
@@ -0,0 +1,13 @@
+
+using System.Text.Json.Serialization;
+
+namespace Shokofin.SignalR.Models;
+
+[JsonConverter(typeof(JsonStringEnumConverter))]
+public enum UpdateReason
+{
+ None = 0,
+ Added = 1,
+ Updated = 2,
+ Removed = 3,
+}
\ No newline at end of file
diff --git a/Shokofin/SignalR/SignalRConnectionManager.cs b/Shokofin/SignalR/SignalRConnectionManager.cs
index 954db286..5676b376 100644
--- a/Shokofin/SignalR/SignalRConnectionManager.cs
+++ b/Shokofin/SignalR/SignalRConnectionManager.cs
@@ -6,6 +6,7 @@
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
+using Shokofin.API.Models;
using Shokofin.Configuration;
using Shokofin.Resolvers;
using Shokofin.SignalR.Interfaces;
@@ -15,6 +16,14 @@ namespace Shokofin.SignalR;
public class SignalRConnectionManager : IDisposable
{
+ private static ComponentVersion? ServerVersion =>
+ Plugin.Instance.Configuration.ServerVersion;
+
+ private static readonly DateTime EventChangedDate = DateTime.Parse("2024-04-01T04:04:00.000Z");
+
+ private static bool UseOlderEvents =>
+ ServerVersion != null && ((ServerVersion.ReleaseChannel == ReleaseChannel.Stable && ServerVersion.Version == "4.2.2.0") || (ServerVersion.ReleaseDate.HasValue && ServerVersion.ReleaseDate.Value < EventChangedDate));
+
private const string HubUrl = "/signalr/aggregate?feeds=shoko";
private readonly ILogger Logger;
@@ -76,10 +85,18 @@ private async Task ConnectAsync(PluginConfiguration config)
connection.On("ShokoEvent:SeriesUpdated", OnSeriesInfoUpdated);
// Attach file events.
- connection.On("ShokoEvent:FileMatched", OnFileMatched);
- connection.On("ShokoEvent:FileMoved", OnFileMoved);
- connection.On("ShokoEvent:FileRenamed", OnFileRenamed);
- connection.On("ShokoEvent:FileDeleted", OnFileDeleted);
+ if (UseOlderEvents) {
+ connection.On("ShokoEvent:FileMatched", OnFileMatched);
+ connection.On("ShokoEvent:FileMoved", OnFileRelocated);
+ connection.On("ShokoEvent:FileRenamed", OnFileRelocated);
+ connection.On("ShokoEvent:FileDeleted", OnFileDeleted);
+ }
+ else {
+ connection.On("ShokoEvent:FileMatched", OnFileMatched);
+ connection.On("ShokoEvent:FileMoved", OnFileRelocated);
+ connection.On("ShokoEvent:FileRenamed", OnFileRelocated);
+ connection.On("ShokoEvent:FileDeleted", OnFileDeleted);
+ }
try {
await connection.StartAsync().ConfigureAwait(false);
@@ -181,10 +198,10 @@ private static string ConstructKey(PluginConfiguration config)
#region File Events
- private void OnFileMatched(FileMatchedEventArgs eventArgs)
+ private void OnFileMatched(IFileEventArgs eventArgs)
{
Logger.LogDebug(
- "File matched; {ImportFolderIdB} {PathB} (File={FileId})",
+ "File matched; {ImportFolderId} {Path} (File={FileId})",
eventArgs.ImportFolderId,
eventArgs.RelativePath,
eventArgs.FileId
@@ -222,13 +239,7 @@ private void OnFileRelocated(IFileRelocationEventArgs eventArgs)
// the links broke, and if the newly generated links is not in the list provided by the base items, then remove the broken link.
}
- private void OnFileMoved(FileMovedEventArgs eventArgs)
- => OnFileRelocated(eventArgs);
-
- private void OnFileRenamed(FileRenamedEventArgs eventArgs)
- => OnFileRelocated(eventArgs);
-
- private void OnFileDeleted(FileEventArgs eventArgs)
+ private void OnFileDeleted(IFileEventArgs eventArgs)
{
Logger.LogDebug(
"File deleted; {ImportFolderIdB} {PathB} (File={FileId})",
@@ -253,10 +264,14 @@ private void OnFileDeleted(FileEventArgs eventArgs)
private void OnEpisodeInfoUpdated(EpisodeInfoUpdatedEventArgs eventArgs)
{
Logger.LogDebug(
- "Episode updated. (Episode={EpisodeId},Series={SeriesId},Group={GroupId})",
- eventArgs.EpisodeId,
- eventArgs.SeriesId,
- eventArgs.GroupId
+ "{ProviderName} episode {ProviderId} ({ProviderSeriesId}) dispatched event {UpdateReason}. (Episode={EpisodeId},Series={SeriesId},Group={GroupId})",
+ eventArgs.ProviderName,
+ eventArgs.ProviderId,
+ eventArgs.ProviderSeriesId,
+ eventArgs.Reason,
+ eventArgs.EpisodeIds,
+ eventArgs.SeriesIds,
+ eventArgs.GroupIds
);
// Refresh all epoisodes and movies linked to the episode.
@@ -265,9 +280,12 @@ private void OnEpisodeInfoUpdated(EpisodeInfoUpdatedEventArgs eventArgs)
private void OnSeriesInfoUpdated(SeriesInfoUpdatedEventArgs eventArgs)
{
Logger.LogDebug(
- "Series updated. (Series={SeriesId},Group={GroupId})",
- eventArgs.SeriesId,
- eventArgs.GroupId
+ "{ProviderName} series {ProviderId} dispatched event {UpdateReason}. (Series={SeriesId},Group={GroupId})",
+ eventArgs.ProviderName,
+ eventArgs.ProviderId,
+ eventArgs.Reason,
+ eventArgs.SeriesIds,
+ eventArgs.GroupIds
);
// look up the series/season/movie, then check the media folder they're