174 lines
6.5 KiB
C#
174 lines
6.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Jellyfin.Plugin.SRFPlay.Api;
|
|
using Jellyfin.Plugin.SRFPlay.Services.Interfaces;
|
|
using Jellyfin.Plugin.SRFPlay.Utilities;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace Jellyfin.Plugin.SRFPlay.Services;
|
|
|
|
/// <summary>
|
|
/// Service for refreshing content from SRF API.
|
|
/// </summary>
|
|
public class ContentRefreshService : IContentRefreshService
|
|
{
|
|
private readonly ILogger<ContentRefreshService> _logger;
|
|
private readonly ISRFApiClientFactory _apiClientFactory;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="ContentRefreshService"/> class.
|
|
/// </summary>
|
|
/// <param name="loggerFactory">The logger factory.</param>
|
|
/// <param name="apiClientFactory">The API client factory.</param>
|
|
public ContentRefreshService(
|
|
ILoggerFactory loggerFactory,
|
|
ISRFApiClientFactory apiClientFactory)
|
|
{
|
|
_logger = loggerFactory.CreateLogger<ContentRefreshService>();
|
|
_apiClientFactory = apiClientFactory;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Refreshes latest content from SRF API using Play v3.
|
|
/// </summary>
|
|
/// <param name="businessUnit">The business unit to fetch content for (e.g. "srf", "rts").</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <returns>List of URNs for new content.</returns>
|
|
public async Task<List<string>> RefreshLatestContentAsync(string businessUnit, CancellationToken cancellationToken)
|
|
{
|
|
var config = Plugin.Instance?.Configuration;
|
|
if (config == null || !config.EnableLatestContent)
|
|
{
|
|
_logger.LogDebug("Latest content refresh is disabled");
|
|
return new List<string>();
|
|
}
|
|
|
|
return await FetchVideosFromShowsAsync(
|
|
businessUnit,
|
|
minEpisodeCount: 0,
|
|
maxShows: 20,
|
|
videosPerShow: 1,
|
|
contentType: "latest",
|
|
cancellationToken).ConfigureAwait(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Refreshes trending content from SRF API using Play v3.
|
|
/// Gets videos from shows with the most episodes.
|
|
/// </summary>
|
|
/// <param name="businessUnit">The business unit to fetch content for (e.g. "srf", "rts").</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <returns>List of URNs for trending content.</returns>
|
|
public async Task<List<string>> RefreshTrendingContentAsync(string businessUnit, CancellationToken cancellationToken)
|
|
{
|
|
var config = Plugin.Instance?.Configuration;
|
|
if (config == null || !config.EnableTrendingContent)
|
|
{
|
|
_logger.LogDebug("Trending content refresh is disabled");
|
|
return new List<string>();
|
|
}
|
|
|
|
return await FetchVideosFromShowsAsync(
|
|
businessUnit,
|
|
minEpisodeCount: 10,
|
|
maxShows: 15,
|
|
videosPerShow: 2,
|
|
contentType: "trending",
|
|
cancellationToken).ConfigureAwait(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches videos from shows based on filter criteria.
|
|
/// </summary>
|
|
private async Task<List<string>> FetchVideosFromShowsAsync(
|
|
string businessUnit,
|
|
int minEpisodeCount,
|
|
int maxShows,
|
|
int videosPerShow,
|
|
string contentType,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var urns = new List<string>();
|
|
|
|
try
|
|
{
|
|
_logger.LogInformation("Refreshing {ContentType} content for business unit: {BusinessUnit}", contentType, businessUnit);
|
|
|
|
using var apiClient = _apiClientFactory.CreateClient();
|
|
var shows = await apiClient.GetAllShowsAsync(businessUnit, cancellationToken).ConfigureAwait(false);
|
|
|
|
if (shows == null || shows.Count == 0)
|
|
{
|
|
_logger.LogWarning("No shows found for business unit: {BusinessUnit}", businessUnit);
|
|
return urns;
|
|
}
|
|
|
|
_logger.LogInformation("Found {Count} shows, fetching {ContentType} content", shows.Count, contentType);
|
|
|
|
var filteredShows = shows
|
|
.Where(s => s.NumberOfEpisodes > minEpisodeCount)
|
|
.OrderByDescending(s => s.NumberOfEpisodes)
|
|
.Take(maxShows)
|
|
.ToList();
|
|
|
|
var now = DateTime.UtcNow;
|
|
|
|
foreach (var show in filteredShows)
|
|
{
|
|
if (show.Id == null || cancellationToken.IsCancellationRequested)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
try
|
|
{
|
|
var videos = await apiClient.GetVideosForShowAsync(businessUnit, show.Id, cancellationToken).ConfigureAwait(false);
|
|
if (videos == null || videos.Count == 0)
|
|
{
|
|
_logger.LogDebug("Show {Show} ({ShowId}): No videos returned from API", show.Title, show.Id);
|
|
continue;
|
|
}
|
|
|
|
_logger.LogDebug("Show {Show} ({ShowId}): Found {Count} videos", show.Title, show.Id, videos.Count);
|
|
|
|
// Filter to videos that are actually published (validFrom in the past)
|
|
var publishedVideos = videos
|
|
.Where(v => v.ValidFrom == null || v.ValidFrom.Value.ToUniversalTime() <= now)
|
|
.OrderByDescending(v => v.Date)
|
|
.Take(videosPerShow)
|
|
.ToList();
|
|
|
|
foreach (var video in publishedVideos)
|
|
{
|
|
if (video.Urn != null)
|
|
{
|
|
urns.Add(video.Urn);
|
|
_logger.LogDebug(
|
|
"Added {ContentType} video from show {Show}: {Title} (URN: {Urn})",
|
|
contentType,
|
|
show.Title,
|
|
video.Title,
|
|
video.Urn);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Error fetching videos for show {ShowId}", show.Id);
|
|
}
|
|
}
|
|
|
|
_logger.LogInformation("Refreshed {Count} {ContentType} content items from {ShowCount} shows", urns.Count, contentType, filteredShows.Count);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error refreshing {ContentType} content", contentType);
|
|
}
|
|
|
|
return urns;
|
|
}
|
|
}
|