using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Jellyfin.Plugin.SRFPlay.Api; using Jellyfin.Plugin.SRFPlay.Services; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Providers; using Microsoft.Extensions.Logging; namespace Jellyfin.Plugin.SRFPlay.Providers; /// /// Provides metadata for SRF Play series/shows. /// public class SRFSeriesProvider : IRemoteMetadataProvider { private readonly ILogger _logger; private readonly ILoggerFactory _loggerFactory; private readonly IHttpClientFactory _httpClientFactory; private readonly MetadataCache _metadataCache; /// /// Initializes a new instance of the class. /// /// The logger instance. /// The logger factory. /// The HTTP client factory. /// The metadata cache. public SRFSeriesProvider( ILogger logger, ILoggerFactory loggerFactory, IHttpClientFactory httpClientFactory, MetadataCache metadataCache) { _logger = logger; _loggerFactory = loggerFactory; _httpClientFactory = httpClientFactory; _metadataCache = metadataCache; } /// public string Name => "SRF Play"; /// public async Task> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellationToken) { var results = new List(); try { // Check if we have a URN to search with if (searchInfo.ProviderIds.TryGetValue("SRF", out var urn) && !string.IsNullOrEmpty(urn)) { _logger.LogDebug("Searching for series with URN: {Urn}", urn); var config = Plugin.Instance?.Configuration; if (config == null) { return results; } // Try cache first var mediaComposition = _metadataCache.GetMediaComposition(urn, config.CacheDurationMinutes); // If not in cache, fetch from API if (mediaComposition == null) { using var apiClient = new SRFApiClient(_loggerFactory); mediaComposition = await apiClient.GetMediaCompositionByUrnAsync(urn, cancellationToken).ConfigureAwait(false); if (mediaComposition != null) { _metadataCache.SetMediaComposition(urn, mediaComposition); } } if (mediaComposition?.Show != null) { var show = mediaComposition.Show; results.Add(new RemoteSearchResult { Name = show.Title, Overview = show.Description ?? show.Lead, ImageUrl = show.ImageUrl, SearchProviderName = Name, ProviderIds = new Dictionary { { "SRF", show.Urn ?? urn } } }); } } else if (!string.IsNullOrEmpty(searchInfo.Name)) { _logger.LogDebug("Name-based search not yet implemented for: {Name}", searchInfo.Name); // TODO: Implement name-based search when SRF provides search API } } catch (Exception ex) { _logger.LogError(ex, "Error searching for series: {Name}", searchInfo.Name); } return results; } /// public async Task> GetMetadata(SeriesInfo info, CancellationToken cancellationToken) { var result = new MetadataResult(); try { // Check if we have a URN if (!info.ProviderIds.TryGetValue("SRF", out var urn) || string.IsNullOrEmpty(urn)) { _logger.LogDebug("No SRF URN found for series: {Name}", info.Name); return result; } _logger.LogDebug("Fetching metadata for series URN: {Urn}", urn); var config = Plugin.Instance?.Configuration; if (config == null) { return result; } // Try cache first var mediaComposition = _metadataCache.GetMediaComposition(urn, config.CacheDurationMinutes); // If not in cache, fetch from API if (mediaComposition == null) { using var apiClient = new SRFApiClient(_loggerFactory); mediaComposition = await apiClient.GetMediaCompositionByUrnAsync(urn, cancellationToken).ConfigureAwait(false); if (mediaComposition != null) { _metadataCache.SetMediaComposition(urn, mediaComposition); } } if (mediaComposition?.Show == null) { _logger.LogWarning("No show information found for URN: {Urn}", urn); return result; } var show = mediaComposition.Show; result.Item = new Series { Name = show.Title, Overview = show.Description ?? show.Lead, ProviderIds = new Dictionary { { "SRF", show.Urn ?? urn } } }; // Set additional metadata if available if (!string.IsNullOrEmpty(show.Vendor)) { result.Item.Studios = new[] { show.Vendor }; } result.HasMetadata = true; _logger.LogDebug("Successfully fetched metadata for series: {Title}", show.Title); } catch (Exception ex) { _logger.LogError(ex, "Error fetching metadata for series: {Name}", info.Name); } return result; } /// public Task GetImageResponse(string url, CancellationToken cancellationToken) { throw new NotImplementedException("Image handling is done by SRFImageProvider"); } }