Record coordinated reception results and prepare scoped web H264 option

This commit is contained in:
2026-10-12 23:57:10 +02:00
parent 5c10d8b9b8
commit a7e44efdf7
15 changed files with 12390 additions and 17 deletions
+41
View File
@@ -6,9 +6,17 @@ using System.Security.Claims;
using System.Text.Json.Nodes;
using System.Threading;
using System.Linq;
using Jellyfin.Data;
using Jellyfin.Database.Implementations.Entities;
using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Plugin.Enigma2.Configuration;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
var time=DateTime.UtcNow;
void Check(bool ok,string name){if(!ok)throw new Exception(name);Console.WriteLine("PASS "+name);}
@@ -23,6 +31,24 @@ Check(!InternetEpg.AllowedImage("https://ptv-prod.wphcdn.cloud.evil.example/a"),
Check(InternetEpg.AllowedImage(entry.Image),"real provider image");
var prefs=new ChannelPreferences{FavoriteIds=new[]{Guid.NewGuid().ToString(),"../other-user"},DefaultView="invalid"};prefs.Validate();
Check(prefs.FavoriteIds.Length==1 && prefs.DefaultView=="all","preference input validation");
var legacyConfiguration=(PluginConfiguration)new System.Xml.Serialization.XmlSerializer(typeof(PluginConfiguration)).Deserialize(new StringReader("<PluginConfiguration><HostName>receiver</HostName></PluginConfiguration>"));
Check(legacyConfiguration.PreferH264ForWebLiveTv,"legacy configuration defaults to web H264 preference");
var ownedChannel=new LiveTvChannel{Id=Guid.NewGuid(),ServiceName="Enigma2"};
var policy=WebPlaybackPolicy.For(ownedChannel,true);
Check(policy.IsEnigmaChannel&&policy.PreferH264,"web codec policy recognizes native Enigma service");
policy=WebPlaybackPolicy.For(ownedChannel,false);
Check(policy.IsEnigmaChannel&&!policy.PreferH264,"disabled web codec policy preserves native negotiation");
Check(!WebPlaybackPolicy.For(new LiveTvChannel{ServiceName="OtherProvider"},true).PreferH264&&!WebPlaybackPolicy.For(new Video{ServiceName="Enigma2"},true).PreferH264&&!WebPlaybackPolicy.For(null,true).PreferH264,"web codec policy excludes other providers, movies and missing items");
var policyUser=new User("policy-test","test-auth","test-reset");policyUser.SetPermission(PermissionKind.EnableLiveTvAccess,true);
var userManager=DispatchProxy.Create<IUserManager,PolicyUserProxy>();((PolicyUserProxy)(object)userManager).Current=policyUser;
var libraryManager=DispatchProxy.Create<ILibraryManager,PolicyLibraryProxy>();var libraryProxy=(PolicyLibraryProxy)(object)libraryManager;libraryProxy.Current=policyUser;libraryProxy.Item=ownedChannel;
var policyContext=new DefaultHttpContext();policyContext.User=new ClaimsPrincipal(new ClaimsIdentity(new[]{new Claim("Jellyfin-UserId",policyUser.Id.ToString())},"test"));policyContext.Request.QueryString=new QueryString("?userId="+Guid.NewGuid());
var policyController=new PreferencesController(null,null,null,null,libraryManager,userManager){ControllerContext=new ControllerContext{HttpContext=policyContext}};
Check(policyController.GetWebPlaybackPolicy(ownedChannel.Id).Value.IsEnigmaChannel&&libraryProxy.Calls==1,"web policy uses native user-filtered lookup for authenticated owner");
libraryProxy.Item=null;policy=policyController.GetWebPlaybackPolicy(ownedChannel.Id).Value;Check(!policy.IsEnigmaChannel&&!policy.PreferH264,"native visibility denial leaves web profile unchanged");
policyUser.SetPermission(PermissionKind.EnableLiveTvAccess,false);Check(policyController.GetWebPlaybackPolicy(ownedChannel.Id).Result is ForbidResult&&libraryProxy.Calls==2,"web policy denies user without live TV permission before item lookup");
((PolicyUserProxy)(object)userManager).Current=null;Check(policyController.GetWebPlaybackPolicy(ownedChannel.Id).Result is UnauthorizedResult&&libraryProxy.Calls==2,"web policy rejects deleted user without unrestricted native lookup");
policyContext.User=new ClaimsPrincipal();Check(policyController.GetWebPlaybackPolicy(ownedChannel.Id).Result is UnauthorizedResult,"web policy requires authenticated user claim");
var folder=Path.Combine(Path.GetTempPath(),"decoder-tests-"+Guid.NewGuid().ToString("N"));
var paths=DispatchProxy.Create<IApplicationPaths,PathsProxy>();((PathsProxy)(object)paths).Folder=folder;
try
@@ -101,6 +127,21 @@ public class PathsProxy : DispatchProxy
protected override object Invoke(MethodInfo method,object[] args)=>(method.Name=="get_DataPath" || method.Name=="get_PluginConfigurationsPath")?Folder:null;
}
public class PolicyUserProxy : DispatchProxy
{
public User Current;
protected override object Invoke(MethodInfo method,object[] args) => method.Name=="GetUserById"&&Current!=null&&(Guid)args[0]==Current.Id?Current:null;
}
public class PolicyLibraryProxy : DispatchProxy
{
public User Current;public BaseItem Item;public int Calls;
protected override object Invoke(MethodInfo method,object[] args)
{
if(method.Name!="GetItemById"||args.Length!=2||!ReferenceEquals(args[1],Current))throw new Exception("Expected native item lookup using authenticated User");
Calls++;return Item;
}
}
public class RelayHandler : System.Net.Http.HttpMessageHandler
{
public int Calls;