mirror of
https://github.com/MrSleeps/jellyfin-scene-search.git
synced 2026-11-14 22:11:27 +00:00
Proxy index controls through Jellyfin plugin
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Jellyfin.Plugin.SceneSearch.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
@@ -19,9 +21,6 @@ public sealed class SceneSearchClient : IDisposable
|
||||
_httpClient = new HttpClient();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether enough configuration exists to search.
|
||||
/// </summary>
|
||||
public bool IsConfigured
|
||||
{
|
||||
get
|
||||
@@ -35,9 +34,6 @@ public sealed class SceneSearchClient : IDisposable
|
||||
private static PluginConfiguration Configuration
|
||||
=> Plugin.Instance?.Configuration ?? new PluginConfiguration();
|
||||
|
||||
/// <summary>
|
||||
/// Searches the local scene-search API.
|
||||
/// </summary>
|
||||
internal async Task<IReadOnlyList<SceneSearchItem>> SearchAsync(
|
||||
string searchTerm,
|
||||
int limit,
|
||||
@@ -50,8 +46,7 @@ public sealed class SceneSearchClient : IDisposable
|
||||
}
|
||||
|
||||
var safeLimit = Math.Clamp(limit, 1, Math.Clamp(config.MaxResults, 1, 50));
|
||||
var requestUri = string.Concat(
|
||||
config.ApiUrl.TrimEnd('/'),
|
||||
var path = string.Concat(
|
||||
"/api/search?q=",
|
||||
Uri.EscapeDataString(searchTerm),
|
||||
"&scene_limit=",
|
||||
@@ -59,7 +54,58 @@ public sealed class SceneSearchClient : IDisposable
|
||||
"&item_limit=",
|
||||
safeLimit.ToString(System.Globalization.CultureInfo.InvariantCulture));
|
||||
|
||||
using var request = new HttpRequestMessage(HttpMethod.Get, requestUri);
|
||||
var payload = await SendAsync<SceneSearchResponse>(
|
||||
HttpMethod.Get,
|
||||
path,
|
||||
content: null,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return payload?.Items ?? [];
|
||||
}
|
||||
|
||||
public Task<SceneSearchLibraryListResponse?> GetLibrariesAsync(
|
||||
CancellationToken cancellationToken)
|
||||
=> SendAsync<SceneSearchLibraryListResponse>(
|
||||
HttpMethod.Get,
|
||||
"/api/jellyfin/libraries",
|
||||
content: null,
|
||||
cancellationToken);
|
||||
|
||||
public Task<SceneSearchIndexStatus?> StartIndexAsync(
|
||||
SceneSearchIndexRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
=> SendAsync<SceneSearchIndexStatus>(
|
||||
HttpMethod.Post,
|
||||
"/api/jellyfin/index",
|
||||
JsonContent.Create(request),
|
||||
cancellationToken);
|
||||
|
||||
public Task<SceneSearchIndexStatus?> GetIndexStatusAsync(
|
||||
CancellationToken cancellationToken)
|
||||
=> SendAsync<SceneSearchIndexStatus>(
|
||||
HttpMethod.Get,
|
||||
"/api/jellyfin/index/status",
|
||||
content: null,
|
||||
cancellationToken);
|
||||
|
||||
private async Task<T?> SendAsync<T>(
|
||||
HttpMethod method,
|
||||
string path,
|
||||
HttpContent? content,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var config = Configuration;
|
||||
if (string.IsNullOrWhiteSpace(config.ApiUrl))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
using var request = new HttpRequestMessage(
|
||||
method,
|
||||
config.ApiUrl.TrimEnd('/') + path)
|
||||
{
|
||||
Content = content
|
||||
};
|
||||
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(config.ApiKey))
|
||||
@@ -79,30 +125,26 @@ public sealed class SceneSearchClient : IDisposable
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
_logger.LogWarning(
|
||||
"Scene Search API returned HTTP {StatusCode} for '{SearchTerm}'",
|
||||
(int)response.StatusCode,
|
||||
searchTerm);
|
||||
return [];
|
||||
var body = await response.Content.ReadAsStringAsync(timeout.Token).ConfigureAwait(false);
|
||||
throw new HttpRequestException(
|
||||
$"Scene Search API returned HTTP {(int)response.StatusCode}: {body}");
|
||||
}
|
||||
|
||||
var payload = await response.Content.ReadFromJsonAsync<SceneSearchResponse>(
|
||||
return await response.Content.ReadFromJsonAsync<T>(
|
||||
cancellationToken: timeout.Token).ConfigureAwait(false);
|
||||
|
||||
return payload?.Items ?? [];
|
||||
}
|
||||
catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
_logger.LogWarning(
|
||||
"Scene Search API timed out after {TimeoutSeconds}s for '{SearchTerm}'",
|
||||
"Scene Search API timed out after {TimeoutSeconds}s for {Path}",
|
||||
config.TimeoutSeconds,
|
||||
searchTerm);
|
||||
return [];
|
||||
path);
|
||||
return default;
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Scene Search API request failed for '{SearchTerm}'", searchTerm);
|
||||
return [];
|
||||
_logger.LogWarning(ex, "Scene Search API request failed for {Path}", path);
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user