diff --git a/ErsatzTV.Core/FFmpeg/FFmpegProcessBuilder.cs b/ErsatzTV.Core/FFmpeg/FFmpegProcessBuilder.cs
index 629c1163f..4ffd0b858 100644
--- a/ErsatzTV.Core/FFmpeg/FFmpegProcessBuilder.cs
+++ b/ErsatzTV.Core/FFmpeg/FFmpegProcessBuilder.cs
@@ -225,7 +225,8 @@ namespace ErsatzTV.Core.FFmpeg
public FFmpegProcessBuilder WithErrorText(IDisplaySize desiredResolution, string text)
{
- const string FONT_FILE = "fontfile=Resources/Roboto-Regular.ttf";
+ string fontPath = Path.Combine(FileSystemLayout.ResourcesCacheFolder, "Roboto-Regular.ttf");
+ var fontFile = $"fontfile={fontPath}";
const string FONT_COLOR = "fontcolor=white";
const string X = "x=(w-text_w)/2";
const string Y = "y=(h-text_h)/3*2";
@@ -233,7 +234,7 @@ namespace ErsatzTV.Core.FFmpeg
string fontSize = text.Length > 80 ? "fontsize=30" : text.Length > 60 ? "fontsize=40" : "fontsize=60";
return WithFilterComplex(
- $"[0:0]scale={desiredResolution.Width}:{desiredResolution.Height},drawtext={FONT_FILE}:{fontSize}:{FONT_COLOR}:{X}:{Y}:text='{text}'[v]",
+ $"[0:0]scale={desiredResolution.Width}:{desiredResolution.Height},drawtext={fontFile}:{fontSize}:{FONT_COLOR}:{X}:{Y}:text='{text}'[v]",
"[v]",
"1:a");
}
diff --git a/ErsatzTV.Core/FFmpeg/FFmpegProcessService.cs b/ErsatzTV.Core/FFmpeg/FFmpegProcessService.cs
index bcf46c71a..dadbbd3c3 100644
--- a/ErsatzTV.Core/FFmpeg/FFmpegProcessService.cs
+++ b/ErsatzTV.Core/FFmpeg/FFmpegProcessService.cs
@@ -1,5 +1,6 @@
using System;
using System.Diagnostics;
+using System.IO;
using System.Threading.Tasks;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.FFmpeg;
@@ -110,7 +111,7 @@ namespace ErsatzTV.Core.FFmpeg
.WithQuiet()
.WithFormatFlags(playbackSettings.FormatFlags)
.WithRealtimeOutput(playbackSettings.RealtimeOutput)
- .WithLoopedImage("Resources/background.png")
+ .WithLoopedImage(Path.Combine(FileSystemLayout.ResourcesCacheFolder, "background.png"))
.WithLibavfilter()
.WithInput("anullsrc")
.WithErrorText(desiredResolution, errorMessage)
diff --git a/ErsatzTV.Core/FileSystemLayout.cs b/ErsatzTV.Core/FileSystemLayout.cs
index 7375bc522..1072234a4 100644
--- a/ErsatzTV.Core/FileSystemLayout.cs
+++ b/ErsatzTV.Core/FileSystemLayout.cs
@@ -16,6 +16,7 @@ namespace ErsatzTV.Core
public static readonly string LogDatabasePath = Path.Combine(AppDataFolder, "logs.sqlite3");
public static readonly string LegacyImageCacheFolder = Path.Combine(AppDataFolder, "cache", "images");
+ public static readonly string ResourcesCacheFolder = Path.Combine(AppDataFolder, "cache", "resources");
public static readonly string PlexSecretsPath = Path.Combine(AppDataFolder, "plex-secrets.json");
public static readonly string JellyfinSecretsPath = Path.Combine(AppDataFolder, "jellyfin-secrets.json");
diff --git a/ErsatzTV/ErsatzTV.csproj b/ErsatzTV/ErsatzTV.csproj
index f7b0e9fcd..d7d2ff03d 100644
--- a/ErsatzTV/ErsatzTV.csproj
+++ b/ErsatzTV/ErsatzTV.csproj
@@ -51,12 +51,9 @@
-
- Always
-
-
- Always
-
+
+
+
diff --git a/ErsatzTV/Services/RunOnce/ResourceExtractorService.cs b/ErsatzTV/Services/RunOnce/ResourceExtractorService.cs
new file mode 100644
index 000000000..8be066516
--- /dev/null
+++ b/ErsatzTV/Services/RunOnce/ResourceExtractorService.cs
@@ -0,0 +1,42 @@
+using System.IO;
+using System.Reflection;
+using System.Threading;
+using System.Threading.Tasks;
+using ErsatzTV.Core;
+using Microsoft.Extensions.Hosting;
+
+namespace ErsatzTV.Services.RunOnce
+{
+ public class ResourceExtractorService : IHostedService
+ {
+ public async Task StartAsync(CancellationToken cancellationToken)
+ {
+ if (!Directory.Exists(FileSystemLayout.ResourcesCacheFolder))
+ {
+ Directory.CreateDirectory(FileSystemLayout.ResourcesCacheFolder);
+ }
+
+ Assembly assembly = typeof(ResourceExtractorService).GetTypeInfo().Assembly;
+
+ await ExtractResource(assembly, "background.png", cancellationToken);
+ await ExtractResource(assembly, "ErsatzTV.png", cancellationToken);
+ await ExtractResource(assembly, "Roboto-Regular.ttf", cancellationToken);
+ }
+
+ public Task StopAsync(CancellationToken cancellationToken)
+ {
+ return Task.CompletedTask;
+ }
+
+ private async Task ExtractResource(Assembly assembly, string name, CancellationToken cancellationToken)
+ {
+ await using Stream resource = assembly.GetManifestResourceStream($"ErsatzTV.Resources.{name}");
+ if (resource != null)
+ {
+ await using FileStream fs = File.Create(
+ Path.Combine(FileSystemLayout.ResourcesCacheFolder, name));
+ await resource.CopyToAsync(fs, cancellationToken);
+ }
+ }
+ }
+}
diff --git a/ErsatzTV/Startup.cs b/ErsatzTV/Startup.cs
index 55cfc871f..fe4f48dbb 100644
--- a/ErsatzTV/Startup.cs
+++ b/ErsatzTV/Startup.cs
@@ -255,6 +255,7 @@ namespace ErsatzTV
services.AddHostedService();
services.AddHostedService();
services.AddHostedService();
+ services.AddHostedService();
services.AddHostedService();
services.AddHostedService();
services.AddHostedService();