Skip to content

Commit

Permalink
Merge pull request #10 from timia2109/feature/providers
Browse files Browse the repository at this point in the history
Feature/providers
  • Loading branch information
timia2109 authored Apr 16, 2024
2 parents 56c8288 + c1fe38b commit a03e6b3
Show file tree
Hide file tree
Showing 3,321 changed files with 409 additions and 3,519 deletions.
The diff you're trying to view is too large. We only load the first 3000 changed files.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -482,4 +482,5 @@ $RECYCLE.BIN/

# Vim temporary swap files
*.swp
appsettings.Local.json
appsettings.Local.json
Resources/*
6 changes: 0 additions & 6 deletions DisplayUtil.http

This file was deleted.

2 changes: 0 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,5 @@ RUN apt-get update \
&& rm -rf /var/lib/apt/lists/*

COPY build/ .
RUN mkdir Resources
COPY Resources/ ./Resources

ENTRYPOINT ["dotnet", "DisplayUtil.dll"]
2 changes: 1 addition & 1 deletion Layouting/IconElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace DisplayUtil.Layouting;
/// <param name="iconName">Name of the Icon</param>
/// <param name="height">Width of the Icon</param>
/// <param name="iconDrawer">The Icon Drawer</param>
public class IconElement(string iconName, int height, FaIconDrawer iconDrawer) : Element
public class IconElement(string iconName, int height, IconDrawer iconDrawer) : Element
{
public override void Draw(DrawContext drawContext)
{
Expand Down
2 changes: 1 addition & 1 deletion MqttExport/MqttUrlRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public async Task<Uri> GetMqttTemplateUriAsync()
};

uriBuilder.Path = EspUtilitiesInitExtension.CompressedImageRoute
.Replace("{providerId}", providerPath);
.Replace("{providerId}", Uri.EscapeDataString(providerPath));

if (query != -1)
uriBuilder.Query = providerId[query..];
Expand Down
15 changes: 5 additions & 10 deletions Program.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
using System.Text;
using DisplayUtil;
using DisplayUtil.EspUtilities;
using DisplayUtil.HomeAssistant;
using DisplayUtil.MqttExport;
using DisplayUtil.Providers;
using DisplayUtil.Scenes;
using DisplayUtil.Template;
using DisplayUtil.Utils;
Expand All @@ -16,19 +15,15 @@
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder
.AddProviders()
.AddTemplates()
.AddHassSupport()
.AddMqttWriter()
.AddEspUtilities();

builder.Services.AddSingleton(FontProvider.Create())
builder.Services
.AddSingleton<XmlLayoutDeserializer>()
.AddSingleton<TemplateLoader>();

builder.Services.AddScoped<TemplateRenderer>()
.AddScoped<TemplateContextProvider>()
.AddSingleton<ITemplateExtender, UtilTemplateExtender>();

builder.Services.AddTransient<FaIconDrawer>();
.AddTransient<IconDrawer>();

builder.Services.AddScreenProvider(o => o
.AddScribanFiles()
Expand Down
61 changes: 61 additions & 0 deletions Providers/FontProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System.Collections.Frozen;
using Microsoft.Extensions.Options;
using SkiaSharp;

namespace DisplayUtil.Providers;

/// <summary>
/// Holds the Fonts
/// </summary>
public class FontProvider(IReadOnlyDictionary<string, string> fontPathes)
{
/// <summary>
/// Returns the font by the internal name
/// </summary>
/// <param name="fontName">Name of the font</param>
/// <returns>The Font</returns>
/// <exception cref="Exception">Font not defined</exception>
public SKTypeface GetFont(string fontName)
{
if (!fontPathes.TryGetValue(fontName, out var font))
{
throw new Exception($"Font {fontName} not defined!");
}

return SKTypeface.FromFile(font);
}

public static FontProvider CreateFontProvider(IServiceProvider serviceProvider)
{
var options = serviceProvider
.GetRequiredService<IOptions<ProviderSettings>>();

var fonts = new Dictionary<string, string>(options.Value.Fonts);

// Handle GFonts
var gfontDownloader = ActivatorUtilities
.CreateInstance<GFontDownloader>(serviceProvider);

var gfonts = fonts
.Where(kv => gfontDownloader.IsGFont(kv.Value));

foreach (var (k, v) in gfonts)
{
var path = gfontDownloader.DownloadFontAsync(v).Result;
fonts[k] = path;
}

// Check if fonts exists
var missingFiles = fonts
.Except(gfonts)
.Where(e => !File.Exists(e.Value))
.ToArray();

if (missingFiles.Length != 0)
{
throw new Exception($"Missing fonts detected. Please check existence of: {string.Join(", ", missingFiles)}");
}

return new FontProvider(fonts.ToFrozenDictionary());
}
}
144 changes: 144 additions & 0 deletions Providers/GFontDownloader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Options;

namespace DisplayUtil.Providers;

/// <summary>
/// Responsible to download from Google Fonts
/// </summary>
internal partial class GFontDownloader(
IOptions<ProviderSettings> options,
ILogger<GFontDownloader> logger,
IHttpClientFactory httpClientFactory
)
{
private readonly ILogger _logger = logger;
private readonly HttpClient _httpClient
= httpClientFactory.CreateClient(nameof(GFontDownloader));

private static readonly Dictionary<string, int> _fontWeights = new()
{
{"thin", 100},
{"extra-light", 200},
{"light", 300},
{"regular", 400},
{"medium", 500},
{"semi-bold", 600},
{"bold", 700},
{"extra-bold", 800},
{"black", 900},
};

public bool IsGFont(string fontPath)
{
return GetGFontRegex().IsMatch(fontPath);
}

private DownloadData ParseExpression(string fontPath)
{
var matches = GetGFontRegex().Match(fontPath);

var download = new DownloadData(
matches.Groups[1].Value,
"regular"
);

if (matches.Groups.Count >= 3)
download = download with
{
Weight = matches.Groups[2].Value[1..]
};

return download;
}

private string GeneratePath(DownloadData downloadData)
{
var basePath = options.Value.GoogleFontsCachePath;
return Path.Combine(basePath, downloadData.FileName);
}

private static Uri BuildUri(DownloadData downloadData)
{
var name = $"{downloadData.FontFamily}:wght@{downloadData.Weight}";
var uri = $"https://fonts.googleapis.com/css2?family={name}";

return new Uri(uri);
}

private async Task HandleDownloadAsync(DownloadData downloadData, string path)
{
var uri = BuildUri(downloadData);
LogStartDownload(downloadData, uri);

var response = await _httpClient.GetAsync(uri);
if (!response.IsSuccessStatusCode)
{
throw new Exception($"Error on downloading font {downloadData}");
}
var text = await response.Content.ReadAsStringAsync();

var ttfUri = GetCssRegex().Match(text);
if (ttfUri is null)
{
throw new Exception($"Could not parse GFont Response on font {downloadData}");
}

var fontResponse = await _httpClient.GetAsync(ttfUri.Groups[1].Value);
await fontResponse.Content.CopyToAsync(File.OpenWrite(path));
}

public async Task<string> DownloadFontAsync(string gfontFormat)
{
var data = ParseExpression(gfontFormat);

// Check if weight is number
if (!GetNumberRegex().IsMatch(data.Weight))
{
data = data with
{
Weight = _fontWeights[data.Weight].ToString()
};
}

var path = GeneratePath(data);

// Already downloaded. Skip
if (File.Exists(path))
{
LogExists(data);
return path;
}

await HandleDownloadAsync(data, path);
LogFinishDownload(data);
return path;
}

[GeneratedRegex("^gfonts://([^@]+)(@.+)?$")]
private partial Regex GetGFontRegex();

[GeneratedRegex(@"src:\s+url\((.+)\)\s+format\('truetype'\);")]
private partial Regex GetCssRegex();

[GeneratedRegex(@"^\d+$")]
private partial Regex GetNumberRegex();

[LoggerMessage(LogLevel.Information, "Font {data} already exists. Skip.")]
private partial void LogExists(DownloadData data);

[LoggerMessage(LogLevel.Information, "Start download font {data} from {uri}")]
private partial void LogStartDownload(DownloadData data, Uri uri);

[LoggerMessage(LogLevel.Information, "Finished download font {data}")]
private partial void LogFinishDownload(DownloadData data);

private record DownloadData(
string FontFamily,
string Weight
)
{
public string FileName => $"gfont_{FontFamily}_{Weight}_v1.ttf";
}
}
27 changes: 27 additions & 0 deletions Providers/IconPathProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using DisplayUtil.Utils;
using Microsoft.Extensions.Options;

namespace DisplayUtil.Providers;

/// <summary>
/// Provides the path to an icon
/// </summary>
public class IconPathProvider(IOptions<ProviderSettings> options)
{
private const char _separator = ':';

private ProviderSettings _settings => options.Value;

public string ResolvePath(string path)
{
var (domain, icon) = path.SpiltDomain(_settings.DefaultIcons);
return ResolvePath(domain, icon);
}

public string ResolvePath(string domain, string iconName)
{
var basePath = _settings.Icons[domain];

return Path.Combine(basePath, $"{iconName}.svg");
}
}
30 changes: 30 additions & 0 deletions Providers/ProviderSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
namespace DisplayUtil.Providers;

public record ProviderSettings
{
/// <summary>
/// Fonts.
/// Key = Internal name
/// Value = Font Path || gfonts://font-name (downloaded once)
/// </summary>
public IReadOnlyDictionary<string, string> Fonts { get; init; }
= new Dictionary<string, string>();

/// <summary>
/// Path where Google Fonts gets cached to
/// </summary>
public string GoogleFontsCachePath { get; init; } = null!;

/// <summary>
/// Specifies the available icons
/// Key = Protocol
/// Value = Path to SVG Folder
/// </summary>
public IReadOnlyDictionary<string, string> Icons { get; init; }
= new Dictionary<string, string>();

/// <summary>
/// Defines the default Icons
/// </summary>
public string? DefaultIcons { get; init; }
}
23 changes: 23 additions & 0 deletions Providers/ProvidersInitalizer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Collections.Frozen;
using DisplayUtil.Utils;
using Microsoft.Extensions.Options;

namespace DisplayUtil.Providers;

public static class ProvidersInitalizer
{

public static IHostApplicationBuilder AddProviders(this IHostApplicationBuilder builder)
{
builder.ConfigureAndGet<ProviderSettings>("Providers");

builder.Services
.AddSingleton(FontProvider.CreateFontProvider)
.AddSingleton<IconPathProvider>();

return builder;
}



}
Binary file removed Resources/fonts/ProductSansBold.ttf
Binary file not shown.
Binary file removed Resources/fonts/ProductSansBoldItalic.ttf
Binary file not shown.
Binary file removed Resources/fonts/ProductSansItalic.ttf
Binary file not shown.
Binary file removed Resources/fonts/ProductSansRegular.ttf
Binary file not shown.
Binary file removed Resources/fonts/Roboto-Medium.ttf
Binary file not shown.
8 changes: 0 additions & 8 deletions Resources/screens/_icon_data.sbntxt

This file was deleted.

Loading

0 comments on commit a03e6b3

Please sign in to comment.