test 6
This commit is contained in:
@@ -6,10 +6,17 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
|
|
||||||
namespace Jellyfin.Plugin.Seasonals.Api;
|
namespace Jellyfin.Plugin.Seasonals.Api;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Controller for serving seasonal resources and configuration.
|
||||||
|
/// </summary>
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("Seasonals")]
|
[Route("Seasonals")]
|
||||||
public class SeasonalsController : ControllerBase
|
public class SeasonalsController : ControllerBase
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current plugin configuration.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The configuration object.</returns>
|
||||||
[HttpGet("Config")]
|
[HttpGet("Config")]
|
||||||
[Produces("application/json")]
|
[Produces("application/json")]
|
||||||
public ActionResult<object> GetConfig()
|
public ActionResult<object> GetConfig()
|
||||||
@@ -22,11 +29,16 @@ public class SeasonalsController : ControllerBase
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Serves embedded resources.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path to the resource.</param>
|
||||||
|
/// <returns>The resource file.</returns>
|
||||||
[HttpGet("Resources/{*path}")]
|
[HttpGet("Resources/{*path}")]
|
||||||
public ActionResult GetResource(string path)
|
public ActionResult GetResource(string path)
|
||||||
{
|
{
|
||||||
// Sanitize path
|
// Sanitize path
|
||||||
if (string.IsNullOrWhiteSpace(path) || path.Contains(".."))
|
if (string.IsNullOrWhiteSpace(path) || path.Contains("..", StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
return BadRequest();
|
return BadRequest();
|
||||||
}
|
}
|
||||||
@@ -47,7 +59,7 @@ public class SeasonalsController : ControllerBase
|
|||||||
return File(stream, contentType);
|
return File(stream, contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetContentType(string path)
|
private static string GetContentType(string path)
|
||||||
{
|
{
|
||||||
if (path.EndsWith(".js", StringComparison.OrdinalIgnoreCase)) return "application/javascript";
|
if (path.EndsWith(".js", StringComparison.OrdinalIgnoreCase)) return "application/javascript";
|
||||||
if (path.EndsWith(".css", StringComparison.OrdinalIgnoreCase)) return "text/css";
|
if (path.EndsWith(".css", StringComparison.OrdinalIgnoreCase)) return "text/css";
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
<button is="emby-button" type="submit" class="raised button-submit block emby-button">
|
<button is="emby-button" type="submit" class="raised button-submit block emby-button">
|
||||||
<span>Save</span>
|
<span>Save</span>
|
||||||
</button>
|
</button>
|
||||||
|
<div class="fieldDescription" style="margin-top: 1em;">Please reload the page (F5) after saving for changes to take effect.</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
<Authors>CodeDevMLH</Authors>
|
<Authors>CodeDevMLH</Authors>
|
||||||
<Company>CodeDevMLH</Company>
|
<Company>CodeDevMLH</Company>
|
||||||
<Product>Jellyfin Seasonals Plugin</Product>
|
<Product>Jellyfin Seasonals Plugin</Product>
|
||||||
|
<Version>1.0.0.0</Version>
|
||||||
<PackageProjectUrl>https://github.com/CodeDevMLH/jellyfin-plugin-seasonals</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/CodeDevMLH/jellyfin-plugin-seasonals</PackageProjectUrl>
|
||||||
<RepositoryUrl>https://github.com/CodeDevMLH/jellyfin-plugin-seasonals</RepositoryUrl>
|
<RepositoryUrl>https://github.com/CodeDevMLH/jellyfin-plugin-seasonals</RepositoryUrl>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -26,12 +27,6 @@
|
|||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
|
|
||||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556" PrivateAssets="All" />
|
|
||||||
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Remove="Configuration\configPage.html" />
|
<None Remove="Configuration\configPage.html" />
|
||||||
<EmbeddedResource Include="Configuration\configPage.html" />
|
<EmbeddedResource Include="Configuration\configPage.html" />
|
||||||
|
|||||||
@@ -1,24 +1,35 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Reflection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
|
|
||||||
namespace Jellyfin.Plugin.Seasonals;
|
namespace Jellyfin.Plugin.Seasonals;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles the injection of the Seasonals script into the Jellyfin web interface.
|
||||||
|
/// </summary>
|
||||||
public class ScriptInjector
|
public class ScriptInjector
|
||||||
{
|
{
|
||||||
private readonly IApplicationPaths _appPaths;
|
private readonly IApplicationPaths _appPaths;
|
||||||
private readonly ILogger<ScriptInjector> _logger;
|
private readonly ILogger<ScriptInjector> _logger;
|
||||||
private const string ScriptTag = "<script src=\"/Seasonals/Resources/seasonals.js\"></script>";
|
private const string ScriptTag = "<script src=\"Seasonals/Resources/seasonals.js\"></script>";
|
||||||
private const string Marker = "</body>";
|
private const string Marker = "</body>";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ScriptInjector"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="appPaths">The application paths.</param>
|
||||||
|
/// <param name="logger">The logger.</param>
|
||||||
public ScriptInjector(IApplicationPaths appPaths, ILogger<ScriptInjector> logger)
|
public ScriptInjector(IApplicationPaths appPaths, ILogger<ScriptInjector> logger)
|
||||||
{
|
{
|
||||||
_appPaths = appPaths;
|
_appPaths = appPaths;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Injects the script tag into index.html if it's not already present.
|
||||||
|
/// </summary>
|
||||||
public void Inject()
|
public void Inject()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -38,14 +49,15 @@ public class ScriptInjector
|
|||||||
}
|
}
|
||||||
|
|
||||||
var content = File.ReadAllText(indexPath);
|
var content = File.ReadAllText(indexPath);
|
||||||
if (content.Contains(ScriptTag))
|
if (content.Contains(ScriptTag, StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Seasonals script already injected.");
|
_logger.LogInformation("Seasonals script already injected.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var newContent = content.Replace(Marker, $"{ScriptTag}\n{Marker}");
|
// Insert before the closing body tag
|
||||||
if (newContent == content)
|
var newContent = content.Replace(Marker, $"{ScriptTag}\n{Marker}", StringComparison.Ordinal);
|
||||||
|
if (string.Equals(newContent, content, StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Could not find closing body tag in index.html. Script injection skipped.");
|
_logger.LogWarning("Could not find closing body tag in index.html. Script injection skipped.");
|
||||||
return;
|
return;
|
||||||
@@ -60,20 +72,35 @@ public class ScriptInjector
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the script tag from index.html.
|
||||||
|
/// </summary>
|
||||||
public void Remove()
|
public void Remove()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var webPath = GetWebPath();
|
var webPath = GetWebPath();
|
||||||
if (string.IsNullOrEmpty(webPath)) return;
|
if (string.IsNullOrEmpty(webPath))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var indexPath = Path.Combine(webPath, "index.html");
|
var indexPath = Path.Combine(webPath, "index.html");
|
||||||
if (!File.Exists(indexPath)) return;
|
if (!File.Exists(indexPath))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var content = File.ReadAllText(indexPath);
|
var content = File.ReadAllText(indexPath);
|
||||||
if (!content.Contains(ScriptTag)) return;
|
if (!content.Contains(ScriptTag, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to remove with newline first, then just the tag to ensure clean removal
|
||||||
|
var newContent = content.Replace($"{ScriptTag}\n", "", StringComparison.Ordinal)
|
||||||
|
.Replace(ScriptTag, "", StringComparison.Ordinal);
|
||||||
|
|
||||||
var newContent = content.Replace(ScriptTag, "").Replace($"{ScriptTag}\n", "");
|
|
||||||
File.WriteAllText(indexPath, newContent);
|
File.WriteAllText(indexPath, newContent);
|
||||||
_logger.LogInformation("Successfully removed Seasonals script from index.html.");
|
_logger.LogInformation("Successfully removed Seasonals script from index.html.");
|
||||||
}
|
}
|
||||||
@@ -83,37 +110,14 @@ public class ScriptInjector
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the path to the Jellyfin web interface directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The path to the web directory, or null if not found.</returns>
|
||||||
private string? GetWebPath()
|
private string? GetWebPath()
|
||||||
{
|
{
|
||||||
// Try to find the web path using IApplicationPaths
|
// Use reflection to access WebPath property to ensure compatibility across different Jellyfin versions
|
||||||
// Note: The property name might vary depending on the Jellyfin version,
|
var prop = _appPaths.GetType().GetProperty("WebPath", BindingFlags.Instance | BindingFlags.Public);
|
||||||
// but usually it's accessible via the configuration or standard paths.
|
return prop?.GetValue(_appPaths) as string;
|
||||||
// For this plugin context, we'll try to rely on the standard path structure if IApplicationPaths doesn't expose it directly
|
|
||||||
// or if we need to infer it.
|
|
||||||
|
|
||||||
// In many Jellyfin versions, appPaths.WebPath is the property.
|
|
||||||
// However, since we are in a plugin, we might need to use reflection if the interface doesn't expose it in the reference assembly,
|
|
||||||
// or just assume it's there.
|
|
||||||
|
|
||||||
// Let's try to use the property if it exists.
|
|
||||||
// If the compilation fails, we will adjust.
|
|
||||||
// For now, we assume 'WebPath' is available on IApplicationPaths implementation
|
|
||||||
// but it might not be on the interface in the nuget package.
|
|
||||||
|
|
||||||
// Workaround: Check known locations if property is missing or use reflection.
|
|
||||||
|
|
||||||
// Attempt 1: Reflection to get WebPath property (safest if interface varies)
|
|
||||||
var prop = _appPaths.GetType().GetProperty("WebPath");
|
|
||||||
if (prop != null)
|
|
||||||
{
|
|
||||||
return prop.GetValue(_appPaths) as string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt 2: Guess based on ProgramDataPath (common in Windows)
|
|
||||||
// Usually <ProgramData>/jellyfin/web or <InstallDir>/jellyfin-web
|
|
||||||
|
|
||||||
// Let's try to look relative to the application executable if possible, but that's hard from a plugin.
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,10 +9,7 @@
|
|||||||
"Jellyfin.Plugin.Seasonals/1.0.0.0": {
|
"Jellyfin.Plugin.Seasonals/1.0.0.0": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Jellyfin.Controller": "10.11.0",
|
"Jellyfin.Controller": "10.11.0",
|
||||||
"Jellyfin.Model": "10.11.0",
|
"Jellyfin.Model": "10.11.0"
|
||||||
"SerilogAnalyzer": "0.15.0",
|
|
||||||
"SmartAnalyzers.MultithreadingAnalyzer": "1.1.31",
|
|
||||||
"StyleCop.Analyzers": "1.2.0-beta.556"
|
|
||||||
},
|
},
|
||||||
"runtime": {
|
"runtime": {
|
||||||
"Jellyfin.Plugin.Seasonals.dll": {}
|
"Jellyfin.Plugin.Seasonals.dll": {}
|
||||||
@@ -166,14 +163,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Polly.Core/8.6.4": {},
|
"Polly.Core/8.6.4": {},
|
||||||
"SerilogAnalyzer/0.15.0": {},
|
|
||||||
"SmartAnalyzers.MultithreadingAnalyzer/1.1.31": {},
|
|
||||||
"StyleCop.Analyzers/1.2.0-beta.556": {
|
|
||||||
"dependencies": {
|
|
||||||
"StyleCop.Analyzers.Unstable": "1.2.0.556"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"StyleCop.Analyzers.Unstable/1.2.0.556": {},
|
|
||||||
"System.Globalization/4.3.0": {
|
"System.Globalization/4.3.0": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.NETCore.Platforms": "1.1.0",
|
"Microsoft.NETCore.Platforms": "1.1.0",
|
||||||
@@ -421,34 +410,6 @@
|
|||||||
"path": "polly.core/8.6.4",
|
"path": "polly.core/8.6.4",
|
||||||
"hashPath": "polly.core.8.6.4.nupkg.sha512"
|
"hashPath": "polly.core.8.6.4.nupkg.sha512"
|
||||||
},
|
},
|
||||||
"SerilogAnalyzer/0.15.0": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-sVpwfls4MfNnwIXLSGCgaUnV+c9kgJ8ia6GsyRcpd4Vs3gLogSDtSYBYrre2K2u/PNMo8GgG09RehwVnze70Tw==",
|
|
||||||
"path": "seriloganalyzer/0.15.0",
|
|
||||||
"hashPath": "seriloganalyzer.0.15.0.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"SmartAnalyzers.MultithreadingAnalyzer/1.1.31": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-2f2k7bbhDd132ArglCKpzKoWBcp3uzbIFcb4aosnlqIKlfYKDE2HevBVRNVa+LkWFnjXFFWs47Bo96fu8iS//Q==",
|
|
||||||
"path": "smartanalyzers.multithreadinganalyzer/1.1.31",
|
|
||||||
"hashPath": "smartanalyzers.multithreadinganalyzer.1.1.31.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"StyleCop.Analyzers/1.2.0-beta.556": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-llRPgmA1fhC0I0QyFLEcjvtM2239QzKr/tcnbsjArLMJxJlu0AA5G7Fft0OI30pHF3MW63Gf4aSSsjc5m82J1Q==",
|
|
||||||
"path": "stylecop.analyzers/1.2.0-beta.556",
|
|
||||||
"hashPath": "stylecop.analyzers.1.2.0-beta.556.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"StyleCop.Analyzers.Unstable/1.2.0.556": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-zvn9Mqs/ox/83cpYPignI8hJEM2A93s2HkHs8HYMOAQW0PkampyoErAiIyKxgTLqbbad29HX/shv/6LGSjPJNQ==",
|
|
||||||
"path": "stylecop.analyzers.unstable/1.2.0.556",
|
|
||||||
"hashPath": "stylecop.analyzers.unstable.1.2.0.556.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"System.Globalization/4.3.0": {
|
"System.Globalization/4.3.0": {
|
||||||
"type": "package",
|
"type": "package",
|
||||||
"serviceable": true,
|
"serviceable": true,
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -4,6 +4,24 @@
|
|||||||
<name>Jellyfin.Plugin.Seasonals</name>
|
<name>Jellyfin.Plugin.Seasonals</name>
|
||||||
</assembly>
|
</assembly>
|
||||||
<members>
|
<members>
|
||||||
|
<member name="T:Jellyfin.Plugin.Seasonals.Api.SeasonalsController">
|
||||||
|
<summary>
|
||||||
|
Controller for serving seasonal resources and configuration.
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Jellyfin.Plugin.Seasonals.Api.SeasonalsController.GetConfig">
|
||||||
|
<summary>
|
||||||
|
Gets the current plugin configuration.
|
||||||
|
</summary>
|
||||||
|
<returns>The configuration object.</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:Jellyfin.Plugin.Seasonals.Api.SeasonalsController.GetResource(System.String)">
|
||||||
|
<summary>
|
||||||
|
Serves embedded resources.
|
||||||
|
</summary>
|
||||||
|
<param name="path">The path to the resource.</param>
|
||||||
|
<returns>The resource file.</returns>
|
||||||
|
</member>
|
||||||
<member name="T:Jellyfin.Plugin.Seasonals.Configuration.PluginConfiguration">
|
<member name="T:Jellyfin.Plugin.Seasonals.Configuration.PluginConfiguration">
|
||||||
<summary>
|
<summary>
|
||||||
Plugin configuration.
|
Plugin configuration.
|
||||||
@@ -51,5 +69,33 @@
|
|||||||
<member name="M:Jellyfin.Plugin.Seasonals.Plugin.GetPages">
|
<member name="M:Jellyfin.Plugin.Seasonals.Plugin.GetPages">
|
||||||
<inheritdoc />
|
<inheritdoc />
|
||||||
</member>
|
</member>
|
||||||
|
<member name="T:Jellyfin.Plugin.Seasonals.ScriptInjector">
|
||||||
|
<summary>
|
||||||
|
Handles the injection of the Seasonals script into the Jellyfin web interface.
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Jellyfin.Plugin.Seasonals.ScriptInjector.#ctor(MediaBrowser.Common.Configuration.IApplicationPaths,Microsoft.Extensions.Logging.ILogger{Jellyfin.Plugin.Seasonals.ScriptInjector})">
|
||||||
|
<summary>
|
||||||
|
Initializes a new instance of the <see cref="T:Jellyfin.Plugin.Seasonals.ScriptInjector"/> class.
|
||||||
|
</summary>
|
||||||
|
<param name="appPaths">The application paths.</param>
|
||||||
|
<param name="logger">The logger.</param>
|
||||||
|
</member>
|
||||||
|
<member name="M:Jellyfin.Plugin.Seasonals.ScriptInjector.Inject">
|
||||||
|
<summary>
|
||||||
|
Injects the script tag into index.html if it's not already present.
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Jellyfin.Plugin.Seasonals.ScriptInjector.Remove">
|
||||||
|
<summary>
|
||||||
|
Removes the script tag from index.html.
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Jellyfin.Plugin.Seasonals.ScriptInjector.GetWebPath">
|
||||||
|
<summary>
|
||||||
|
Retrieves the path to the Jellyfin web interface directory.
|
||||||
|
</summary>
|
||||||
|
<returns>The path to the web directory, or null if not found.</returns>
|
||||||
|
</member>
|
||||||
</members>
|
</members>
|
||||||
</doc>
|
</doc>
|
||||||
|
|||||||
59
RELEASE_GUIDE.md
Normal file
59
RELEASE_GUIDE.md
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
# Release & Update Guide
|
||||||
|
|
||||||
|
Diese Anleitung beschreibt die Schritte, die notwendig sind, um eine neue Version des **Seasonals** Plugins zu veröffentlichen.
|
||||||
|
|
||||||
|
## 1. Version erhöhen
|
||||||
|
|
||||||
|
Bevor du baust, musst du die Versionsnummer in den folgenden Dateien aktualisieren (z.B. von `1.0.0.0` auf `1.0.1.0`):
|
||||||
|
|
||||||
|
1. **`Jellyfin.Plugin.Seasonals/Jellyfin.Plugin.Seasonals.csproj`**
|
||||||
|
Suche nach `<Version>...</Version>` und ändere die Nummer.
|
||||||
|
|
||||||
|
2. **`build.yaml`**
|
||||||
|
Ändere den Wert bei `version: "..."`.
|
||||||
|
|
||||||
|
3. **`manifest.json`**
|
||||||
|
Füge einen neuen Eintrag oben in die `versions`-Liste ein (oder bearbeite den vorhandenen, wenn es noch kein Release gab).
|
||||||
|
* `version`: Deine neue Nummer.
|
||||||
|
* `changelog`: Was hat sich geändert?
|
||||||
|
* `timestamp`: Das aktuelle Datum (wird später aktualisiert).
|
||||||
|
* `checksum`: (wird nach dem Build aktualisiert).
|
||||||
|
|
||||||
|
## 2. Plugin bauen und packen
|
||||||
|
|
||||||
|
Führe den folgenden Befehl im Terminal (PowerShell) im Hauptverzeichnis aus. Dieser Befehl baut das Projekt, erstellt das ZIP-Archiv und berechnet direkt die Checksumme (Hash).
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
dotnet publish Jellyfin.Plugin.Seasonals/Jellyfin.Plugin.Seasonals.csproj --configuration Release --output bin/Publish; Compress-Archive -Path bin/Publish/* -DestinationPath bin/Publish/Jellyfin.Plugin.Seasonals.zip -Force; $hash = (Get-FileHash -Algorithm MD5 bin/Publish/Jellyfin.Plugin.Seasonals.zip).Hash.ToLower(); $time = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"); Write-Output "`n----------------------------------------"; Write-Output "NEUE CHECKSUMME (MD5): $hash"; Write-Output "ZEITSTEMPEL: $time"; Write-Output "----------------------------------------`n"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Manifest aktualisieren
|
||||||
|
|
||||||
|
Nachdem der Befehl durchgelaufen ist, siehst du am Ende eine Ausgabe wie:
|
||||||
|
|
||||||
|
```text
|
||||||
|
----------------------------------------
|
||||||
|
NEUE CHECKSUMME (MD5): ef8654666ffeae9695e660944f644ad3
|
||||||
|
ZEITSTEMPEL: 2025-12-15T12:34:56Z
|
||||||
|
----------------------------------------
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Kopiere die **Checksumme**.
|
||||||
|
2. Öffne `manifest.json`.
|
||||||
|
3. Füge die Checksumme bei deinem Versionseintrag unter `"checksum"` ein.
|
||||||
|
4. Kopiere den **Zeitstempel** und füge ihn unter `"timestamp"` ein.
|
||||||
|
5. Stelle sicher, dass die `sourceUrl` korrekt auf dein Repository zeigt.
|
||||||
|
|
||||||
|
## 4. Veröffentlichen
|
||||||
|
|
||||||
|
1. Lade die Datei `bin/Publish/Jellyfin.Plugin.Seasonals.zip` irgendwo hoch (z.B. GitHub Releases).
|
||||||
|
2. Stelle sicher, dass die `sourceUrl` im `manifest.json` auf diesen Download zeigt (oder auf das Repo, je nachdem wie Jellyfin das handhabt - meistens ist `sourceUrl` der Link zum ZIP).
|
||||||
|
* *Hinweis:* Wenn du das Plugin über ein Repo hostest, muss die URL im Manifest direkt auf die ZIP-Datei zeigen.
|
||||||
|
|
||||||
|
## Zusammenfassung der Dateien
|
||||||
|
|
||||||
|
| Datei | Zweck | Änderung nötig? |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| `Jellyfin.Plugin.Seasonals.csproj` | Definiert die DLL-Version | **Ja** |
|
||||||
|
| `build.yaml` | Build-Konfiguration | **Ja** |
|
||||||
|
| `manifest.json` | Plugin-Liste für Jellyfin | **Ja** (Version, Hash, Zeit) |
|
||||||
@@ -9,10 +9,7 @@
|
|||||||
"Jellyfin.Plugin.Seasonals/1.0.0.0": {
|
"Jellyfin.Plugin.Seasonals/1.0.0.0": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Jellyfin.Controller": "10.11.0",
|
"Jellyfin.Controller": "10.11.0",
|
||||||
"Jellyfin.Model": "10.11.0",
|
"Jellyfin.Model": "10.11.0"
|
||||||
"SerilogAnalyzer": "0.15.0",
|
|
||||||
"SmartAnalyzers.MultithreadingAnalyzer": "1.1.31",
|
|
||||||
"StyleCop.Analyzers": "1.2.0-beta.556"
|
|
||||||
},
|
},
|
||||||
"runtime": {
|
"runtime": {
|
||||||
"Jellyfin.Plugin.Seasonals.dll": {}
|
"Jellyfin.Plugin.Seasonals.dll": {}
|
||||||
@@ -166,14 +163,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Polly.Core/8.6.4": {},
|
"Polly.Core/8.6.4": {},
|
||||||
"SerilogAnalyzer/0.15.0": {},
|
|
||||||
"SmartAnalyzers.MultithreadingAnalyzer/1.1.31": {},
|
|
||||||
"StyleCop.Analyzers/1.2.0-beta.556": {
|
|
||||||
"dependencies": {
|
|
||||||
"StyleCop.Analyzers.Unstable": "1.2.0.556"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"StyleCop.Analyzers.Unstable/1.2.0.556": {},
|
|
||||||
"System.Globalization/4.3.0": {
|
"System.Globalization/4.3.0": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.NETCore.Platforms": "1.1.0",
|
"Microsoft.NETCore.Platforms": "1.1.0",
|
||||||
@@ -421,34 +410,6 @@
|
|||||||
"path": "polly.core/8.6.4",
|
"path": "polly.core/8.6.4",
|
||||||
"hashPath": "polly.core.8.6.4.nupkg.sha512"
|
"hashPath": "polly.core.8.6.4.nupkg.sha512"
|
||||||
},
|
},
|
||||||
"SerilogAnalyzer/0.15.0": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-sVpwfls4MfNnwIXLSGCgaUnV+c9kgJ8ia6GsyRcpd4Vs3gLogSDtSYBYrre2K2u/PNMo8GgG09RehwVnze70Tw==",
|
|
||||||
"path": "seriloganalyzer/0.15.0",
|
|
||||||
"hashPath": "seriloganalyzer.0.15.0.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"SmartAnalyzers.MultithreadingAnalyzer/1.1.31": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-2f2k7bbhDd132ArglCKpzKoWBcp3uzbIFcb4aosnlqIKlfYKDE2HevBVRNVa+LkWFnjXFFWs47Bo96fu8iS//Q==",
|
|
||||||
"path": "smartanalyzers.multithreadinganalyzer/1.1.31",
|
|
||||||
"hashPath": "smartanalyzers.multithreadinganalyzer.1.1.31.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"StyleCop.Analyzers/1.2.0-beta.556": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-llRPgmA1fhC0I0QyFLEcjvtM2239QzKr/tcnbsjArLMJxJlu0AA5G7Fft0OI30pHF3MW63Gf4aSSsjc5m82J1Q==",
|
|
||||||
"path": "stylecop.analyzers/1.2.0-beta.556",
|
|
||||||
"hashPath": "stylecop.analyzers.1.2.0-beta.556.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"StyleCop.Analyzers.Unstable/1.2.0.556": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-zvn9Mqs/ox/83cpYPignI8hJEM2A93s2HkHs8HYMOAQW0PkampyoErAiIyKxgTLqbbad29HX/shv/6LGSjPJNQ==",
|
|
||||||
"path": "stylecop.analyzers.unstable/1.2.0.556",
|
|
||||||
"hashPath": "stylecop.analyzers.unstable.1.2.0.556.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"System.Globalization/4.3.0": {
|
"System.Globalization/4.3.0": {
|
||||||
"type": "package",
|
"type": "package",
|
||||||
"serviceable": true,
|
"serviceable": true,
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -4,6 +4,24 @@
|
|||||||
<name>Jellyfin.Plugin.Seasonals</name>
|
<name>Jellyfin.Plugin.Seasonals</name>
|
||||||
</assembly>
|
</assembly>
|
||||||
<members>
|
<members>
|
||||||
|
<member name="T:Jellyfin.Plugin.Seasonals.Api.SeasonalsController">
|
||||||
|
<summary>
|
||||||
|
Controller for serving seasonal resources and configuration.
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Jellyfin.Plugin.Seasonals.Api.SeasonalsController.GetConfig">
|
||||||
|
<summary>
|
||||||
|
Gets the current plugin configuration.
|
||||||
|
</summary>
|
||||||
|
<returns>The configuration object.</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:Jellyfin.Plugin.Seasonals.Api.SeasonalsController.GetResource(System.String)">
|
||||||
|
<summary>
|
||||||
|
Serves embedded resources.
|
||||||
|
</summary>
|
||||||
|
<param name="path">The path to the resource.</param>
|
||||||
|
<returns>The resource file.</returns>
|
||||||
|
</member>
|
||||||
<member name="T:Jellyfin.Plugin.Seasonals.Configuration.PluginConfiguration">
|
<member name="T:Jellyfin.Plugin.Seasonals.Configuration.PluginConfiguration">
|
||||||
<summary>
|
<summary>
|
||||||
Plugin configuration.
|
Plugin configuration.
|
||||||
@@ -51,5 +69,33 @@
|
|||||||
<member name="M:Jellyfin.Plugin.Seasonals.Plugin.GetPages">
|
<member name="M:Jellyfin.Plugin.Seasonals.Plugin.GetPages">
|
||||||
<inheritdoc />
|
<inheritdoc />
|
||||||
</member>
|
</member>
|
||||||
|
<member name="T:Jellyfin.Plugin.Seasonals.ScriptInjector">
|
||||||
|
<summary>
|
||||||
|
Handles the injection of the Seasonals script into the Jellyfin web interface.
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Jellyfin.Plugin.Seasonals.ScriptInjector.#ctor(MediaBrowser.Common.Configuration.IApplicationPaths,Microsoft.Extensions.Logging.ILogger{Jellyfin.Plugin.Seasonals.ScriptInjector})">
|
||||||
|
<summary>
|
||||||
|
Initializes a new instance of the <see cref="T:Jellyfin.Plugin.Seasonals.ScriptInjector"/> class.
|
||||||
|
</summary>
|
||||||
|
<param name="appPaths">The application paths.</param>
|
||||||
|
<param name="logger">The logger.</param>
|
||||||
|
</member>
|
||||||
|
<member name="M:Jellyfin.Plugin.Seasonals.ScriptInjector.Inject">
|
||||||
|
<summary>
|
||||||
|
Injects the script tag into index.html if it's not already present.
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Jellyfin.Plugin.Seasonals.ScriptInjector.Remove">
|
||||||
|
<summary>
|
||||||
|
Removes the script tag from index.html.
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Jellyfin.Plugin.Seasonals.ScriptInjector.GetWebPath">
|
||||||
|
<summary>
|
||||||
|
Retrieves the path to the Jellyfin web interface directory.
|
||||||
|
</summary>
|
||||||
|
<returns>The path to the web directory, or null if not found.</returns>
|
||||||
|
</member>
|
||||||
</members>
|
</members>
|
||||||
</doc>
|
</doc>
|
||||||
|
|||||||
Binary file not shown.
@@ -13,8 +13,8 @@
|
|||||||
"changelog": "Initial release",
|
"changelog": "Initial release",
|
||||||
"targetAbi": "10.9.0.0",
|
"targetAbi": "10.9.0.0",
|
||||||
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Jellyfin-Seasonals-Plugin/raw/branch/main/bin/Publish/Jellyfin.Plugin.Seasonals.zip",
|
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Jellyfin-Seasonals-Plugin/raw/branch/main/bin/Publish/Jellyfin.Plugin.Seasonals.zip",
|
||||||
"checksum": "f7e8c352385768c118d1577d09dcff7e",
|
"checksum": "87990236bd9337eda22757423d896e22",
|
||||||
"timestamp": "2025-12-14T22:50:50Z"
|
"timestamp": "2025-12-14T23:50:27Z"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user