Integrate native decoder TV and internet EPG artwork with Jellyfin 12.2
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.IO;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Jellyfin.Plugin.Enigma2;
|
||||
|
||||
/// <summary>Apply presentation preferences after the native API has enforced access rights.</summary>
|
||||
public sealed class NativeChannelFilter : IStartupFilter
|
||||
{
|
||||
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next) => app =>
|
||||
{
|
||||
app.Use(async (context, continuePipeline) =>
|
||||
{
|
||||
if (!HttpMethods.IsGet(context.Request.Method) ||
|
||||
!context.Request.Path.Value.TrimEnd('/').Equals("/LiveTv/Channels",StringComparison.OrdinalIgnoreCase))
|
||||
{ await continuePipeline(); return; }
|
||||
var originalQuery=context.Request.QueryString;
|
||||
var originalEncoding=context.Request.Headers.AcceptEncoding;
|
||||
// Buffer JSON before applying preferences; compression must not run inside this buffer.
|
||||
context.Request.Headers.Remove("Accept-Encoding");
|
||||
var parsed=QueryHelpers.ParseQuery(originalQuery.Value ?? "");
|
||||
int Number(string name,int fallback) => parsed.TryGetValue(name,out var value) && int.TryParse(value,out var number) && number>=0 ? number : fallback;
|
||||
var start=Number("StartIndex",0);var limit=Number("Limit",int.MaxValue);
|
||||
// Fetch the permission-filtered full result, then paginate after preferences.
|
||||
context.Request.QueryString=QueryString.Create(parsed.Where(p=>!p.Key.Equals("StartIndex",StringComparison.OrdinalIgnoreCase)&&!p.Key.Equals("Limit",StringComparison.OrdinalIgnoreCase)));
|
||||
var originalBody=context.Response.Body;
|
||||
await using var buffer=new MemoryStream();context.Response.Body=buffer;
|
||||
try
|
||||
{
|
||||
await continuePipeline();
|
||||
context.Response.Body=originalBody;
|
||||
if (context.Response.StatusCode==200 && context.Response.ContentType?.StartsWith("application/json",StringComparison.OrdinalIgnoreCase)==true)
|
||||
{
|
||||
buffer.Position=0;
|
||||
var document=await JsonNode.ParseAsync(buffer,cancellationToken:context.RequestAborted);
|
||||
if(document?["Items"] is JsonArray items)
|
||||
{
|
||||
Guid.TryParse(context.User.FindFirst("Jellyfin-UserId")?.Value,out var userId);
|
||||
if(userId==Guid.Empty && parsed.TryGetValue("UserId",out var requested)&&Guid.TryParse(requested,out var requestedId)) userId=requestedId;
|
||||
var preferences=userId==Guid.Empty?new ChannelPreferences():await context.RequestServices.GetRequiredService<PreferencesStore>().Load(userId,context.RequestAborted);
|
||||
var hidden=preferences.HiddenIds.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||
var includeHidden=parsed.TryGetValue("DecoderIncludeHidden",out var includeValue)&&bool.TryParse(includeValue,out var include)&&include;
|
||||
var order=preferences.OrderedIds.Select((id,index)=>(id,index)).ToDictionary(x=>x.id,x=>x.index,StringComparer.OrdinalIgnoreCase);
|
||||
string Id(JsonNode node) => Guid.TryParse((string)node?["Id"],out var id)?id.ToString("N"):"";
|
||||
var filtered=items.Where(item=>includeHidden||!hidden.Contains(Id(item))).OrderBy(item=>order.TryGetValue(Id(item),out var position)?position:int.MaxValue).ToArray();
|
||||
document["TotalRecordCount"]=filtered.Length;
|
||||
document["StartIndex"]=start;
|
||||
document["Items"]=new JsonArray(filtered.Skip(start).Take(limit).Select(item=>item.DeepClone()).ToArray());
|
||||
context.Response.ContentLength=null;
|
||||
await context.Response.WriteAsync(document.ToJsonString(),context.RequestAborted);
|
||||
return;
|
||||
}
|
||||
}
|
||||
buffer.Position=0;await buffer.CopyToAsync(originalBody,context.RequestAborted);
|
||||
}
|
||||
finally { context.Response.Body=originalBody;context.Request.QueryString=originalQuery;context.Request.Headers.AcceptEncoding=originalEncoding; }
|
||||
});
|
||||
next(app);
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user