2 Commits
Author SHA1 Message Date
knackebrot a2e9686898 Update for Jellyfin 10.8
- Change branding from Vu+ to Enigma2

- Fix wrong default hostname

- Add new options UseLoginForStreams, UseHTTPSForStreams

- Use new GUID to avoid clashing with the older version of plugin
2022-06-29 02:40:53 +02:00
knackebrot 4a41cf4b74 Update for Jellyfin 10.7 2021-03-14 19:24:59 +01:00
14 changed files with 841 additions and 735 deletions
+199
View File
@@ -0,0 +1,199 @@
# With more recent updates Visual Studio 2017 supports EditorConfig files out of the box
# Visual Studio Code needs an extension: https://github.com/editorconfig/editorconfig-vscode
# For emacs, vim, np++ and other editors, see here: https://github.com/editorconfig
###############################
# Core EditorConfig Options #
###############################
root = true
# All files
[*]
indent_style = space
indent_size = 4
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
end_of_line = lf
max_line_length = 9999
# YAML indentation
[*.{yml,yaml}]
indent_size = 2
# XML indentation
[*.{csproj,xml}]
indent_size = 2
###############################
# .NET Coding Conventions #
###############################
[*.{cs,vb}]
# Organize usings
dotnet_sort_system_directives_first = true
# this. preferences
dotnet_style_qualification_for_field = false:silent
dotnet_style_qualification_for_property = false:silent
dotnet_style_qualification_for_method = false:silent
dotnet_style_qualification_for_event = false:silent
# Language keywords vs BCL types preferences
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
dotnet_style_predefined_type_for_member_access = true:silent
# Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
# Modifier preferences
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
dotnet_style_readonly_field = true:suggestion
# Expression-level preferences
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_auto_properties = true:silent
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent
###############################
# Naming Conventions #
###############################
# Style Definitions (From Roslyn)
# Non-private static fields are PascalCase
dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non_private_static_fields
dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style
dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field
dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected
dotnet_naming_symbols.non_private_static_fields.required_modifiers = static
dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case
# Constants are PascalCase
dotnet_naming_rule.constants_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants
dotnet_naming_rule.constants_should_be_pascal_case.style = constant_style
dotnet_naming_symbols.constants.applicable_kinds = field, local
dotnet_naming_symbols.constants.required_modifiers = const
dotnet_naming_style.constant_style.capitalization = pascal_case
# Static fields are camelCase and start with s_
dotnet_naming_rule.static_fields_should_be_camel_case.severity = suggestion
dotnet_naming_rule.static_fields_should_be_camel_case.symbols = static_fields
dotnet_naming_rule.static_fields_should_be_camel_case.style = static_field_style
dotnet_naming_symbols.static_fields.applicable_kinds = field
dotnet_naming_symbols.static_fields.required_modifiers = static
dotnet_naming_style.static_field_style.capitalization = camel_case
dotnet_naming_style.static_field_style.required_prefix = _
# Instance fields are camelCase and start with _
dotnet_naming_rule.instance_fields_should_be_camel_case.severity = suggestion
dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields
dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style
dotnet_naming_symbols.instance_fields.applicable_kinds = field
dotnet_naming_style.instance_field_style.capitalization = camel_case
dotnet_naming_style.instance_field_style.required_prefix = _
# Locals and parameters are camelCase
dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion
dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters
dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style
dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local
dotnet_naming_style.camel_case_style.capitalization = camel_case
# Local functions are PascalCase
dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions
dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style
dotnet_naming_symbols.local_functions.applicable_kinds = local_function
dotnet_naming_style.local_function_style.capitalization = pascal_case
# By default, name items with PascalCase
dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members
dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style
dotnet_naming_symbols.all_members.applicable_kinds = *
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
###############################
# C# Coding Conventions #
###############################
[*.cs]
# var preferences
csharp_style_var_for_built_in_types = true:silent
csharp_style_var_when_type_is_apparent = true:silent
csharp_style_var_elsewhere = true:silent
# Expression-bodied members
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_accessors = true:silent
# Pattern matching preferences
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
# Null-checking preferences
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
# Modifier preferences
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
# Expression-level preferences
csharp_prefer_braces = true:silent
csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_prefer_simple_default_expression = true:suggestion
csharp_style_pattern_local_over_anonymous_function = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
###############################
# C# Formatting Rules #
###############################
# New line preferences
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true
# Indentation preferences
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = flush_left
# Space preferences
csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
# Wrapping preferences
csharp_preserve_single_line_statements = true
csharp_preserve_single_line_blocks = true
+2
View File
@@ -106,3 +106,5 @@ Generated_Code #added for RIA/Silverlight projects
_UpgradeReport_Files/ _UpgradeReport_Files/
Backup*/ Backup*/
UpgradeLog*.XML UpgradeLog*.XML
.vs
@@ -1,9 +1,14 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio Version 17
VisualStudioVersion = 15.0.26730.3 VisualStudioVersion = 17.2.32616.157
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Plugins.VuPlus", "MediaBrowser.Plugins.VuPlus\MediaBrowser.Plugins.VuPlus.csproj", "{52B1ABDF-09C1-450E-B808-BBA0A9C19848}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Plugin.Enigma2", "Jellyfin.Plugin.Enigma2\Jellyfin.Plugin.Enigma2.csproj", "{52B1ABDF-09C1-450E-B808-BBA0A9C19848}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A968FB09-8732-407C-8748-6DB383EB5D91}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
EndProjectSection
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -1,7 +1,6 @@
using System;
using MediaBrowser.Model.Plugins; using MediaBrowser.Model.Plugins;
namespace MediaBrowser.Plugins.VuPlus.Configuration namespace Jellyfin.Plugin.Enigma2.Configuration
{ {
/// <summary> /// <summary>
/// Class PluginConfiguration /// Class PluginConfiguration
@@ -13,26 +12,30 @@ namespace MediaBrowser.Plugins.VuPlus.Configuration
public string WebInterfacePort { get; set; } public string WebInterfacePort { get; set; }
public string WebInterfaceUsername { get; set; } public string WebInterfaceUsername { get; set; }
public string WebInterfacePassword { get; set; } public string WebInterfacePassword { get; set; }
public Boolean UseSecureHTTPS { get; set; } public bool UseLoginForStreams { get; set; }
public Boolean OnlyOneBouquet { get; set; } public bool UseSecureHTTPS { get; set; }
public bool UseSecureHTTPSForStreams { get; set; }
public bool OnlyOneBouquet { get; set; }
public string TVBouquet { get; set; } public string TVBouquet { get; set; }
public Boolean ZapToChannel { get; set; } public bool ZapToChannel { get; set; }
public Boolean FetchPiconsFromWebInterface { get; set; } public bool FetchPiconsFromWebInterface { get; set; }
public string PiconsPath { get; set; } public string PiconsPath { get; set; }
public string RecordingPath { get; set; } public string RecordingPath { get; set; }
public Boolean EnableDebugLogging { get; set; } public bool EnableDebugLogging { get; set; }
public PluginConfiguration() public PluginConfiguration()
{ {
HostName = "http://localhost"; HostName = "localhost";
StreamingPort = "8001"; StreamingPort = "8001";
WebInterfacePort = "8000"; WebInterfacePort = "8000";
WebInterfaceUsername= ""; WebInterfaceUsername = "";
WebInterfacePassword = ""; WebInterfacePassword = "";
UseLoginForStreams = false;
UseSecureHTTPS = false; UseSecureHTTPS = false;
UseSecureHTTPSForStreams = false;
OnlyOneBouquet = true; OnlyOneBouquet = true;
TVBouquet = "Favourites (TV)"; TVBouquet = "Favourites (TV)";
ZapToChannel = false; ZapToChannel = false;
@@ -42,7 +45,6 @@ namespace MediaBrowser.Plugins.VuPlus.Configuration
RecordingPath = ""; RecordingPath = "";
EnableDebugLogging = false; EnableDebugLogging = false;
} }
} }
} }
@@ -0,0 +1,208 @@
<!DOCTYPE html>
<html>
<head>
<title>Enigma2</title>
</head>
<body>
<div data-role="page" id="Enigma2ConfigurationPage" class="page type-interior pluginConfigurationPage Enigma2ConfigurationPage" data-require="emby-button,emby-checkbox,emby-input">
<div data-role="content">
<div class="content-primary">
<h1>Enigma2</h1>
<form id="Enigma2ConfigurationForm" class="Enigma2ConfigurationForm">
<div class="inputContainer">
<input is="emby-input" id="txtHostName" type="text" label="Enigma2 hostname or ip address:" />
<div class="fieldDescription">
The host name (address) or ip address of your receiver
</div>
</div>
<div class="inputContainer">
<input is="emby-input" id="txtStreamingPort" type="text" label="Enigma2 streaming port:" />
<div class="fieldDescription">
The Streaming port of your receiver eg. 8001
</div>
</div>
<div class="inputContainer">
<input is="emby-input" id="txtWebInterfacePort" type="text" label="Enigma2 Web Interface port:" />
<div class="fieldDescription">
The web interface port of your receiver eg. 8000
</div>
</div>
<div class="inputContainer">
<input is="emby-input" id="txtWebInterfaceUsername" type="text" label="Enigma2 Web Interface username:" />
<div class="fieldDescription">
The web interface username of your receiver (optional)
</div>
</div>
<div class="inputContainer">
<input is="emby-input" id="txtWebInterfacePassword" type="password" label="Enigma2 Web Interface password:" />
<div class="fieldDescription">
The web interface password of your receiver (optional)
</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input is="emby-checkbox" type="checkbox" id="chkUseLoginForStreams" />
<span>Use login for streaming</span>
</label>
<div class="fieldDescription checkboxFieldDescription">
Use web interface login for streaming
</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input is="emby-checkbox" type="checkbox" id="chkUseSecureHTTPS" />
<span>Use secure HTTP (HTTPS)</span>
</label>
<div class="fieldDescription checkboxFieldDescription">
Use HTTPS to connect to your receiver
</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input is="emby-checkbox" type="checkbox" id="chkUseSecureHTTPSForStreams" />
<span>Use secure HTTP (HTTPS) for streams</span>
</label>
<div class="fieldDescription checkboxFieldDescription">
Use HTTPS to connect to streaming port
</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input is="emby-checkbox" type="checkbox" id="chkOnlyOneBouquet" />
<span>Fetch Only one TV bouquet</span>
</label>
<div class="fieldDescription checkboxFieldDescription">
Limit channels to only those contained within the specified TV Bouquet below (optional)
</div>
</div>
<div class="inputContainer">
<input is="emby-input" id="txtTVBouquet" type="text" label="Enigma2 TVBouquet:" />
<div class="fieldDescription">
The TV Bouquet to load channels for (optional)
</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input is="emby-checkbox" type="checkbox" id="chkZapToChannel" />
<span>Zap before Channel switch (single tuner)</span>
</label>
<div class="fieldDescription checkboxFieldDescription">
Set if only one tuner within receiver
</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input is="emby-checkbox" type="checkbox" id="chkFetchPiconsFromWebInterface" />
<span>Fetch picons from webinterface</span>
</label>
<div class="fieldDescription checkboxFieldDescription">
Set if you want to retrieve Picons from the web interface of the receiver
</div>
</div>
<div class="inputContainer">
<input is="emby-input" id="txtPiconsPath" type="text" label="Picons Path:" />
<div class="fieldDescription">
The local location of your Picons eg. C:\Picons\ (optional)
</div>
</div>
<div class="inputContainer">
<input is="emby-input" id="txtRecordingPath" type="text" label="Recording Path:" />
<div class="fieldDescription">
The location to store your recordings on your receiver eg. /hdd/movie/ (optional)
</div>
</div>
<label class="checkboxContainer">
<input is="emby-checkbox" type="checkbox" id="chkDebugLogging" />
<span>Enable Enigma2 debug logging</span>
</label>
<div>
<button is="emby-button" type="submit" class="raised button-submit block"><span>Save</span></button>
</div>
</form>
</div>
</div>
<script type="text/javascript">
var Enigma2ConfigurationPage = {
pluginUniqueId: "193f29f9-ea6c-4595-a6f6-55e79d7c590a",
loadConfiguration: function () {
Dashboard.showLoadingMsg();
ApiClient.getPluginConfiguration(Enigma2ConfigurationPage.pluginUniqueId).then(function (config) {
document.getElementById('txtHostName').value = config.HostName || "";
document.getElementById('txtStreamingPort').value = config.StreamingPort || "";
document.getElementById('txtWebInterfacePort').value = config.WebInterfacePort || "";
document.getElementById('txtWebInterfaceUsername').value = config.WebInterfaceUsername || "";
document.getElementById('txtWebInterfacePassword').value = config.WebInterfacePassword || "";
document.getElementById('chkUseLoginForStreams').checked = config.UseLoginForStreams || false;
document.getElementById('chkUseSecureHTTPS').checked = config.UseSecureHTTPS || false;
document.getElementById('chkUseSecureHTTPSForStreams').checked = config.UseSecureHTTPSForStreams || false;
document.getElementById('chkOnlyOneBouquet').checked = config.OnlyOneBouquet || false;
document.getElementById('txtTVBouquet').value = config.TVBouquet || "";
document.getElementById('chkZapToChannel').checked = config.ZapToChannel || false;
document.getElementById('chkFetchPiconsFromWebInterface').checked = config.FetchPiconsFromWebInterface || false;
document.getElementById('txtPiconsPath').value = config.PiconsPath || "";
document.getElementById('txtRecordingPath').value = config.RecordingPath || "";
document.getElementById('chkDebugLogging').checked = config.EnableDebugLogging || false;
Dashboard.hideLoadingMsg();
});
},
saveConfiguration: function () {
Dashboard.showLoadingMsg();
ApiClient.getPluginConfiguration(Enigma2ConfigurationPage.pluginUniqueId).then(function (config) {
config.HostName = document.getElementById('txtHostName').value;
config.StreamingPort = document.getElementById('txtStreamingPort').value;
config.WebInterfacePort = document.getElementById('txtWebInterfacePort').value;
config.WebInterfaceUsername = document.getElementById('txtWebInterfaceUsername').value;
config.WebInterfacePassword = document.getElementById('txtWebInterfacePassword').value;
config.UseLoginForStreams = document.getElementById('chkUseLoginForStreams').checked;
config.UseSecureHTTPS = document.getElementById('chkUseSecureHTTPS').checked;
config.UseSecureHTTPSForStreams = document.getElementById('chkUseSecureHTTPSForStreams').checked;
config.OnlyOneBouquet = document.getElementById('chkOnlyOneBouquet').checked;
config.TVBouquet = document.getElementById('txtTVBouquet').value;
config.ZapToChannel = document.getElementById('chkZapToChannel').checked;
config.FetchPiconsFromWebInterface = document.getElementById('chkFetchPiconsFromWebInterface').checked;
config.PiconsPath = document.getElementById('txtPiconsPath').value;
config.RecordingPath = document.getElementById('txtRecordingPath').value;
config.EnableDebugLogging = document.getElementById('chkDebugLogging').checked;
ApiClient.updatePluginConfiguration(Enigma2ConfigurationPage.pluginUniqueId, config).then(Dashboard.processPluginConfigurationUpdateResult);
});
}
}
document.getElementById('Enigma2ConfigurationPage').addEventListener('pageshow', function () {
Enigma2ConfigurationPage.loadConfiguration();
});
document.getElementById('Enigma2ConfigurationForm').addEventListener('submit', function (e) {
e.preventDefault();
Enigma2ConfigurationPage.saveConfiguration();
});
</script>
</div>
</body>
</html>
@@ -1,14 +1,14 @@
using MediaBrowser.Model.LiveTv;
using System; using System;
using MediaBrowser.Model.LiveTv;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace MediaBrowser.Plugins.VuPlus.Helpers namespace Jellyfin.Plugin.Enigma2.Helpers
{ {
public static class ChannelHelper public static class ChannelHelper
{ {
public static ChannelType GetChannelType(string channelType) public static ChannelType GetChannelType(string channelType)
{ {
ChannelType type = new ChannelType(); var type = new ChannelType();
if (channelType == "0x1") if (channelType == "0x1")
{ {
@@ -28,14 +28,14 @@ namespace MediaBrowser.Plugins.VuPlus.Helpers
public static void DebugInformation(ILogger<LiveTvService> logger, string message) public static void DebugInformation(ILogger<LiveTvService> logger, string message)
{ {
var config = Plugin.Instance.Configuration; var config = Plugin.Instance.Configuration;
bool enableDebugLogging = config.EnableDebugLogging; var enableDebugLogging = config.EnableDebugLogging;
if (enableDebugLogging) if (enableDebugLogging)
{ {
logger.LogDebug(message); logger.LogDebug(message);
} }
} }
} }
public static class RecordingHelper public static class RecordingHelper

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0</TargetFrameworks>
<AssemblyVersion>5.0.0.0</AssemblyVersion>
<FileVersion>5.0.0.0</FileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net6.0|AnyCPU'">
<DebugType>none</DebugType>
<DebugSymbols>false</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<None Remove="Configuration\configPage.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Configuration\configPage.html" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Jellyfin.Common" Version="10.8.0" />
<PackageReference Include="Jellyfin.Naming" Version="10.8.0" />
<PackageReference Include="Jellyfin.Controller" Version="10.8.0" />
<PackageReference Include="Jellyfin.Model" Version="10.8.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
</ItemGroup>
</Project>
@@ -4,17 +4,19 @@ using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Plugins;
using MediaBrowser.Model.Plugins; using MediaBrowser.Model.Plugins;
using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Serialization;
using MediaBrowser.Plugins.VuPlus.Configuration; using Jellyfin.Plugin.Enigma2.Configuration;
namespace MediaBrowser.Plugins.VuPlus namespace Jellyfin.Plugin.Enigma2
{ {
/// <summary> /// <summary>
/// Class Plugin /// Class Plugin
/// </summary> /// </summary>
public class Plugin : BasePlugin<PluginConfiguration>, IHasWebPages public class Plugin : BasePlugin<PluginConfiguration>, IHasWebPages
{ {
public Plugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer) public Plugin(
: base(applicationPaths, xmlSerializer) IApplicationPaths applicationPaths,
IXmlSerializer xmlSerializer
) : base(applicationPaths, xmlSerializer)
{ {
Instance = this; Instance = this;
} }
@@ -23,28 +25,16 @@ namespace MediaBrowser.Plugins.VuPlus
/// Gets the name of the plugin /// Gets the name of the plugin
/// </summary> /// </summary>
/// <value>The name.</value> /// <value>The name.</value>
public override string Name public override string Name => "Enigma2";
{
get { return "VuPlus"; }
}
/// <summary> /// <summary>
/// Gets the description. /// Gets the description.
/// </summary> /// </summary>
/// <value>The description.</value> /// <value>The description.</value>
public override string Description public override string Description => "Provides live TV using Enigma2 PVR as a back-end.";
{
get
{
return "Provides live tv using Vu+ / Enigma2 pvr as a back-end.";
}
}
private Guid _id = new Guid("9564ac10-af23-39bc-449f-624f23cfa48f"); private Guid _id = new Guid("193f29f9-ea6c-4595-a6f6-55e79d7c590a");
public override Guid Id public override Guid Id => _id;
{
get { return _id; }
}
/// <summary> /// <summary>
/// Gets the instance. /// Gets the instance.
@@ -58,8 +48,8 @@ namespace MediaBrowser.Plugins.VuPlus
{ {
new PluginPageInfo new PluginPageInfo
{ {
Name = "vuplus", Name = "enigma2",
EmbeddedResourcePath = "MediaBrowser.Plugins.VuPlus.Configuration.configPage.html" EmbeddedResourcePath = "Jellyfin.Plugin.Enigma2.Configuration.configPage.html"
} }
}; };
} }
@@ -1,22 +1,21 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Globalization;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Channels;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Controller.LiveTv;
using System.Linq;
using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Extensions;
using MediaBrowser.Model.Dto; using MediaBrowser.Controller.Channels;
using System.Globalization;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Channels;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.MediaInfo;
namespace MediaBrowser.Plugins.VuPlus namespace Jellyfin.Plugin.Enigma2
{ {
public class RecordingsChannel : IChannel, IHasCacheKey, ISupportsDelete, ISupportsLatestMedia, ISupportsMediaProbe, IHasFolderAttributes public class RecordingsChannel : IChannel, IHasCacheKey, ISupportsDelete, ISupportsLatestMedia, ISupportsMediaProbe, IHasFolderAttributes
{ {
@@ -27,56 +26,27 @@ namespace MediaBrowser.Plugins.VuPlus
_liveTvManager = liveTvManager; _liveTvManager = liveTvManager;
} }
public string Name public string Name => "Enigma2 Recordings";
{
get
{
return "VuPlus Recordings";
}
}
public string[] Attributes public string[] Attributes => new[] { "Recordings" };
{
get
{
return new[] { "Recordings" };
}
}
public string Description public string Description => "Enigma2 Recordings";
{
get
{
return "VuPlus Recordings";
}
}
public string DataVersion public string DataVersion => "1";
{
get
{
return "1";
}
}
public string HomePageUrl public string HomePageUrl => null;
{
get { return null; }
}
public ChannelParentalRating ParentalRating public ChannelParentalRating ParentalRating => ChannelParentalRating.GeneralAudience;
{
get { return ChannelParentalRating.GeneralAudience; }
}
public string GetCacheKey(string userId) public string GetCacheKey(string userId)
{ {
var now = DateTime.UtcNow; var now = DateTime.UtcNow;
var values = new List<string>(); var values = new List<string>
{
values.Add(now.DayOfYear.ToString(CultureInfo.InvariantCulture)); now.DayOfYear.ToString(CultureInfo.InvariantCulture),
values.Add(now.Hour.ToString(CultureInfo.InvariantCulture)); now.Hour.ToString(CultureInfo.InvariantCulture)
};
double minute = now.Minute; double minute = now.Minute;
minute /= 5; minute /= 5;
@@ -94,8 +64,8 @@ namespace MediaBrowser.Plugins.VuPlus
{ {
ContentTypes = new List<ChannelMediaContentType> ContentTypes = new List<ChannelMediaContentType>
{ {
ChannelMediaContentType.Movie, ChannelMediaContentType.Movie,
ChannelMediaContentType.Episode, ChannelMediaContentType.Episode,
ChannelMediaContentType.Clip ChannelMediaContentType.Clip
}, },
MediaTypes = new List<ChannelMediaType> MediaTypes = new List<ChannelMediaType>
@@ -211,14 +181,10 @@ namespace MediaBrowser.Plugins.VuPlus
var service = GetService(); var service = GetService();
var allRecordings = await service.GetAllRecordingsAsync(cancellationToken).ConfigureAwait(false); var allRecordings = await service.GetAllRecordingsAsync(cancellationToken).ConfigureAwait(false);
var result = new ChannelItemResult() return new ChannelItemResult()
{ {
Items = new List<ChannelItemInfo>() Items = allRecordings.Where(filter).Select(ConvertToChannelItem).ToList()
}; };
result.Items.AddRange(allRecordings.Where(filter).Select(ConvertToChannelItem));
return result;
} }
private ChannelItemInfo ConvertToChannelItem(MyRecordingInfo item) private ChannelItemInfo ConvertToChannelItem(MyRecordingInfo item)
@@ -237,7 +203,7 @@ namespace MediaBrowser.Plugins.VuPlus
//HomePageUrl = item.HomePageUrl //HomePageUrl = item.HomePageUrl
Id = item.Id, Id = item.Id,
//IndexNumber = item.IndexNumber, //IndexNumber = item.IndexNumber,
MediaType = item.ChannelType == Model.LiveTv.ChannelType.TV ? ChannelMediaType.Video : ChannelMediaType.Audio, MediaType = item.ChannelType == ChannelType.TV ? ChannelMediaType.Video : ChannelMediaType.Audio,
MediaSources = new List<MediaSourceInfo> MediaSources = new List<MediaSourceInfo>
{ {
new MediaSourceInfo new MediaSourceInfo
@@ -255,7 +221,7 @@ namespace MediaBrowser.Plugins.VuPlus
DateModified = item.DateLastUpdated, DateModified = item.DateLastUpdated,
Overview = item.Overview, Overview = item.Overview,
//People = item.People //People = item.People
IsLiveStream = item.Status == Model.LiveTv.RecordingStatus.InProgress, IsLiveStream = item.Status == RecordingStatus.InProgress,
Etag = item.Status.ToString() Etag = item.Status.ToString()
}; };
@@ -267,16 +233,14 @@ namespace MediaBrowser.Plugins.VuPlus
var service = GetService(); var service = GetService();
var allRecordings = await service.GetAllRecordingsAsync(cancellationToken).ConfigureAwait(false); var allRecordings = await service.GetAllRecordingsAsync(cancellationToken).ConfigureAwait(false);
var result = new ChannelItemResult()
{
Items = new List<ChannelItemInfo>()
};
var series = allRecordings var series = allRecordings
.Where(i => i.IsSeries) .Where(i => i.IsSeries)
.ToLookup(i => i.Name, StringComparer.OrdinalIgnoreCase); .ToLookup(i => i.Name, StringComparer.OrdinalIgnoreCase);
result.Items.AddRange(series.OrderBy(i => i.Key).Select(i => new ChannelItemInfo var items = new List<ChannelItemInfo>();
items.AddRange(series.OrderBy(i => i.Key).Select(i => new ChannelItemInfo
{ {
Name = i.Key, Name = i.Key,
FolderType = ChannelFolderType.Container, FolderType = ChannelFolderType.Container,
@@ -289,7 +253,7 @@ namespace MediaBrowser.Plugins.VuPlus
if (kids != null) if (kids != null)
{ {
result.Items.Add(new ChannelItemInfo items.Add(new ChannelItemInfo
{ {
Name = "Kids", Name = "Kids",
FolderType = ChannelFolderType.Container, FolderType = ChannelFolderType.Container,
@@ -302,7 +266,7 @@ namespace MediaBrowser.Plugins.VuPlus
var movies = allRecordings.FirstOrDefault(i => i.IsMovie); var movies = allRecordings.FirstOrDefault(i => i.IsMovie);
if (movies != null) if (movies != null)
{ {
result.Items.Add(new ChannelItemInfo items.Add(new ChannelItemInfo
{ {
Name = "Movies", Name = "Movies",
FolderType = ChannelFolderType.Container, FolderType = ChannelFolderType.Container,
@@ -315,7 +279,7 @@ namespace MediaBrowser.Plugins.VuPlus
var news = allRecordings.FirstOrDefault(i => i.IsNews); var news = allRecordings.FirstOrDefault(i => i.IsNews);
if (news != null) if (news != null)
{ {
result.Items.Add(new ChannelItemInfo items.Add(new ChannelItemInfo
{ {
Name = "News", Name = "News",
FolderType = ChannelFolderType.Container, FolderType = ChannelFolderType.Container,
@@ -328,7 +292,7 @@ namespace MediaBrowser.Plugins.VuPlus
var sports = allRecordings.FirstOrDefault(i => i.IsSports); var sports = allRecordings.FirstOrDefault(i => i.IsSports);
if (sports != null) if (sports != null)
{ {
result.Items.Add(new ChannelItemInfo items.Add(new ChannelItemInfo
{ {
Name = "Sports", Name = "Sports",
FolderType = ChannelFolderType.Container, FolderType = ChannelFolderType.Container,
@@ -341,7 +305,7 @@ namespace MediaBrowser.Plugins.VuPlus
var other = allRecordings.FirstOrDefault(i => !i.IsSports && !i.IsNews && !i.IsMovie && !i.IsKids && !i.IsSeries); var other = allRecordings.FirstOrDefault(i => !i.IsSports && !i.IsNews && !i.IsMovie && !i.IsKids && !i.IsSeries);
if (other != null) if (other != null)
{ {
result.Items.Add(new ChannelItemInfo items.Add(new ChannelItemInfo
{ {
Name = "Others", Name = "Others",
FolderType = ChannelFolderType.Container, FolderType = ChannelFolderType.Container,
@@ -351,7 +315,10 @@ namespace MediaBrowser.Plugins.VuPlus
}); });
} }
return result; return new ChannelItemResult()
{
Items = items
};
} }
} }
public class MyRecordingInfo public class MyRecordingInfo
@@ -1,204 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Vu+</title>
</head>
<body>
<div data-role="page" class="page type-interior pluginConfigurationPage VuPlusConfigurationPage" data-require="emby-button,emby-checkbox,emby-input">
<div data-role="content">
<div class="content-primary">
<h1>VuPlus</h1>
<form class="VuPlusConfigurationForm">
<div class="inputContainer">
<input is="emby-input" id="txtHostName" type="text" label="Vu+ hostname or ip address:" />
<div class="fieldDescription">
The host name (address) or ip address of your receiver
</div>
</div>
<div class="inputContainer">
<input is="emby-input" id="txtStreamingPort" type="text" label="Vu+ streaming port:" />
<div class="fieldDescription">
The Streaming port of your receiver eg. 8001
</div>
</div>
<div class="inputContainer">
<input is="emby-input" id="txtWebInterfacePort" type="text" label="Vu+ Web Interface port:" />
<div class="fieldDescription">
The web Interface port of your receiver eg. 8000
</div>
</div>
<div class="inputContainer">
<input is="emby-input" id="txtWebInterfaceUsername" type="text" label="Vu+ Web Interface username:" />
<div class="fieldDescription">
The web Interface username of your receiver (optional)
</div>
</div>
<div class="inputContainer">
<input is="emby-input" id="txtWebInterfacePassword" type="text" label="Vu+ Web Interface password:" />
<div class="fieldDescription">
The web Interface password of your receiver (optional)
</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input is="emby-checkbox" type="checkbox" id="chkUseSecureHTTPS" />
<span>Use secure HTTP (HTTPS)</span>
</label>
<div class="fieldDescription checkboxFieldDescription">
Use HTTPS to connect to your receiver
</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input is="emby-checkbox" type="checkbox" id="chkOnlyOneBouquet" />
<span>Fetch Only one TV bouquet</span>
</label>
<div class="fieldDescription checkboxFieldDescription">
Limit channels to only those contained within the specified TV Bouquet below (optional)
</div>
</div>
<div class="inputContainer">
<input is="emby-input" id="txtTVBouquet" type="text" label="Vu+ TVBouquet:" />
<div class="fieldDescription">
The TV Bouquet to load channels for (optional)
</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input is="emby-checkbox" type="checkbox" id="chkZapToChannel" />
<span>Zap before Channel switch (single tuner)</span>
</label>
<div class="fieldDescription checkboxFieldDescription">
Set if only one tuner within receiver
</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input is="emby-checkbox" type="checkbox" id="chkFetchPiconsFromWebInterface" />
<span>Fetch picons from webinterface</span>
</label>
<div class="fieldDescription checkboxFieldDescription">
Set if you want to retrieve Picons from the web interface of the receiver
</div>
</div>
<div class="inputContainer">
<input is="emby-input" id="txtPiconsPath" type="text" label="Picons Path:" />
<div class="fieldDescription">
The local location of your Picons eg. C:\Picons\ (optional)
</div>
</div>
<div class="inputContainer">
<input is="emby-input" id="txtRecordingPath" type="text" label="Recording Path:" />
<div class="fieldDescription">
The location to store your recordings on your receiver eg. /hdd/movie/ (optional)
</div>
</div>
<label class="checkboxContainer">
<input is="emby-checkbox" type="checkbox" id="chkDebugLogging" />
<span>Enable VuPlus debug logging</span>
</label>
<div>
<button is="emby-button" type="submit" class="raised button-submit block"><span>Save</span></button>
</div>
</form>
</div>
</div>
<script type="text/javascript">
var VuPlusConfigurationPage = {
pluginUniqueId: "9564ac10-af23-39bc-449f-624f23cfa48f"
};
$('.VuPlusConfigurationPage').on('pageshow', function (event) {
Dashboard.showLoadingMsg();
var page = this;
ApiClient.getPluginConfiguration(VuPlusConfigurationPage.pluginUniqueId).then(function (config) {
$('#txtHostName', page).val(config.HostName || "");
$('#txtStreamingPort', page).val(config.StreamingPort || "");
$('#txtWebInterfacePort', page).val(config.WebInterfacePort || "");
$('#txtWebInterfaceUsername', page).val(config.WebInterfaceUsername || "");
$('#txtWebInterfacePassword', page).val(config.WebInterfacePassword || "");
$('#chkUseSecureHTTPS', page).checked(config.UseSecureHTTPS || false).checkboxradio("refresh");
$('#chkOnlyOneBouquet', page).checked(config.OnlyOneBouquet || false).checkboxradio("refresh");
$('#txtTVBouquet', page).val(config.TVBouquet || "");
$('#chkZapToChannel', page).checked(config.ZapToChannel || false).checkboxradio("refresh");
$('#chkFetchPiconsFromWebInterface', page).checked(config.FetchPiconsFromWebInterface || false).checkboxradio("refresh");
$('#txtPiconsPath', page).val(config.PiconsPath || "");
$('#txtRecordingPath', page).val(config.RecordingPath || "");
$('#chkDebugLogging', page).checked(config.EnableDebugLogging || false).checkboxradio("refresh");
Dashboard.hideLoadingMsg();
});
});
$('.VuPlusConfigurationForm').on('submit', function (e) {
Dashboard.showLoadingMsg();
var form = this;
ApiClient.getPluginConfiguration(VuPlusConfigurationPage.pluginUniqueId).then(function (config) {
//reset TV bouquet reference if TV Bouquet changed
//if (config.TVBouquet != $('#txtTVBouquet', form).val()) {
// config.tvBouquetSRef = '';
//}
//reset TV bouquet reference if Only 1 Bouquet not set
//if ($('#chkOnlyOneBouquet', form).checked()) {
//}
//else
//{
// config.tvBouquetSRef = '';
//}
config.HostName = $('#txtHostName', form).val();
config.StreamingPort = $('#txtStreamingPort', form).val();
config.WebInterfacePort = $('#txtWebInterfacePort', form).val();
config.WebInterfaceUsername = $('#txtWebInterfaceUsername', form).val();
config.WebInterfacePassword = $('#txtWebInterfacePassword', form).val();
config.UseSecureHTTPS = $('#chkUseSecureHTTPS', form).checked();
config.OnlyOneBouquet = $('#chkOnlyOneBouquet', form).checked();
config.TVBouquet = $('#txtTVBouquet', form).val();
config.ZapToChannel = $('#chkZapToChannel', form).checked();
config.FetchPiconsFromWebInterface = $('#chkFetchPiconsFromWebInterface', form).checked();
config.PiconsPath = $('#txtPiconsPath', form).val();
config.RecordingPath = $('#txtRecordingPath', form).val();
config.EnableDebugLogging = $('#chkDebugLogging', form).checked();
ApiClient.updatePluginConfiguration(VuPlusConfigurationPage.pluginUniqueId, config).then(Dashboard.processPluginConfigurationUpdateResult);
});
// Disable default form submission
return false;
});
</script>
</div>
</body>
</html>
@@ -1,24 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.1</TargetFrameworks>
<AssemblyVersion>3.1.8</AssemblyVersion>
<FileVersion>3.1.8</FileVersion>
</PropertyGroup>
<ItemGroup>
<None Remove="Configuration\configPage.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Configuration\configPage.html" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Jellyfin.Common" Version="10.6.0" />
<PackageReference Include="Jellyfin.Naming" Version="10.6.0" />
<PackageReference Include="Jellyfin.Controller" Version="10.6.0" />
<PackageReference Include="Jellyfin.Model" Version="10.6.0" />
</ItemGroup>
</Project>
+10 -10
View File
@@ -1,32 +1,32 @@
--- ---
# The name of the plugin; official plugins always start "jellyfin-plugin-" # The name of the plugin; official plugins always start "jellyfin-plugin-"
name: "jellyfin-plugin-vuplus" name: "jellyfin-plugin-enigma2"
# The GUID of the plugin, found in Plugin.cs # The GUID of the plugin, found in Plugin.cs
guid: "9564ac10-af23-39bc-449f-624f23cfa48f" 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: "3.1.8" # Please increment with each pull request version: "5.0.0.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.
targetAbi: "10.6.0" # The earliest binary-compatible version targetAbi: "10.8.0.0" # The earliest binary-compatible version
framework: "net6.0"
# The owner name of the plugin, "jellyfin" for official plugins. Change # The owner name of the plugin, "jellyfin" for official plugins. Change
# to your own name if you wish to remain a 3rd-party plugin. # to your own name if you wish to remain a 3rd-party plugin.
owner: "knackebrot" owner: "knackebrot"
# A short description of the plugin # A short description of the plugin
overview: "VU+" overview: "Enigma2"
# A longer and more detailed description of the plugin; use multiple # A longer and more detailed description of the plugin; use multiple
# lines as required for readability. # lines as required for readability.
description: > description: >
Plugin for Jellyfin to allow it to view channels, browse epg, set and delete timers, play recordings etc. Live TV plugin for watching Enigma 2 channels and recordings
# The plugin category, in a general sense. These fields are dynamic. # The plugin category, in a general sense. These fields are dynamic.
category: "Live TV" category: "Live TV"
@@ -35,10 +35,10 @@ category: "Live TV"
# Include the main output file, as well as any dependency `.dll`s that # Include the main output file, as well as any dependency `.dll`s that
# might be required for the plugin to run. # might be required for the plugin to run.
artifacts: artifacts:
- "MediaBrowser.Plugins.VuPlus.dll" - "Jellyfin.Plugin.Enigma2.dll"
# Build information values for the build infrastructure; these should # Build information values for the build infrastructure; these should
# not need to be changed usually. # not need to be changed usually.
build_type: "dotnet" build_type: "dotnet"
dotnet_configuration: "Release" dotnet_configuration: "Release"
dotnet_framework: "netstandard2.1" dotnet_framework: "net6.0"