190 lines
6.6 KiB
C#
190 lines
6.6 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using MediaBrowser.Common.Configuration;
|
|
using MediaBrowser.Controller.Configuration;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace JellyfinPlugin
|
|
{
|
|
public class WrapperGenerator : IHostedService
|
|
{
|
|
private readonly ILogger<WrapperGenerator> _logger;
|
|
private readonly IApplicationPaths _appPaths;
|
|
private readonly IServerConfigurationManager _configManager;
|
|
|
|
public WrapperGenerator(ILogger<WrapperGenerator> logger, IApplicationPaths appPaths, IServerConfigurationManager configManager)
|
|
{
|
|
_logger = logger;
|
|
_appPaths = appPaths;
|
|
_configManager = configManager;
|
|
}
|
|
|
|
public Task StartAsync(CancellationToken cancellationToken)
|
|
{
|
|
GenerateAndSetWrapper();
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public Task StopAsync(CancellationToken cancellationToken)
|
|
{
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private void GenerateAndSetWrapper()
|
|
{
|
|
try
|
|
{
|
|
var mode = Plugin.Instance!.Configuration.PlaybackMode;
|
|
if (mode == "Client")
|
|
{
|
|
// Jeżeli wybrano tylko klienta, nie nadpisujemy ffmpeg
|
|
return;
|
|
}
|
|
|
|
// Przygotowujemy zamianę pliku ffmpeg bezpośrednio w /usr/lib/jellyfin-ffmpeg/ffmpeg
|
|
string defaultFfmpeg = "/usr/lib/jellyfin-ffmpeg/ffmpeg";
|
|
string origFfmpeg = "/usr/lib/jellyfin-ffmpeg/ffmpeg.original";
|
|
string realFfmpegPath = origFfmpeg;
|
|
|
|
if (!File.Exists(origFfmpeg))
|
|
{
|
|
if (File.Exists(defaultFfmpeg))
|
|
{
|
|
try
|
|
{
|
|
File.Move(defaultFfmpeg, origFfmpeg);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Nie udało się przenieść {DefaultFfmpeg} do {OrigFfmpeg}", defaultFfmpeg, origFfmpeg);
|
|
realFfmpegPath = defaultFfmpeg;
|
|
}
|
|
}
|
|
else if (File.Exists("/usr/bin/ffmpeg"))
|
|
{
|
|
realFfmpegPath = "/usr/bin/ffmpeg";
|
|
}
|
|
}
|
|
|
|
string wrapperDir = Path.Combine(_appPaths.PluginsPath, "BlackBarRemover");
|
|
Directory.CreateDirectory(wrapperDir);
|
|
string wrapperPath = Path.Combine(wrapperDir, "ffmpeg");
|
|
|
|
string script = $@"#!/bin/bash
|
|
REAL_FFMPEG=""{realFfmpegPath}""
|
|
|
|
INPUT_FILE=""""
|
|
for (( i=1; i<=$#; i++ )); do
|
|
arg=""${{!i}}""
|
|
if [[ ""$arg"" == ""-i"" ]]; then
|
|
let next_idx=i+1
|
|
if [ $next_idx -le $# ]; then
|
|
INPUT_FILE=""${{!next_idx}}""
|
|
fi
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [ -n ""$INPUT_FILE"" ]; then
|
|
CLEAN_PATH=$(echo ""$INPUT_FILE"" | tr -d '""' | sed 's/^file://')
|
|
|
|
CROP_DATA=$(curl -s --max-time 1 -G --data-urlencode ""Path=$CLEAN_PATH"" http://127.0.0.1:8096/BlackBarRemover/CropByPath)
|
|
|
|
if [ -n ""$CROP_DATA"" ] && [ ""$CROP_DATA"" != """" ]; then
|
|
# Modyfikujemy argumenty w locie
|
|
declare -a NEW_ARGS
|
|
HAS_VF=0
|
|
IS_COPY=0
|
|
|
|
for (( i=1; i<=$#; i++ )); do
|
|
arg=""${{!i}}""
|
|
|
|
if [[ ""$arg"" == ""copy"" ]]; then
|
|
let prev_idx=i-1
|
|
prev_arg=""""
|
|
if [ $prev_idx -gt 0 ]; then
|
|
prev_arg=""${{!prev_idx}}""
|
|
fi
|
|
if [[ ""$prev_arg"" == *codec:v* ]] || [[ ""$prev_arg"" == *-c:v* ]] || [[ ""$prev_arg"" == *-vcodec* ]]; then
|
|
IS_COPY=1
|
|
fi
|
|
fi
|
|
|
|
if [[ ""$arg"" == ""-vf"" ]]; then
|
|
HAS_VF=1
|
|
NEW_ARGS+=(""-vf"")
|
|
next_arg=""""
|
|
let next_idx=i+1
|
|
if [ $next_idx -le $# ]; then
|
|
next_arg=""${{!next_idx}}""
|
|
fi
|
|
NEW_ARGS+=(""crop=$CROP_DATA,$next_arg"")
|
|
let i++
|
|
continue
|
|
fi
|
|
|
|
NEW_ARGS+=(""$arg"")
|
|
done
|
|
|
|
# Jeżeli Jellyfin nadal upiera się przy copy, nie możemy wstrzyknąć filtra crop (bo zcrashuje FFmpega)
|
|
if [ $IS_COPY -eq 1 ]; then
|
|
exec ""$REAL_FFMPEG"" ""$@""
|
|
exit 0
|
|
fi
|
|
|
|
if [ $HAS_VF -eq 0 ]; then
|
|
NEW_ARGS+=(""-vf"")
|
|
NEW_ARGS+=(""crop=$CROP_DATA"")
|
|
fi
|
|
|
|
exec ""$REAL_FFMPEG"" ""${{NEW_ARGS[@]}}""
|
|
exit 0
|
|
fi
|
|
fi
|
|
|
|
exec ""$REAL_FFMPEG"" ""$@""
|
|
";
|
|
File.WriteAllText(wrapperPath, script);
|
|
if (File.Exists(origFfmpeg) || defaultFfmpeg != origFfmpeg)
|
|
{
|
|
try
|
|
{
|
|
File.WriteAllText(defaultFfmpeg, script);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Nie udało się zapisać skryptu wrappera do {DefaultFfmpeg}", defaultFfmpeg);
|
|
}
|
|
}
|
|
|
|
if (OperatingSystem.IsLinux() || OperatingSystem.IsFreeBSD() || OperatingSystem.IsMacOS())
|
|
{
|
|
string[] pathsToChmod = new[] { wrapperPath, defaultFfmpeg };
|
|
foreach (var path in pathsToChmod)
|
|
{
|
|
if (!File.Exists(path)) continue;
|
|
try
|
|
{
|
|
File.SetUnixFileMode(path, UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute | UnixFileMode.GroupRead | UnixFileMode.GroupExecute | UnixFileMode.OtherRead | UnixFileMode.OtherExecute);
|
|
}
|
|
catch
|
|
{
|
|
var proc = System.Diagnostics.Process.Start("chmod", $"+x \"{path}\"");
|
|
proc?.WaitForExit();
|
|
}
|
|
}
|
|
}
|
|
|
|
_logger.LogInformation("Wygenerowano skrypt FFmpeg Wrapper w lokalizacji: {Path} oraz {DefaultFfmpeg}", wrapperPath, defaultFfmpeg);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Błąd podczas generowania i ustawiania skryptu FFmpeg wrapper.");
|
|
}
|
|
}
|
|
}
|
|
}
|