docs: clarify multi-targeting (.NET 9 and .NET 10) in README build instructions
This commit is contained in:
@@ -71,9 +71,40 @@ namespace JellyfinPlugin.Api
|
|||||||
let currentItemId = null;
|
let currentItemId = null;
|
||||||
let interceptedItemId = null;
|
let interceptedItemId = null;
|
||||||
|
|
||||||
|
function isTranscoding() {
|
||||||
|
try {
|
||||||
|
if (window.playbackManager) {
|
||||||
|
const currentPlayer = window.playbackManager.getCurrentPlayer();
|
||||||
|
if (currentPlayer && typeof currentPlayer.getPlayerState === 'function') {
|
||||||
|
const state = currentPlayer.getPlayerState();
|
||||||
|
if (state && state.PlayMethod) {
|
||||||
|
return state.PlayMethod === 'Transcode' || state.PlayMethod === 'DirectStream';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
const video = document.querySelector('video');
|
||||||
|
if (video && video.src) {
|
||||||
|
const src = video.src.toLowerCase();
|
||||||
|
if (src.includes('transcode') || src.includes('.m3u8') || src.includes('transcodereasons')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function applyCrop(cropData) {
|
function applyCrop(cropData) {
|
||||||
const video = document.querySelector('video');
|
const video = document.querySelector('video');
|
||||||
if (!video) return;
|
if (!video) return;
|
||||||
|
|
||||||
|
if (isTranscoding()) {
|
||||||
|
console.log('Black Bar Remover: Video is transcoded by server, skipping CSS crop.');
|
||||||
|
video.style.clipPath = '';
|
||||||
|
video.style.transform = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const parts = cropData.split(':');
|
const parts = cropData.split(':');
|
||||||
if (parts.length === 4) {
|
if (parts.length === 4) {
|
||||||
const w = parseInt(parts[0]);
|
const w = parseInt(parts[0]);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace JellyfinPlugin.Configuration
|
|||||||
// Czy wtyczka jest aktywna
|
// Czy wtyczka jest aktywna
|
||||||
public bool IsEnabled { get; set; } = true;
|
public bool IsEnabled { get; set; } = true;
|
||||||
|
|
||||||
// Tryb odtwarzania: "Server" (FFmpeg wrapper), "Client" (CSS injection w Web UI), "Both" (Obydwa naraz)
|
// Tryb odtwarzania: "Server" (FFmpeg wrapper), "Client" (CSS injection w Web UI), "Auto" (Automatyczny: CSS dla Web, FFmpeg dla aplikacji natywnych)
|
||||||
public string PlaybackMode { get; set; } = "Both";
|
public string PlaybackMode { get; set; } = "Auto";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,11 +26,11 @@
|
|||||||
<div class="selectContainer">
|
<div class="selectContainer">
|
||||||
<label class="selectLabel" for="selectPlaybackMode">Black Bar Removal Method:</label>
|
<label class="selectLabel" for="selectPlaybackMode">Black Bar Removal Method:</label>
|
||||||
<select is="emby-select" id="selectPlaybackMode" class="emby-select-withcolor">
|
<select is="emby-select" id="selectPlaybackMode" class="emby-select-withcolor">
|
||||||
|
<option value="Auto">Auto (CSS clip in Web, Transcode on Native Apps / Transcoded streams)</option>
|
||||||
<option value="Server">Server Only (FFmpeg Transcoding)</option>
|
<option value="Server">Server Only (FFmpeg Transcoding)</option>
|
||||||
<option value="Client">Client Only (CSS Clip in Jellyfin Web)</option>
|
<option value="Client">Client Only (CSS Clip in Jellyfin Web)</option>
|
||||||
<option value="Both">Both (Transcoding or CSS, depending on client)</option>
|
|
||||||
</select>
|
</select>
|
||||||
<div class="fieldDescription">Choose how the plugin should remove black bars. Server option forces transcoding (CPU/GPU load), Client option is lightweight but only works in web browsers.</div>
|
<div class="fieldDescription">Choose how the plugin should remove black bars. Auto mode uses lightweight CSS clipping for Web browser DirectPlay, and falls back to FFmpeg transcoding for native apps or unsupported video formats.</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -53,7 +53,9 @@
|
|||||||
ApiClient.getPluginConfiguration(BlackBarRemoverConfig.pluginUniqueId).then(function (config) {
|
ApiClient.getPluginConfiguration(BlackBarRemoverConfig.pluginUniqueId).then(function (config) {
|
||||||
$('#chkEnablePlugin', page).prop('checked', config.IsEnabled !== false);
|
$('#chkEnablePlugin', page).prop('checked', config.IsEnabled !== false);
|
||||||
$('#txtCropLimit', page).val(config.CropDetectLimit || 0.094);
|
$('#txtCropLimit', page).val(config.CropDetectLimit || 0.094);
|
||||||
$('#selectPlaybackMode', page).val(config.PlaybackMode || "Both");
|
var mode = config.PlaybackMode || "Auto";
|
||||||
|
if (mode === "Both") mode = "Auto";
|
||||||
|
$('#selectPlaybackMode', page).val(mode);
|
||||||
Dashboard.hideLoadingMsg();
|
Dashboard.hideLoadingMsg();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -60,6 +60,14 @@ namespace JellyfinPlugin
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isAutoMode = config.PlaybackMode == "Auto" || config.PlaybackMode == "Both";
|
||||||
|
if (isAutoMode && IsJellyfinWebClient(context))
|
||||||
|
{
|
||||||
|
// W trybie Auto dla przeglądarki Web pozwalamy na Direct Play (przycięcie wykona skrypt CSS w przeglądarce).
|
||||||
|
await nextMw().ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// --- HLS STREAM QUERY REWRITE ---
|
// --- HLS STREAM QUERY REWRITE ---
|
||||||
// If the client requests the m3u8 playlist, we simply tell Jellyfin NOT to allow video stream copy.
|
// If the client requests the m3u8 playlist, we simply tell Jellyfin NOT to allow video stream copy.
|
||||||
// This elegantly forces transcoding for the BEST supported codec without breaking FFmpeg tags/filters!
|
// This elegantly forces transcoding for the BEST supported codec without breaking FFmpeg tags/filters!
|
||||||
@@ -147,5 +155,43 @@ namespace JellyfinPlugin
|
|||||||
|
|
||||||
await nextMw().ConfigureAwait(false);
|
await nextMw().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsJellyfinWebClient(HttpContext context)
|
||||||
|
{
|
||||||
|
if (context.Request.Headers.TryGetValue("X-Emby-Authorization", out var authHeader) ||
|
||||||
|
context.Request.Headers.TryGetValue("Authorization", out authHeader))
|
||||||
|
{
|
||||||
|
var authStr = authHeader.ToString();
|
||||||
|
if (authStr.Contains("Client=\"Jellyfin Web\"", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
authStr.Contains("Client=\"Jellyfin%20Web\"", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
authStr.Contains("Client=Jellyfin Web", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.Request.Headers.TryGetValue("User-Agent", out var uaHeader))
|
||||||
|
{
|
||||||
|
var ua = uaHeader.ToString();
|
||||||
|
if (ua.Contains("JellyfinMediaPlayer", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
ua.Contains("Jellyfin-Android", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
ua.Contains("ExoPlayer", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
ua.Contains("okhttp", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
ua.Contains("Kodi", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ua.Contains("Mozilla", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
ua.Contains("Chrome", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
ua.Contains("Safari", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
ua.Contains("Firefox", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,12 +43,21 @@ This plugin has been verified and tested on:
|
|||||||
### Method 3: Building from Source
|
### Method 3: Building from Source
|
||||||
|
|
||||||
1. Clone this repository.
|
1. Clone this repository.
|
||||||
2. Build the plugin using the .NET 9 SDK:
|
2. Ensure you have the **.NET 9.0 SDK** and/or **.NET 10.0 SDK** installed (the project multi-targets both `net9.0` and `net10.0`).
|
||||||
|
3. Build the plugin for all targets:
|
||||||
```bash
|
```bash
|
||||||
dotnet build JellyfinPlugin/JellyfinPlugin.csproj -c Release
|
dotnet build JellyfinPlugin/JellyfinPlugin.csproj -c Release
|
||||||
```
|
```
|
||||||
3. Copy the compiled DLLs from `JellyfinPlugin/bin/Release/net9.0/` into a new folder named `BlackBarRemover` inside your Jellyfin plugins directory.
|
Or build for a specific target framework:
|
||||||
4. Restart the Jellyfin server.
|
```bash
|
||||||
|
# For Jellyfin 10.11 (.NET 9.0)
|
||||||
|
dotnet build JellyfinPlugin/JellyfinPlugin.csproj -c Release -f net9.0
|
||||||
|
|
||||||
|
# For Jellyfin 12.0 / 13.0 Unstable (.NET 10.0)
|
||||||
|
dotnet build JellyfinPlugin/JellyfinPlugin.csproj -c Release -f net10.0
|
||||||
|
```
|
||||||
|
4. Copy the compiled DLLs from `JellyfinPlugin/bin/Release/net9.0/` (for Jellyfin 10.11) or `JellyfinPlugin/bin/Release/net10.0/` (for Jellyfin 12.0+) into a new folder named `BlackBarRemover` inside your Jellyfin plugins directory (e.g., `/var/lib/jellyfin/plugins/BlackBarRemover/`).
|
||||||
|
5. Restart the Jellyfin server.
|
||||||
|
|
||||||
### Configuration & Initial Scan
|
### Configuration & Initial Scan
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user