aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Controller')
-rw-r--r--MediaBrowser.Controller/Entities/InternalItemsQuery.cs2
-rw-r--r--MediaBrowser.Controller/Library/ILocalSimilarItemsProvider.cs63
-rw-r--r--MediaBrowser.Controller/Library/IRemoteSimilarItemsProvider.cs62
-rw-r--r--MediaBrowser.Controller/Library/ISimilarItemsManager.cs50
-rw-r--r--MediaBrowser.Controller/Library/ISimilarItemsProvider.cs26
-rw-r--r--MediaBrowser.Controller/Library/SimilarItemReference.cs22
-rw-r--r--MediaBrowser.Controller/Library/SimilarItemsQuery.cs37
-rw-r--r--MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs5
-rw-r--r--MediaBrowser.Controller/Net/IWebSocketConnection.cs9
-rw-r--r--MediaBrowser.Controller/Providers/IProviderManager.cs11
10 files changed, 287 insertions, 0 deletions
diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
index fa82ea8663..8ae578b228 100644
--- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
+++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
@@ -351,6 +351,8 @@ namespace MediaBrowser.Controller.Entities
public Dictionary<string, string>? HasAnyProviderId { get; set; }
+ public Dictionary<string, string[]>? HasAnyProviderIds { get; set; }
+
public Guid[] AlbumArtistIds { get; set; }
public Guid[] BoxSetLibraryFolders { get; set; }
diff --git a/MediaBrowser.Controller/Library/ILocalSimilarItemsProvider.cs b/MediaBrowser.Controller/Library/ILocalSimilarItemsProvider.cs
new file mode 100644
index 0000000000..b8e41ec810
--- /dev/null
+++ b/MediaBrowser.Controller/Library/ILocalSimilarItemsProvider.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Entities;
+
+namespace MediaBrowser.Controller.Library;
+
+/// <summary>
+/// Provides similar items from the local library.
+/// Returns fully resolved BaseItems directly - no additional resolution needed.
+/// </summary>
+public interface ILocalSimilarItemsProvider : ISimilarItemsProvider
+{
+ /// <summary>
+ /// Determines whether the provider can handle items of the specified type.
+ /// </summary>
+ /// <param name="itemType">The item type.</param>
+ /// <returns><c>true</c> if the provider handles this item type; otherwise <c>false</c>.</returns>
+ bool Supports(Type itemType);
+
+ /// <summary>
+ /// Gets similar items from the local library.
+ /// </summary>
+ /// <param name="item">The source item to find similar items for.</param>
+ /// <param name="query">The query options (user, limit, exclusions, etc.).</param>
+ /// <param name="cancellationToken">Cancellation token.</param>
+ /// <returns>The list of similar items from the library.</returns>
+ Task<IReadOnlyList<BaseItem>> GetSimilarItemsAsync(
+ BaseItem item,
+ SimilarItemsQuery query,
+ CancellationToken cancellationToken);
+}
+
+/// <summary>
+/// Provides similar items from the local library for a specific item type.
+/// Returns fully resolved BaseItems directly - no additional resolution needed.
+/// </summary>
+/// <typeparam name="TItemType">The type of item this provider handles.</typeparam>
+public interface ILocalSimilarItemsProvider<TItemType> : ILocalSimilarItemsProvider
+ where TItemType : BaseItem
+{
+ /// <summary>
+ /// Gets similar items from the local library.
+ /// </summary>
+ /// <param name="item">The source item to find similar items for.</param>
+ /// <param name="query">The query options (user, limit, exclusions, etc.).</param>
+ /// <param name="cancellationToken">Cancellation token.</param>
+ /// <returns>The list of similar items from the library.</returns>
+ Task<IReadOnlyList<BaseItem>> GetSimilarItemsAsync(
+ TItemType item,
+ SimilarItemsQuery query,
+ CancellationToken cancellationToken);
+
+ bool ILocalSimilarItemsProvider.Supports(Type itemType)
+ => typeof(TItemType).IsAssignableFrom(itemType);
+
+ Task<IReadOnlyList<BaseItem>> ILocalSimilarItemsProvider.GetSimilarItemsAsync(
+ BaseItem item,
+ SimilarItemsQuery query,
+ CancellationToken cancellationToken)
+ => GetSimilarItemsAsync((TItemType)item, query, cancellationToken);
+}
diff --git a/MediaBrowser.Controller/Library/IRemoteSimilarItemsProvider.cs b/MediaBrowser.Controller/Library/IRemoteSimilarItemsProvider.cs
new file mode 100644
index 0000000000..3803e51769
--- /dev/null
+++ b/MediaBrowser.Controller/Library/IRemoteSimilarItemsProvider.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using MediaBrowser.Controller.Entities;
+
+namespace MediaBrowser.Controller.Library;
+
+/// <summary>
+/// Provides similar item references from remote/external sources.
+/// Returns lightweight references with ProviderIds that the manager resolves to library items.
+/// </summary>
+public interface IRemoteSimilarItemsProvider : ISimilarItemsProvider
+{
+ /// <summary>
+ /// Determines whether the provider can handle items of the specified type.
+ /// </summary>
+ /// <param name="itemType">The item type.</param>
+ /// <returns><c>true</c> if the provider handles this item type; otherwise <c>false</c>.</returns>
+ bool Supports(Type itemType);
+
+ /// <summary>
+ /// Gets similar item references from an external source as an async stream.
+ /// </summary>
+ /// <param name="item">The source item to find similar items for.</param>
+ /// <param name="query">The query options (user, limit, exclusions).</param>
+ /// <param name="cancellationToken">Cancellation token.</param>
+ /// <returns>An async enumerable of similar item references.</returns>
+ IAsyncEnumerable<SimilarItemReference> GetSimilarItemsAsync(
+ BaseItem item,
+ SimilarItemsQuery query,
+ CancellationToken cancellationToken);
+}
+
+/// <summary>
+/// Provides similar item references from remote/external sources for a specific item type.
+/// Returns lightweight references with ProviderIds that the manager resolves to library items.
+/// </summary>
+/// <typeparam name="TItemType">The type of item this provider handles.</typeparam>
+public interface IRemoteSimilarItemsProvider<TItemType> : IRemoteSimilarItemsProvider
+ where TItemType : BaseItem
+{
+ /// <summary>
+ /// Gets similar item references from an external source as an async stream.
+ /// </summary>
+ /// <param name="item">The source item to find similar items for.</param>
+ /// <param name="query">The query options (user, limit, exclusions).</param>
+ /// <param name="cancellationToken">Cancellation token.</param>
+ /// <returns>An async enumerable of similar item references.</returns>
+ IAsyncEnumerable<SimilarItemReference> GetSimilarItemsAsync(
+ TItemType item,
+ SimilarItemsQuery query,
+ CancellationToken cancellationToken);
+
+ bool IRemoteSimilarItemsProvider.Supports(Type itemType)
+ => typeof(TItemType).IsAssignableFrom(itemType);
+
+ IAsyncEnumerable<SimilarItemReference> IRemoteSimilarItemsProvider.GetSimilarItemsAsync(
+ BaseItem item,
+ SimilarItemsQuery query,
+ CancellationToken cancellationToken)
+ => GetSimilarItemsAsync((TItemType)item, query, cancellationToken);
+}
diff --git a/MediaBrowser.Controller/Library/ISimilarItemsManager.cs b/MediaBrowser.Controller/Library/ISimilarItemsManager.cs
new file mode 100644
index 0000000000..0ced6f71ee
--- /dev/null
+++ b/MediaBrowser.Controller/Library/ISimilarItemsManager.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Jellyfin.Database.Implementations.Entities;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Configuration;
+
+namespace MediaBrowser.Controller.Library;
+
+/// <summary>
+/// Interface for managing similar items providers and operations.
+/// </summary>
+public interface ISimilarItemsManager
+{
+ /// <summary>
+ /// Registers similar items providers discovered through dependency injection.
+ /// </summary>
+ /// <param name="providers">The similar items providers to register.</param>
+ void AddParts(IEnumerable<ISimilarItemsProvider> providers);
+
+ /// <summary>
+ /// Gets the similar items providers for a specific item type.
+ /// </summary>
+ /// <typeparam name="T">The item type.</typeparam>
+ /// <returns>The list of similar items providers for that type.</returns>
+ IReadOnlyList<ISimilarItemsProvider> GetSimilarItemsProviders<T>()
+ where T : BaseItem;
+
+ /// <summary>
+ /// Gets similar items for the specified item.
+ /// </summary>
+ /// <param name="item">The source item to find similar items for.</param>
+ /// <param name="excludeArtistIds">Artist IDs to exclude from results.</param>
+ /// <param name="user">The user context.</param>
+ /// <param name="dtoOptions">The DTO options.</param>
+ /// <param name="limit">Maximum number of results.</param>
+ /// <param name="libraryOptions">The library options for provider configuration.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>The list of similar items.</returns>
+ Task<IReadOnlyList<BaseItem>> GetSimilarItemsAsync(
+ BaseItem item,
+ IReadOnlyList<Guid> excludeArtistIds,
+ User? user,
+ DtoOptions dtoOptions,
+ int? limit,
+ LibraryOptions? libraryOptions,
+ CancellationToken cancellationToken);
+}
diff --git a/MediaBrowser.Controller/Library/ISimilarItemsProvider.cs b/MediaBrowser.Controller/Library/ISimilarItemsProvider.cs
new file mode 100644
index 0000000000..0d089369a8
--- /dev/null
+++ b/MediaBrowser.Controller/Library/ISimilarItemsProvider.cs
@@ -0,0 +1,26 @@
+using System;
+using MediaBrowser.Model.Configuration;
+
+namespace MediaBrowser.Controller.Library;
+
+/// <summary>
+/// Base marker interface for similar items providers.
+/// </summary>
+public interface ISimilarItemsProvider
+{
+ /// <summary>
+ /// Gets the name of the provider.
+ /// </summary>
+ string Name { get; }
+
+ /// <summary>
+ /// Gets the type of the provider.
+ /// </summary>
+ MetadataPluginType Type { get; }
+
+ /// <summary>
+ /// Gets the cache duration for results from this provider.
+ /// If null, results will not be cached.
+ /// </summary>
+ TimeSpan? CacheDuration => null;
+}
diff --git a/MediaBrowser.Controller/Library/SimilarItemReference.cs b/MediaBrowser.Controller/Library/SimilarItemReference.cs
new file mode 100644
index 0000000000..2a40c93bdd
--- /dev/null
+++ b/MediaBrowser.Controller/Library/SimilarItemReference.cs
@@ -0,0 +1,22 @@
+namespace MediaBrowser.Controller.Library;
+
+/// <summary>
+/// A reference to a similar item by provider ID with a similarity score.
+/// </summary>
+public class SimilarItemReference
+{
+ /// <summary>
+ /// Gets or sets the provider name (e.g., "Tmdb", "MusicBrainzArtist").
+ /// </summary>
+ public required string ProviderName { get; set; }
+
+ /// <summary>
+ /// Gets or sets the provider ID value.
+ /// </summary>
+ public required string ProviderId { get; set; }
+
+ /// <summary>
+ /// Gets or sets the similarity score (0.0 to 1.0).
+ /// </summary>
+ public float? Score { get; set; }
+}
diff --git a/MediaBrowser.Controller/Library/SimilarItemsQuery.cs b/MediaBrowser.Controller/Library/SimilarItemsQuery.cs
new file mode 100644
index 0000000000..1ed3ceec16
--- /dev/null
+++ b/MediaBrowser.Controller/Library/SimilarItemsQuery.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using Jellyfin.Database.Implementations.Entities;
+using MediaBrowser.Controller.Dto;
+
+namespace MediaBrowser.Controller.Library;
+
+/// <summary>
+/// Query options for similar items requests.
+/// </summary>
+public class SimilarItemsQuery
+{
+ /// <summary>
+ /// Gets or sets the user context.
+ /// </summary>
+ public User? User { get; set; }
+
+ /// <summary>
+ /// Gets or sets the maximum number of results.
+ /// </summary>
+ public int? Limit { get; set; }
+
+ /// <summary>
+ /// Gets or sets the DTO options.
+ /// </summary>
+ public DtoOptions? DtoOptions { get; set; }
+
+ /// <summary>
+ /// Gets or sets the item IDs to exclude from results.
+ /// </summary>
+ public IReadOnlyList<Guid> ExcludeItemIds { get; set; } = [];
+
+ /// <summary>
+ /// Gets or sets the artist IDs to exclude from results.
+ /// </summary>
+ public IReadOnlyList<Guid> ExcludeArtistIds { get; set; } = [];
+}
diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs
index 6b1eac8047..2bcce168cf 100644
--- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs
+++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs
@@ -209,6 +209,11 @@ namespace MediaBrowser.Controller.Net
var (connection, cts, state) = tuple;
var cancellationToken = cts.Token;
+ // Restore the culture context captured when the connection was established
+ // so that GetDataToSendForConnection produces a localized payload matching
+ // the client's Accept-Language preference rather than the server default.
+ connection.ApplyRequestCulture();
+
var data = await GetDataToSendForConnection(connection).ConfigureAwait(false);
if (data is null)
{
diff --git a/MediaBrowser.Controller/Net/IWebSocketConnection.cs b/MediaBrowser.Controller/Net/IWebSocketConnection.cs
index bdc0f9a10f..48431e75c3 100644
--- a/MediaBrowser.Controller/Net/IWebSocketConnection.cs
+++ b/MediaBrowser.Controller/Net/IWebSocketConnection.cs
@@ -77,5 +77,14 @@ namespace MediaBrowser.Controller.Net
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task ReceiveAsync(CancellationToken cancellationToken = default);
+
+ /// <summary>
+ /// Applies the culture context captured when the connection was established
+ /// (from the upgrade request's <c>Accept-Language</c> header) to the current
+ /// async flow. Server-initiated message senders should call this before
+ /// localising any payload so that the response uses the client's preferred
+ /// language rather than the server default.
+ /// </summary>
+ void ApplyRequestCulture();
}
}
diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs
index 0d3a334dfb..c87f09a117 100644
--- a/MediaBrowser.Controller/Providers/IProviderManager.cs
+++ b/MediaBrowser.Controller/Providers/IProviderManager.cs
@@ -144,6 +144,17 @@ namespace MediaBrowser.Controller.Providers
where T : BaseItem;
/// <summary>
+ /// Gets the metadata providers for the provided item.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="libraryOptions">The library options.</param>
+ /// <param name="includeDisabled">Whether to include disabled providers.</param>
+ /// <typeparam name="T">The type of metadata provider.</typeparam>
+ /// <returns>The metadata providers.</returns>
+ IEnumerable<IMetadataProvider<T>> GetMetadataProviders<T>(BaseItem item, LibraryOptions libraryOptions, bool includeDisabled)
+ where T : BaseItem;
+
+ /// <summary>
/// Gets the metadata savers for the provided item.
/// </summary>
/// <param name="item">The item.</param>