Remove 9 dead methods, 6 unused constants, and redundant ReaderWriterLockSlim from MetadataCache. Consolidate repeated patterns into HasChapters, IsPlayable, and ToLowerString helpers. Extract shared API methods in SRFApiClient. Move variant manifest rewriting from controller to StreamProxyService. Make Auto quality distinct from HD. Update README architecture section.
221 lines
9.7 KiB
C#
221 lines
9.7 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Jellyfin.Plugin.SRFPlay.Api;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace Jellyfin.Plugin.SRFPlay.Tests
|
|
{
|
|
public class TestPlayV3Api
|
|
{
|
|
public static async Task RunTests()
|
|
{
|
|
Console.WriteLine("=== Play v3 API Test Suite ===\n");
|
|
|
|
using var loggerFactory = LoggerFactory.Create(builder =>
|
|
{
|
|
builder.AddConsole();
|
|
builder.SetMinimumLevel(LogLevel.Warning);
|
|
});
|
|
|
|
var apiClient = new SRFApiClient(loggerFactory);
|
|
var cancellationToken = CancellationToken.None;
|
|
|
|
// Test 1: Get all shows
|
|
Console.WriteLine("[Test 1] Fetch All Shows");
|
|
Console.WriteLine("------------------------");
|
|
try
|
|
{
|
|
var shows = await apiClient.GetAllShowsAsync("srf", cancellationToken);
|
|
if (shows != null && shows.Any())
|
|
{
|
|
Console.WriteLine($"✓ Successfully fetched {shows.Count} shows");
|
|
Console.WriteLine($" First show: {shows[0]?.Title} ({shows[0]?.NumberOfEpisodes} episodes)");
|
|
Console.WriteLine($" Show ID: {shows[0]?.Id}");
|
|
Console.WriteLine($" URN: {shows[0]?.Urn}");
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("✗ Failed: No shows returned");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"✗ Error: {ex.Message}");
|
|
}
|
|
Console.WriteLine();
|
|
|
|
// Test 2: Get videos for a show
|
|
Console.WriteLine("[Test 2] Fetch Videos for a Show");
|
|
Console.WriteLine("--------------------------------");
|
|
try
|
|
{
|
|
var shows = await apiClient.GetAllShowsAsync("srf", cancellationToken);
|
|
if (shows != null && shows.Any())
|
|
{
|
|
// Find a show with episodes
|
|
var showWithEpisodes = shows.FirstOrDefault(s => s.NumberOfEpisodes > 0);
|
|
if (showWithEpisodes != null && showWithEpisodes.Id != null)
|
|
{
|
|
Console.WriteLine($"Testing with show: {showWithEpisodes.Title}");
|
|
|
|
var videos = await apiClient.GetVideosForShowAsync("srf", showWithEpisodes.Id, cancellationToken);
|
|
if (videos != null && videos.Any())
|
|
{
|
|
Console.WriteLine($"✓ Successfully fetched {videos.Count} videos");
|
|
var firstVideo = videos[0];
|
|
Console.WriteLine($" First video: {firstVideo?.Title}");
|
|
Console.WriteLine($" URN: {firstVideo?.Urn}");
|
|
Console.WriteLine($" Duration: {firstVideo?.Duration / 1000}s");
|
|
Console.WriteLine($" Date: {firstVideo?.Date}");
|
|
Console.WriteLine($" Playable abroad: {firstVideo?.PlayableAbroad}");
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("✗ Failed: No videos returned");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("✗ Failed: No shows with episodes found");
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"✗ Error: {ex.Message}");
|
|
}
|
|
Console.WriteLine();
|
|
|
|
// Test 3: Get video stream URL using Integration Layer
|
|
Console.WriteLine("[Test 3] Get Stream URL for Video");
|
|
Console.WriteLine("---------------------------------");
|
|
try
|
|
{
|
|
var shows = await apiClient.GetAllShowsAsync("srf", cancellationToken);
|
|
if (shows != null && shows.Any())
|
|
{
|
|
var showWithEpisodes = shows.FirstOrDefault(s => s.NumberOfEpisodes > 0);
|
|
if (showWithEpisodes != null && showWithEpisodes.Id != null)
|
|
{
|
|
var videos = await apiClient.GetVideosForShowAsync("srf", showWithEpisodes.Id, cancellationToken);
|
|
if (videos != null && videos.Any())
|
|
{
|
|
var video = videos[0];
|
|
if (video.Urn != null)
|
|
{
|
|
Console.WriteLine($"Fetching stream for: {video.Title}");
|
|
|
|
// Use Integration Layer 2.0 to get stream URL
|
|
var mediaComposition = await apiClient.GetMediaCompositionByUrnAsync(video.Urn, cancellationToken);
|
|
if (mediaComposition?.ChapterList != null && mediaComposition.ChapterList.Any())
|
|
{
|
|
var chapter = mediaComposition.ChapterList[0];
|
|
if (chapter.ResourceList != null && chapter.ResourceList.Any())
|
|
{
|
|
var hlsResource = chapter.ResourceList.FirstOrDefault(r =>
|
|
r.Protocol == "HLS" && r.IsPlayable);
|
|
|
|
if (hlsResource != null)
|
|
{
|
|
Console.WriteLine($"✓ Stream URL found:");
|
|
Console.WriteLine($" URL: {hlsResource.Url?.Substring(0, Math.Min(80, hlsResource.Url?.Length ?? 0))}...");
|
|
Console.WriteLine($" Quality: {hlsResource.Quality}");
|
|
Console.WriteLine($" Protocol: {hlsResource.Protocol}");
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("✗ No HLS stream without DRM found");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("✗ No resources found");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("✗ Failed to fetch media composition");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"✗ Error: {ex.Message}");
|
|
}
|
|
Console.WriteLine();
|
|
|
|
// Test 4: Check multiple shows
|
|
Console.WriteLine("[Test 4] Check Multiple Shows");
|
|
Console.WriteLine("----------------------------");
|
|
try
|
|
{
|
|
var shows = await apiClient.GetAllShowsAsync("srf", cancellationToken);
|
|
if (shows != null)
|
|
{
|
|
var showsWithEpisodes = shows.Where(s => s.NumberOfEpisodes > 0).Take(10).ToList();
|
|
Console.WriteLine($"Checking {showsWithEpisodes.Count} shows with episodes...\n");
|
|
|
|
int successCount = 0;
|
|
foreach (var show in showsWithEpisodes)
|
|
{
|
|
if (show.Id != null)
|
|
{
|
|
var videos = await apiClient.GetVideosForShowAsync("srf", show.Id, cancellationToken);
|
|
if (videos != null && videos.Any())
|
|
{
|
|
Console.WriteLine($"✓ {show.Title}: {videos.Count} videos available");
|
|
successCount++;
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine($"✗ {show.Title}: No videos found");
|
|
}
|
|
}
|
|
}
|
|
|
|
Console.WriteLine();
|
|
Console.WriteLine($"Summary: {successCount}/{showsWithEpisodes.Count} shows successfully fetched videos");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"✗ Error: {ex.Message}");
|
|
}
|
|
Console.WriteLine();
|
|
|
|
// Test 5: Test all business units
|
|
Console.WriteLine("[Test 5] Test All Business Units");
|
|
Console.WriteLine("--------------------------------");
|
|
var businessUnits = new[] { "srf", "rts", "rsi", "rtr", "swi" };
|
|
|
|
foreach (var bu in businessUnits)
|
|
{
|
|
try
|
|
{
|
|
var shows = await apiClient.GetAllShowsAsync(bu, cancellationToken);
|
|
if (shows != null && shows.Any())
|
|
{
|
|
Console.WriteLine($"✓ {bu.ToUpper()}: {shows.Count} shows available");
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine($"✗ {bu.ToUpper()}: No shows found");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"✗ {bu.ToUpper()}: Error - {ex.Message}");
|
|
}
|
|
}
|
|
Console.WriteLine();
|
|
|
|
Console.WriteLine("=== Test Suite Complete ===");
|
|
}
|
|
}
|
|
}
|