mirror of
https://github.com/jellyfin/jellyfin-plugin-nextpvr.git
synced 2024-11-26 23:50:45 +00:00
Initial changes for 10.9.1 (#48)
This commit is contained in:
parent
4e170ab567
commit
d375758b21
2
.gitignore
vendored
2
.gitignore
vendored
@ -230,5 +230,3 @@ pip-log.txt
|
||||
.mr.developer.cfg
|
||||
|
||||
.idea
|
||||
artifacts
|
||||
.idea
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>0.0.0.0</Version>
|
||||
<AssemblyVersion>0.0.0.0</AssemblyVersion>
|
||||
<FileVersion>0.0.0.0</FileVersion>
|
||||
<Version>9.0.0.0</Version>
|
||||
<AssemblyVersion>9.0.0.0</AssemblyVersion>
|
||||
<FileVersion>9.0.0.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
17
Jellyfin.Plugin.NextPVR/Helpers/ChannelHelper.cs
Normal file
17
Jellyfin.Plugin.NextPVR/Helpers/ChannelHelper.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
|
||||
namespace Jellyfin.Plugin.NextPVR.Helpers;
|
||||
public static class ChannelHelper
|
||||
{
|
||||
public static ChannelType GetChannelType(int channelType)
|
||||
{
|
||||
ChannelType type = channelType switch
|
||||
{
|
||||
1 => ChannelType.TV,
|
||||
10 => ChannelType.Radio,
|
||||
_ => ChannelType.TV
|
||||
};
|
||||
|
||||
return type;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Jellyfin.Plugin.NextPVR.Configuration;
|
||||
@ -45,29 +45,29 @@ public class GenreMapper
|
||||
{
|
||||
if (genreMappings != null)
|
||||
{
|
||||
if (_configuration.GenreMappings.ContainsKey(GenreMovie) && _configuration.GenreMappings[GenreMovie] != null)
|
||||
if (_configuration.GenreMappings.TryGetValue(GenreMovie, out var value) && value != null)
|
||||
{
|
||||
_movieGenres.AddRange(_configuration.GenreMappings[GenreMovie]);
|
||||
_movieGenres.AddRange(value);
|
||||
}
|
||||
|
||||
if (_configuration.GenreMappings.ContainsKey(GenreSport) && _configuration.GenreMappings[GenreSport] != null)
|
||||
if (_configuration.GenreMappings.TryGetValue(GenreSport, out value) && value != null)
|
||||
{
|
||||
_sportGenres.AddRange(_configuration.GenreMappings[GenreSport]);
|
||||
_sportGenres.AddRange(value);
|
||||
}
|
||||
|
||||
if (_configuration.GenreMappings.ContainsKey(GenreNews) && _configuration.GenreMappings[GenreNews] != null)
|
||||
if (_configuration.GenreMappings.TryGetValue(GenreNews, out value) && value != null)
|
||||
{
|
||||
_newsGenres.AddRange(_configuration.GenreMappings[GenreNews]);
|
||||
_newsGenres.AddRange(value);
|
||||
}
|
||||
|
||||
if (_configuration.GenreMappings.ContainsKey(GenreKids) && _configuration.GenreMappings[GenreKids] != null)
|
||||
if (_configuration.GenreMappings.TryGetValue(GenreKids, out value) && value != null)
|
||||
{
|
||||
_kidsGenres.AddRange(_configuration.GenreMappings[GenreKids]);
|
||||
_kidsGenres.AddRange(value);
|
||||
}
|
||||
|
||||
if (_configuration.GenreMappings.ContainsKey(GenreLive) && _configuration.GenreMappings[GenreLive] != null)
|
||||
if (_configuration.GenreMappings.TryGetValue(GenreLive, out value) && value != null)
|
||||
{
|
||||
_liveGenres.AddRange(_configuration.GenreMappings[GenreLive]);
|
||||
_liveGenres.AddRange(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,7 @@
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Jellyfin.Plugin.NextPVR.Helpers;
|
||||
|
||||
public static class ChannelHelper
|
||||
{
|
||||
public static ChannelType GetChannelType(int channelType)
|
||||
{
|
||||
ChannelType type = channelType switch
|
||||
{
|
||||
1 => ChannelType.TV,
|
||||
10 => ChannelType.Radio,
|
||||
_ => ChannelType.TV
|
||||
};
|
||||
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
public static class UtilsHelper
|
||||
{
|
||||
public static void DebugInformation(ILogger<LiveTvService> logger, string message)
|
@ -1,7 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<AssemblyVersion>6.0.0.0</AssemblyVersion>
|
||||
<FileVersion>6.0.0.0</FileVersion>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
@ -20,12 +22,9 @@
|
||||
<PackageReference Include="Jellyfin.Controller" Version="10.*-*" />
|
||||
<PackageReference Include="Jellyfin.Extensions" Version="10.*-*" />
|
||||
<PackageReference Include="System.Memory" Version="4.5.*" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
||||
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.376" PrivateAssets="All" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="All" />
|
||||
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
@ -35,10 +36,13 @@ public class LiveTvService : ILiveTvService
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_logger = logger;
|
||||
LastUpdatedSidDateTime = DateTime.UtcNow;
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
private string Sid { get; set; }
|
||||
|
||||
public static LiveTvService Instance { get; private set; }
|
||||
|
||||
public bool IsActive => Sid != null;
|
||||
|
||||
private DateTimeOffset LastUpdatedSidDateTime { get; set; }
|
||||
@ -58,7 +62,7 @@ public class LiveTvService : ILiveTvService
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
private async Task EnsureConnectionAsync(CancellationToken cancellationToken)
|
||||
public async Task EnsureConnectionAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var config = Plugin.Instance.Configuration;
|
||||
|
||||
@ -132,7 +136,7 @@ public class LiveTvService : ILiveTvService
|
||||
private string GetMd5Hash(string value)
|
||||
{
|
||||
#pragma warning disable CA5351
|
||||
var hashValue = MD5.Create().ComputeHash(new UTF8Encoding().GetBytes(value));
|
||||
var hashValue = MD5.HashData(new UTF8Encoding().GetBytes(value));
|
||||
#pragma warning restore CA5351
|
||||
// Bit convertor return the byte to string as all caps hex values separated by "-"
|
||||
return BitConverter.ToString(hashValue).Replace("-", string.Empty, StringComparison.Ordinal).ToLowerInvariant();
|
||||
@ -587,19 +591,19 @@ public class LiveTvService : ILiveTvService
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ImageStream> GetChannelImageAsync(string channelId, CancellationToken cancellationToken)
|
||||
public Task<Stream> GetChannelImageAsync(string channelId, CancellationToken cancellationToken)
|
||||
{
|
||||
// Leave as is. This is handled by supplying image url to ChannelInfo
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ImageStream> GetProgramImageAsync(string programId, string channelId, CancellationToken cancellationToken)
|
||||
public Task<Stream> GetProgramImageAsync(string programId, string channelId, CancellationToken cancellationToken)
|
||||
{
|
||||
// Leave as is. This is handled by supplying image url to ProgramInfo
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ImageStream> GetRecordingImageAsync(string recordingId, CancellationToken cancellationToken)
|
||||
public Task<Stream> GetRecordingImageAsync(string recordingId, CancellationToken cancellationToken)
|
||||
{
|
||||
// Leave as is. This is handled by supplying image url to RecordingInfo
|
||||
throw new NotImplementedException();
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
@ -8,7 +8,6 @@ using Jellyfin.Plugin.NextPVR.Entities;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Channels;
|
||||
using MediaBrowser.Model.Dto;
|
||||
@ -20,7 +19,6 @@ namespace Jellyfin.Plugin.NextPVR;
|
||||
|
||||
public class RecordingsChannel : IChannel, IHasCacheKey, ISupportsDelete, ISupportsLatestMedia, ISupportsMediaProbe, IHasFolderAttributes, IDisposable
|
||||
{
|
||||
private readonly ILiveTvManager _liveTvManager;
|
||||
private readonly CancellationTokenSource _cancellationToken;
|
||||
private Timer _updateTimer;
|
||||
private DateTimeOffset _lastUpdate = DateTimeOffset.FromUnixTimeSeconds(0);
|
||||
@ -28,9 +26,8 @@ public class RecordingsChannel : IChannel, IHasCacheKey, ISupportsDelete, ISuppo
|
||||
private IEnumerable<MyRecordingInfo> _allRecordings;
|
||||
private bool _useCachedRecordings;
|
||||
|
||||
public RecordingsChannel(ILiveTvManager liveTvManager)
|
||||
public RecordingsChannel()
|
||||
{
|
||||
_liveTvManager = liveTvManager;
|
||||
var interval = TimeSpan.FromSeconds(20);
|
||||
_updateTimer = new Timer(OnUpdateTimerCallbackAsync, null, interval, interval);
|
||||
if (_updateTimer != null)
|
||||
@ -116,7 +113,13 @@ public class RecordingsChannel : IChannel, IHasCacheKey, ISupportsDelete, ISuppo
|
||||
|
||||
private LiveTvService GetService()
|
||||
{
|
||||
return _liveTvManager.Services.OfType<LiveTvService>().FirstOrDefault();
|
||||
LiveTvService service = LiveTvService.Instance;
|
||||
if (service is not null && !service.IsActive)
|
||||
{
|
||||
service.EnsureConnectionAsync(new System.Threading.CancellationToken(false)).Wait();
|
||||
}
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
public bool CanDelete(BaseItem item)
|
||||
@ -338,12 +341,7 @@ public class RecordingsChannel : IChannel, IHasCacheKey, ISupportsDelete, ISuppo
|
||||
private async void OnUpdateTimerCallbackAsync(object state)
|
||||
{
|
||||
var service = GetService();
|
||||
if (service is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (service.IsActive)
|
||||
if (service is not null && service.IsActive)
|
||||
{
|
||||
var backendUpdate = await service.GetLastUpdate(_cancellationToken.Token).ConfigureAwait(false);
|
||||
if (backendUpdate > _lastUpdate)
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Extensions.Json;
|
||||
@ -24,7 +24,7 @@ public class CancelDeleteRecordingResponse
|
||||
return false;
|
||||
}
|
||||
|
||||
private class RootObject
|
||||
private sealed class RootObject
|
||||
{
|
||||
public string Stat { get; set; }
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@ -49,7 +49,7 @@ public class ChannelResponse
|
||||
}
|
||||
|
||||
// Classes created with http://json2csharp.com/
|
||||
private class Channel
|
||||
private sealed class Channel
|
||||
{
|
||||
public int ChannelId { get; set; }
|
||||
|
||||
@ -68,7 +68,7 @@ public class ChannelResponse
|
||||
public bool ChannelIcon { get; set; }
|
||||
}
|
||||
|
||||
private class RootObject
|
||||
private sealed class RootObject
|
||||
{
|
||||
public List<Channel> Channels { get; set; }
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Extensions.Json;
|
||||
@ -25,7 +25,7 @@ public class InitializeResponse
|
||||
throw new JsonException("Failed to validate your connection with NextPVR.");
|
||||
}
|
||||
|
||||
private class RootObject
|
||||
private sealed class RootObject
|
||||
{
|
||||
public string Stat { get; set; }
|
||||
|
||||
|
@ -19,18 +19,16 @@ public class LastUpdateResponse
|
||||
UtilsHelper.DebugInformation(logger, $"[NextPVR] LastUpdate Response: {JsonSerializer.Serialize(root, _jsonOptions)}");
|
||||
return DateTimeOffset.FromUnixTimeSeconds(root.LastUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
// Classes created with http://json2csharp.com/
|
||||
|
||||
public class RootObject
|
||||
{
|
||||
[JsonPropertyName("last_update")]
|
||||
public int LastUpdate { get; set; }
|
||||
|
||||
public string Stat { get; set; }
|
||||
|
||||
public int Code { get; set; }
|
||||
|
||||
public string Msg { get; set; }
|
||||
|
||||
private sealed class RootObject
|
||||
{
|
||||
[JsonPropertyName("last_update")]
|
||||
public int LastUpdate { get; set; }
|
||||
|
||||
public string Stat { get; set; }
|
||||
|
||||
public int Code { get; set; }
|
||||
|
||||
public string Msg { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ public class ListingsResponse
|
||||
|
||||
// Classes created with http://json2csharp.com/
|
||||
|
||||
private class Listing
|
||||
private sealed class Listing
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
@ -114,7 +114,7 @@ public class ListingsResponse
|
||||
public int RecordingId { get; set; }
|
||||
}
|
||||
|
||||
private class RootObject
|
||||
private sealed class RootObject
|
||||
{
|
||||
public List<Listing> Listings { get; set; }
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ public class RecordingResponse
|
||||
}
|
||||
else
|
||||
{
|
||||
info.Url = $"{_baseUrl}/live?recording={i.Id}";
|
||||
info.Url = $"{_baseUrl}/live?recording={i.Id}&sid=jellyfin";
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,7 +215,7 @@ public class RecordingResponse
|
||||
return RecordingStatus.New;
|
||||
}
|
||||
|
||||
private class Recording
|
||||
private sealed class Recording
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
@ -280,7 +280,7 @@ public class RecordingResponse
|
||||
public int? Year { get; set; }
|
||||
}
|
||||
|
||||
private class RootObject
|
||||
private sealed class RootObject
|
||||
{
|
||||
public List<Recording> Recordings { get; set; }
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
@ -12,7 +12,7 @@ using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Jellyfin.Plugin.NextPVR.Responses;
|
||||
|
||||
internal class RecurringResponse
|
||||
internal sealed class RecurringResponse
|
||||
{
|
||||
private readonly ILogger<LiveTvService> _logger;
|
||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.CamelCaseOptions;
|
||||
@ -70,7 +70,7 @@ internal class RecurringResponse
|
||||
return info;
|
||||
}
|
||||
|
||||
private class Recurring
|
||||
private sealed class Recurring
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
@ -107,7 +107,7 @@ internal class RecurringResponse
|
||||
public string AdvancedRules { get; set; }
|
||||
}
|
||||
|
||||
private class RootObject
|
||||
private sealed class RootObject
|
||||
{
|
||||
public List<Recurring> Recurrings { get; set; }
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Globalization;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
@ -31,7 +31,7 @@ public class SettingResponse
|
||||
|
||||
// Classes created with http://json2csharp.com/
|
||||
|
||||
private class ScheduleSettings
|
||||
private sealed class ScheduleSettings
|
||||
{
|
||||
public string Version { get; set; }
|
||||
|
||||
@ -78,7 +78,7 @@ public class SettingResponse
|
||||
public int TimeEpoch { get; set; }
|
||||
}
|
||||
|
||||
private class SettingValue
|
||||
private sealed class SettingValue
|
||||
{
|
||||
public string Value { get; set; }
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@ -14,27 +14,29 @@ public class TunerResponse
|
||||
{
|
||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.CamelCaseOptions;
|
||||
|
||||
public async Task<List<LiveTvTunerInfo>> LiveTvTunerInfos(Stream stream)
|
||||
public async Task<List<TunerHostInfo>> LiveTvTunerInfo(Stream stream)
|
||||
{
|
||||
var root = await JsonSerializer.DeserializeAsync<RootObject>(stream, _jsonOptions).ConfigureAwait(false);
|
||||
return root.Tuners.Select(GetTunerInformation).ToList();
|
||||
}
|
||||
|
||||
private LiveTvTunerInfo GetTunerInformation(Tuner i)
|
||||
private TunerHostInfo GetTunerInformation(Tuner i)
|
||||
{
|
||||
LiveTvTunerInfo tunerinfo = new LiveTvTunerInfo();
|
||||
TunerHostInfo tunerinfo = new TunerHostInfo();
|
||||
|
||||
tunerinfo.Name = i.TunerName;
|
||||
tunerinfo.FriendlyName = i.TunerName;
|
||||
/*
|
||||
tunerinfo.Status = GetStatus(i);
|
||||
|
||||
if (i.Recordings.Count > 0)
|
||||
{
|
||||
tunerinfo.ChannelId = i.Recordings.Single().Recording.ChannelOid.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
*/
|
||||
return tunerinfo;
|
||||
}
|
||||
|
||||
/*
|
||||
private LiveTvTunerStatus GetStatus(Tuner i)
|
||||
{
|
||||
if (i.Recordings.Count > 0)
|
||||
@ -49,8 +51,9 @@ public class TunerResponse
|
||||
|
||||
return LiveTvTunerStatus.Available;
|
||||
}
|
||||
*/
|
||||
|
||||
private class Recording
|
||||
private sealed class Recording
|
||||
{
|
||||
public int TunerOid { get; set; }
|
||||
|
||||
@ -61,12 +64,12 @@ public class TunerResponse
|
||||
public int RecordingOid { get; set; }
|
||||
}
|
||||
|
||||
private class Recordings
|
||||
private sealed class Recordings
|
||||
{
|
||||
public Recording Recording { get; set; }
|
||||
}
|
||||
|
||||
private class Tuner
|
||||
private sealed class Tuner
|
||||
{
|
||||
public string TunerName { get; set; }
|
||||
|
||||
@ -77,7 +80,7 @@ public class TunerResponse
|
||||
public List<object> LiveTv { get; set; }
|
||||
}
|
||||
|
||||
private class RootObject
|
||||
private sealed class RootObject
|
||||
{
|
||||
public List<Tuner> Tuners { get; set; }
|
||||
}
|
||||
|
23
Jellyfin.Plugin.NextPVR/ServiceRegistrator.cs
Normal file
23
Jellyfin.Plugin.NextPVR/ServiceRegistrator.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using Jellyfin.Plugin.NextPVR;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Authentication;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.Plugins;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Jellyfin.Plugin.NextPVR;
|
||||
|
||||
/// <summary>
|
||||
/// Register NextPVR services.
|
||||
/// </summary>
|
||||
///
|
||||
public class ServiceRegistrator : IPluginServiceRegistrator
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public void RegisterServices(IServiceCollection serviceCollection, IServerApplicationHost applicationHost)
|
||||
{
|
||||
serviceCollection.AddSingleton<ILiveTvService, LiveTvService>();
|
||||
serviceCollection.AddSingleton<IChannel, RecordingsChannel>();
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@ This plugin provides access to live TV, program guide, and recordings from a [Ne
|
||||
|
||||
## Build
|
||||
|
||||
1. To build this plugin you will need [.Net 5.x](https://dotnet.microsoft.com/download/dotnet/5.0).
|
||||
1. To build this plugin you will need [.Net 8.x](https://dotnet.microsoft.com/download/dotnet/8.0).
|
||||
|
||||
2. Build plugin with following command
|
||||
```
|
||||
|
@ -1,9 +1,9 @@
|
||||
name: "NextPVR"
|
||||
guid: "9574ac10-bf23-49bc-949f-924f23cfa48f"
|
||||
imageUrl: "https://repo.jellyfin.org/releases/plugin/images/jellyfin-plugin-nextpvr.png"
|
||||
version: "8"
|
||||
targetAbi: "10.8.0.0"
|
||||
framework: "net6.0"
|
||||
version: 9
|
||||
targetAbi: "10.9.0.0"
|
||||
framework: "net8.0"
|
||||
overview: "Live TV plugin for NextPVR"
|
||||
description: >
|
||||
Provides access to live TV, program guide, and recordings from NextPVR.
|
||||
|
Loading…
Reference in New Issue
Block a user