Resolve saved native channel references after receiver migrations
This commit is contained in:
@@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using MediaBrowser.Controller.LiveTv;
|
||||||
|
|
||||||
|
namespace Jellyfin.Plugin.Enigma2;
|
||||||
|
|
||||||
|
/// <summary>Keep saved native channels playable after a receiver bouquet migration.</summary>
|
||||||
|
public static class ChannelReferenceResolver
|
||||||
|
{
|
||||||
|
public static string Resolve(string reference, IEnumerable<ChannelInfo> channels, Func<string> previousName)
|
||||||
|
{
|
||||||
|
var current = channels.Where(c => !string.IsNullOrWhiteSpace(c.Id)).ToArray();
|
||||||
|
var exact = current.FirstOrDefault(c => string.Equals(c.Id, reference, StringComparison.OrdinalIgnoreCase));
|
||||||
|
if (exact != null) return exact.Id;
|
||||||
|
|
||||||
|
// A changed Enigma service type does not change the DVB service identity.
|
||||||
|
var identity = Identity(reference);
|
||||||
|
var matches = current.Where(c => identity != null && Identity(c.Id) == identity)
|
||||||
|
.Select(c => c.Id).Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
|
||||||
|
if (matches.Length == 1) return matches[0];
|
||||||
|
if (matches.Length > 1) return reference;
|
||||||
|
|
||||||
|
// A moved service has a new SID/TSID. Use only a unique exact historical
|
||||||
|
// name; never guess between HD/SD, regional or alternative services.
|
||||||
|
var name = previousName()?.Trim();
|
||||||
|
if (string.IsNullOrEmpty(name)) return reference;
|
||||||
|
matches = current.Where(c => string.Equals(c.Name?.Trim(), name, StringComparison.OrdinalIgnoreCase))
|
||||||
|
.Select(c => c.Id).Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
|
||||||
|
return matches.Length == 1 ? matches[0] : reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string Identity(string reference)
|
||||||
|
{
|
||||||
|
var fields = reference?.TrimEnd(':').Split(':');
|
||||||
|
if (fields == null || fields.Length != 10 || fields[0] != "1" || fields[1] != "0") return null;
|
||||||
|
// No URLs, labels or non-DVB references participate in this fallback.
|
||||||
|
if (fields.Any(f => f.Length == 0 || !f.All(Uri.IsHexDigit))) return null;
|
||||||
|
fields[2] = "";
|
||||||
|
return string.Join(':', fields).ToUpperInvariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net10.0</TargetFrameworks>
|
<TargetFrameworks>net10.0</TargetFrameworks>
|
||||||
<AssemblyVersion>7.0.8.0</AssemblyVersion>
|
<AssemblyVersion>7.0.9.0</AssemblyVersion>
|
||||||
<FileVersion>7.0.8.0</FileVersion>
|
<FileVersion>7.0.9.0</FileVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net6.0|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net6.0|AnyCPU'">
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ using MediaBrowser.Common.Extensions;
|
|||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.LiveTv;
|
using MediaBrowser.Controller.LiveTv;
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.LiveTv;
|
using MediaBrowser.Model.LiveTv;
|
||||||
@@ -32,6 +35,7 @@ namespace Jellyfin.Plugin.Enigma2
|
|||||||
private int _liveStreams;
|
private int _liveStreams;
|
||||||
private readonly LiveStreamProbe _streamProbe;
|
private readonly LiveStreamProbe _streamProbe;
|
||||||
private readonly LiveStreamRelay _streamRelay;
|
private readonly LiveStreamRelay _streamRelay;
|
||||||
|
private readonly ILibraryManager _library;
|
||||||
|
|
||||||
private string tvBouquetSRef;
|
private string tvBouquetSRef;
|
||||||
private List<ChannelInfo> tvChannelInfos = new List<ChannelInfo>();
|
private List<ChannelInfo> tvChannelInfos = new List<ChannelInfo>();
|
||||||
@@ -42,12 +46,13 @@ namespace Jellyfin.Plugin.Enigma2
|
|||||||
|
|
||||||
public static LiveTvService Instance { get; private set; }
|
public static LiveTvService Instance { get; private set; }
|
||||||
|
|
||||||
public LiveTvService(ILogger<LiveTvService> logger, IHttpClientFactory httpClientFactory, InternetEpg internetEpg, LiveStreamProbe streamProbe, LiveStreamRelay streamRelay)
|
public LiveTvService(ILogger<LiveTvService> logger, IHttpClientFactory httpClientFactory, InternetEpg internetEpg, LiveStreamProbe streamProbe, LiveStreamRelay streamRelay, ILibraryManager library)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_httpClientFactory = httpClientFactory;
|
_httpClientFactory = httpClientFactory;
|
||||||
_streamProbe = streamProbe;
|
_streamProbe = streamProbe;
|
||||||
_streamRelay = streamRelay;
|
_streamRelay = streamRelay;
|
||||||
|
_library = library;
|
||||||
Instance = this;
|
Instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1139,6 +1144,26 @@ namespace Jellyfin.Plugin.Enigma2
|
|||||||
{
|
{
|
||||||
_logger.LogInformation("[Enigma2] Start GetChannelStream");
|
_logger.LogInformation("[Enigma2] Start GetChannelStream");
|
||||||
|
|
||||||
|
var requestedReference = channelOid;
|
||||||
|
var currentChannels = await GetChannelsAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
channelOid = ChannelReferenceResolver.Resolve(channelOid, currentChannels, () =>
|
||||||
|
{
|
||||||
|
// Native playback has already checked the user's channel access.
|
||||||
|
// This internal lookup reads only Enigma2 channel metadata and
|
||||||
|
// does not expose items or alter the user's native channel ID.
|
||||||
|
var names = _library.GetItemList(new InternalItemsQuery
|
||||||
|
{
|
||||||
|
IncludeItemTypes = new[] { BaseItemKind.LiveTvChannel }
|
||||||
|
}).OfType<LiveTvChannel>()
|
||||||
|
.Where(c => string.Equals(c.ServiceName, "Enigma2", StringComparison.OrdinalIgnoreCase)
|
||||||
|
&& string.Equals(c.ExternalId, requestedReference, StringComparison.OrdinalIgnoreCase))
|
||||||
|
.Select(c => c.Name).Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
|
||||||
|
return names.Length == 1 ? names[0] : null;
|
||||||
|
});
|
||||||
|
if (!string.Equals(channelOid, requestedReference, StringComparison.OrdinalIgnoreCase))
|
||||||
|
_logger.LogInformation("[Enigma2] Resolved saved channel reference {PreviousReference} to current bouquet reference {CurrentReference}", requestedReference, channelOid);
|
||||||
|
|
||||||
var protocol = "http";
|
var protocol = "http";
|
||||||
if (Plugin.Instance.Configuration.UseSecureHTTPSForStreams)
|
if (Plugin.Instance.Configuration.UseSecureHTTPSForStreams)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -63,3 +63,10 @@ Plugin Debugging
|
|||||||
## Local Jellyfin 10.11 integration
|
## Local Jellyfin 10.11 integration
|
||||||
See [integration changes and deployment](README.integration.md). Internet EPG artwork, native channel preferences, optional Vu+ recordings provider; local version 6.1.0.0.
|
See [integration changes and deployment](README.integration.md). Internet EPG artwork, native channel preferences, optional Vu+ recordings provider; local version 6.1.0.0.
|
||||||
|
|
||||||
|
## Kandydat 7.0.9 — stare wpisy kanałów po migracji, 23.10.2026
|
||||||
|
|
||||||
|
Odczyt metadanych LiveTvChannel potwierdził stare i nowe wpisy Pulsu/Pulsu 2 oraz stare wpisy WP i TVN24 po zmianie bukietów dekodera. GetChannelStream odświeża listę z dekodera i rozwiązuje zapamiętaną referencję przed zapem, rejestracją relay i wyznaczeniem SID do probe. Najpierw zachowuje dokładny aktualny wpis; potem dopuszcza jednoznaczną zmianę samego typu usługi DVB; migrację SID/TSID rozpoznaje tylko po unikalnej dokładnej nazwie odczytanej z historycznego kanału Enigma2. Brak dopasowania lub niejednoznaczność zachowuje poprzednie zachowanie. Nie zgadujemy HD/SD ani wariantów regionalnych. Natywny identyfikator kanału i preferencje użytkownika pozostają zachowane. Stary i nowy wpis wskazują ten sam adres relay, więc nie otwierają dwóch źródeł.
|
||||||
|
|
||||||
|
100 kontroli .NET10 przeszło, w tym rzeczywiste GetChannelStream z atrapą OpenWebif i natywnej biblioteki: nowy SID 5105, wspólne metadane i jedno połączenie relay dla starego/nowego Pulsu, anulowanie bez dodatkowego połączenia. Build Release: 0 ostrzeżeń, 0 błędów. Restore korzystał z cache pakietów bez sieci; NuGetAudit wyłączono jedynie dla tego odtworzenia offline. Nie potwierdza to odbioru na zalogowanym urządzeniu.
|
||||||
|
|
||||||
|
Status na moment zapisu: **7.0.9 przygotowana, niewdrożona**. W produkcji pozostaje 7.0.8. Nowa sesja Wydarzeń 24 rozpoczęta o 16:21:45 UTC dała poprawne serwerowe HLS (248 klatek 1080p / 9,88 s oraz 10,027 s audio). Restart wymagany do podmiany DLL czeka na zgodę dotyczącą tej aktywnej sesji. Osobny brak odkodowanego wyjścia CANAL+4K wymaga diagnostyki źródła ECM i nie jest naprawiany przez ten resolver. Nie zmieniono ustawień Jellyfina, wrapperów, plików Web ani konfiguracji dekodera.
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using System;
|
||||||
|
using Jellyfin.Plugin.Enigma2;
|
||||||
|
using MediaBrowser.Controller.LiveTv;
|
||||||
|
|
||||||
|
public static class ChannelReferenceTests
|
||||||
|
{
|
||||||
|
public static void Run(Action<bool,string> check)
|
||||||
|
{
|
||||||
|
const string oldPuls = "1:0:1:3D66:2C88:13E:820000:0:0:0:";
|
||||||
|
const string newPuls = "1:0:1:13F1:5DC:13E:820000:0:0:0:";
|
||||||
|
const string oldTvn = "1:0:1:3DD2:640:13E:820000:0:0:0:";
|
||||||
|
const string newTvn = "1:0:19:3DD2:640:13E:820000:0:0:0:";
|
||||||
|
var channels = new[] { new ChannelInfo { Id=newPuls, Name="TV PULS HD" }, new ChannelInfo { Id=newTvn, Name="TVN24 HD" } };
|
||||||
|
check(ChannelReferenceResolver.Resolve(newPuls,channels,()=>throw new Exception("Unnecessary library lookup"))==newPuls,"current channel uses its exact reference without historical lookup");
|
||||||
|
check(ChannelReferenceResolver.Resolve(oldTvn,channels,()=>throw new Exception("Unnecessary library lookup"))==newTvn,"saved TVN24 reference resolves changed service type");
|
||||||
|
check(ChannelReferenceResolver.Resolve(oldPuls,channels,()=>"TV PULS HD")==newPuls,"saved Puls reference resolves migrated SID and transponder");
|
||||||
|
check(ChannelReferenceResolver.Resolve(oldPuls,channels,()=>"tv puls hd ")==newPuls,"historical name matches case and surrounding whitespace only");
|
||||||
|
check(ChannelReferenceResolver.Resolve(oldPuls,channels,()=>"TV PULS")==oldPuls,"HD and SD names are not guessed");
|
||||||
|
check(ChannelReferenceResolver.Resolve(oldPuls,channels,()=>null)==oldPuls,"unknown historical name preserves original service");
|
||||||
|
var duplicate = new[] { channels[0], channels[0] };
|
||||||
|
check(ChannelReferenceResolver.Resolve(oldPuls,duplicate,()=>"TV PULS HD")==newPuls,"same reference in two bouquets is not ambiguous");
|
||||||
|
var ambiguous = new[] { channels[0], new ChannelInfo { Id=oldTvn, Name="TV PULS HD" } };
|
||||||
|
check(ChannelReferenceResolver.Resolve(oldPuls,ambiguous,()=>"TV PULS HD")==oldPuls,"different services with the same name are not guessed");
|
||||||
|
var types = new[] { channels[1], new ChannelInfo { Id="1:0:1F:3DD2:640:13E:820000:0:0:0:",Name="TVN24 HD" } };
|
||||||
|
check(ChannelReferenceResolver.Resolve(oldTvn,types,()=>throw new Exception("Ambiguous identity must not fall back"))==oldTvn,"ambiguous DVB identity cannot select arbitrary service type");
|
||||||
|
var presentOld = new[] { channels[0], new ChannelInfo { Id=oldPuls,Name="TV PULS HD" } };
|
||||||
|
check(ChannelReferenceResolver.Resolve(oldPuls,presentOld,()=>throw new Exception("Exact reference wins"))==oldPuls,"reference still present in bouquet wins over same-name alternative");
|
||||||
|
check(ChannelReferenceResolver.Resolve(oldTvn,Array.Empty<ChannelInfo>(),()=>"TVN24 HD")==oldTvn,"empty bouquet cannot redirect a saved channel");
|
||||||
|
const string nonDvb = "4097:0:1:3DD2:640:13E:820000:0:0:0:";
|
||||||
|
check(ChannelReferenceResolver.Resolve(nonDvb,channels,()=>null)==nonDvb,"non-DVB reference cannot use service-type fallback");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
var time=DateTime.UtcNow;
|
var time=DateTime.UtcNow;
|
||||||
void Check(bool ok,string name){if(!ok)throw new Exception(name);Console.WriteLine("PASS "+name);}
|
void Check(bool ok,string name){if(!ok)throw new Exception(name);Console.WriteLine("PASS "+name);}
|
||||||
|
ChannelReferenceTests.Run(Check);
|
||||||
var entry=new InternetEpg.Entry("Barwy szczęścia",time,"https://ptv-prod.wphcdn.cloud/media/a.jpg");
|
var entry=new InternetEpg.Entry("Barwy szczęścia",time,"https://ptv-prod.wphcdn.cloud/media/a.jpg");
|
||||||
Check(InternetEpg.Match(new[]{entry},"Barwy szczęścia",time.AddMinutes(5))==entry,"matching channel programme time");
|
Check(InternetEpg.Match(new[]{entry},"Barwy szczęścia",time.AddMinutes(5))==entry,"matching channel programme time");
|
||||||
Check(InternetEpg.Match(new[]{entry},"Inny program",time)==null,"reject different title");
|
Check(InternetEpg.Match(new[]{entry},"Inny program",time)==null,"reject different title");
|
||||||
@@ -123,6 +124,7 @@ using(var relay=new LiveStreamRelay(new System.Net.Http.HttpClient(relayHandler)
|
|||||||
await second.DisposeAsync();await System.Threading.Tasks.Task.Delay(250);
|
await second.DisposeAsync();await System.Threading.Tasks.Task.Delay(250);
|
||||||
Check(System.Text.Json.JsonSerializer.Serialize(relay.Status()).Contains("\"ActiveSources\":0"),"receiver connection released after final consumer");
|
Check(System.Text.Json.JsonSerializer.Serialize(relay.Status()).Contains("\"ActiveSources\":0"),"receiver connection released after final consumer");
|
||||||
}
|
}
|
||||||
|
await SavedChannelPlaybackTests.Run(Check);
|
||||||
public class PathsProxy : DispatchProxy
|
public class PathsProxy : DispatchProxy
|
||||||
{
|
{
|
||||||
public string Folder;
|
public string Folder;
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
|
using Jellyfin.Plugin.Enigma2;
|
||||||
|
using MediaBrowser.Common.Configuration;
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Controller.LiveTv;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
|
|
||||||
|
public static class SavedChannelPlaybackTests
|
||||||
|
{
|
||||||
|
public const string Old = "1:0:1:3D66:2C88:13E:820000:0:0:0:";
|
||||||
|
public const string Current = "1:0:1:13F1:5DC:13E:820000:0:0:0:";
|
||||||
|
public static async Task Run(Action<bool,string> check)
|
||||||
|
{
|
||||||
|
var previous = Plugin.Instance;
|
||||||
|
var folder = Path.Combine(Path.GetTempPath(),"saved-channel-"+Guid.NewGuid().ToString("N"));
|
||||||
|
Directory.CreateDirectory(folder);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var paths=DispatchProxy.Create<IApplicationPaths,SavedPaths>();((SavedPaths)(object)paths).Folder=folder;
|
||||||
|
var plugin=new Plugin(paths,DispatchProxy.Create<IXmlSerializer,NoXmlFiles>());
|
||||||
|
plugin.Configuration.HostName="receiver";plugin.Configuration.WebInterfacePort="80";
|
||||||
|
plugin.Configuration.StreamingPort="8001";plugin.Configuration.OnlyOneBouquet=true;
|
||||||
|
plugin.Configuration.TVBouquet="Polskie";plugin.Configuration.FetchPiconsFromWebInterface=true;
|
||||||
|
var library=DispatchProxy.Create<ILibraryManager,SavedChannelLibrary>();
|
||||||
|
var handler=new ReceiverHandler();
|
||||||
|
using var relay=new LiveStreamRelay(new HttpClient(handler),8096,TimeSpan.FromMilliseconds(50));
|
||||||
|
var calls=0;
|
||||||
|
var probe=new LiveStreamProbe((url,token)=>
|
||||||
|
{
|
||||||
|
calls++;
|
||||||
|
check(url.EndsWith("?programme=5105",StringComparison.Ordinal),"saved channel probes the migrated SID rather than the historical SID");
|
||||||
|
return Task.FromResult("{\"programs\":[{\"program_id\":5105,\"streams\":[{\"index\":0,\"codec_type\":\"video\",\"codec_name\":\"h264\",\"width\":1920,\"height\":1080}]}],\"streams\":[{\"index\":0,\"codec_type\":\"video\",\"codec_name\":\"h264\",\"width\":1920,\"height\":1080}]}");
|
||||||
|
});
|
||||||
|
var service=new LiveTvService(NullLogger<LiveTvService>.Instance,new ReceiverFactory(),null,probe,relay,library);
|
||||||
|
var saved=await service.GetChannelStream(Old,null,CancellationToken.None);
|
||||||
|
var current=await service.GetChannelStream(Current,null,CancellationToken.None);
|
||||||
|
check(saved.Path==current.Path&&calls==1,"saved and current native channels share the same relay and metadata probe");
|
||||||
|
check(((SavedChannelLibrary)(object)library).Calls==1,"current reference avoids the native historical lookup");
|
||||||
|
var id=saved.Path.Split('/').Last();
|
||||||
|
await using var first=await relay.Subscribe(id,CancellationToken.None);
|
||||||
|
await using var second=await relay.Subscribe(id,CancellationToken.None);
|
||||||
|
await first.Reader.ReadAsync();await second.Reader.ReadAsync();
|
||||||
|
check(handler.Calls==1&&handler.Reference==Current,"both native IDs open only one upstream using the migrated receiver reference");
|
||||||
|
using var cancelled=new CancellationTokenSource();cancelled.Cancel();
|
||||||
|
try { await service.GetChannelStream(Old,null,cancelled.Token);throw new Exception("Expected cancellation"); }
|
||||||
|
catch(OperationCanceledException) { check(handler.Calls==1,"cancelled channel lookup opens no extra upstream"); }
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
typeof(Plugin).GetProperty(nameof(Plugin.Instance)).SetValue(null,previous);
|
||||||
|
Directory.Delete(folder,true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NoXmlFiles:DispatchProxy
|
||||||
|
{
|
||||||
|
protected override object Invoke(MethodInfo method,object[] args)
|
||||||
|
{
|
||||||
|
if(method.Name=="SerializeToFile")return null; // Keep default configuration in memory.
|
||||||
|
throw new Exception("No persisted configuration expected in isolated test");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class SavedPaths:DispatchProxy
|
||||||
|
{
|
||||||
|
public string Folder;
|
||||||
|
protected override object Invoke(MethodInfo method,object[] args) => method.ReturnType==typeof(string)?Folder:null;
|
||||||
|
}
|
||||||
|
public class SavedChannelLibrary:DispatchProxy
|
||||||
|
{
|
||||||
|
public int Calls;
|
||||||
|
protected override object Invoke(MethodInfo method,object[] args)
|
||||||
|
{
|
||||||
|
if(method.Name!="GetItemList"||args[0] is not InternalItemsQuery q||!q.IncludeItemTypes.SequenceEqual(new[]{BaseItemKind.LiveTvChannel}))
|
||||||
|
throw new Exception("Expected metadata lookup restricted to live TV channels");
|
||||||
|
Calls++;
|
||||||
|
return new BaseItem[]{new LiveTvChannel{ExternalId=Old,Name="TV PULS HD",ServiceName="Enigma2"},
|
||||||
|
new LiveTvChannel{ExternalId=Old,Name="Different channel",ServiceName="Other provider"}};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private sealed class ReceiverFactory:IHttpClientFactory
|
||||||
|
{
|
||||||
|
public HttpClient CreateClient(string name)=>new(new BouquetHandler());
|
||||||
|
}
|
||||||
|
private sealed class BouquetHandler:HttpMessageHandler
|
||||||
|
{
|
||||||
|
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,CancellationToken token)
|
||||||
|
{
|
||||||
|
token.ThrowIfCancellationRequested();
|
||||||
|
var body=string.IsNullOrEmpty(request.RequestUri.Query)
|
||||||
|
? "<e2servicelist><e2service><e2servicereference>1:7:1:0:0:0:0:0:0:0:FROM BOUQUET</e2servicereference><e2servicename>Polskie</e2servicename></e2service></e2servicelist>"
|
||||||
|
: "<e2servicelist><e2service><e2servicereference>"+Current+"</e2servicereference><e2servicename>TV PULS HD</e2servicename></e2service></e2servicelist>";
|
||||||
|
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK){Content=new StringContent(body)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private sealed class ReceiverHandler:HttpMessageHandler
|
||||||
|
{
|
||||||
|
public int Calls;public string Reference;
|
||||||
|
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,CancellationToken token)
|
||||||
|
{
|
||||||
|
Calls++;Reference=request.RequestUri.AbsolutePath.TrimStart('/');
|
||||||
|
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK){Content=new StreamContent(new PacketStream())});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -8,7 +8,7 @@ guid: "193f29f9-ea6c-4595-a6f6-55e79d7c590a"
|
|||||||
# The version of the plugin, starting at 1. Note that the AssemblyVersion
|
# The version of the plugin, starting at 1. Note that the AssemblyVersion
|
||||||
# and FileVersion flags in the `.csproj` file must have two additional
|
# and FileVersion flags in the `.csproj` file must have two additional
|
||||||
# fiels, e.g. 1.0.0 to be built correctly.
|
# fiels, e.g. 1.0.0 to be built correctly.
|
||||||
version: "7.0.8.0" # Please increment with each pull request
|
version: "7.0.9.0" # Please increment with each pull request
|
||||||
|
|
||||||
# The supported Jellyfin version, usually the earliest binary-compatible
|
# The supported Jellyfin version, usually the earliest binary-compatible
|
||||||
# version. Based on the Jellyfin components from NuGet.
|
# version. Based on the Jellyfin components from NuGet.
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import urllib.error
|
|||||||
import urllib.request
|
import urllib.request
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
VERSION = '7.0.8.0'
|
VERSION = '7.0.9.0'
|
||||||
ABI = '12.2.0.0'
|
ABI = '12.2.0.0'
|
||||||
GUID = '193f29f9-ea6c-4595-a6f6-55e79d7c590a'
|
GUID = '193f29f9-ea6c-4595-a6f6-55e79d7c590a'
|
||||||
DLL = 'Jellyfin.Plugin.Enigma2.dll'
|
DLL = 'Jellyfin.Plugin.Enigma2.dll'
|
||||||
|
|||||||
Reference in New Issue
Block a user