fix(posters): add custom fonts support

add fonts to /config/fonts/ and they will be auto detected

fix #219
This commit is contained in:
Tom Wheeler
2025-12-31 14:46:40 +13:00
parent b2e645bc95
commit 02999acad6
4 changed files with 58 additions and 8 deletions
+3 -2
View File
@@ -47,14 +47,15 @@ config/posters/*.*
config/temp/*.*
config/plex-base-posters/**
# wallpaper storage
config/wallpapers/*.*
# theme music storage
config/themes/*.*
# fonts storage
config/fonts/*.*
# logs
config/logs/*.log*
config/logs/*.json
+8
View File
@@ -72,6 +72,14 @@ RUN apk add --no-cache \
fc-cache -fv && \
rm -rf /tmp/*
# Configure fontconfig to scan custom fonts directory
RUN mkdir -p /etc/fonts/conf.d && \
echo '<?xml version="1.0"?>' > /etc/fonts/conf.d/99-agregarr-custom-fonts.conf && \
echo '<!DOCTYPE fontconfig SYSTEM "fonts.dtd">' >> /etc/fonts/conf.d/99-agregarr-custom-fonts.conf && \
echo '<fontconfig>' >> /etc/fonts/conf.d/99-agregarr-custom-fonts.conf && \
echo ' <dir>/app/config/fonts</dir>' >> /etc/fonts/conf.d/99-agregarr-custom-fonts.conf && \
echo '</fontconfig>' >> /etc/fonts/conf.d/99-agregarr-custom-fonts.conf
# Install Deno - yt-dlp requires a JS runtime as of 2025-11-12
RUN echo "@edge https://dl-cdn.alpinelinux.org/alpine/edge/main" >> /etc/apk/repositories && \
echo "@edge https://dl-cdn.alpinelinux.org/alpine/edge/community" >> /etc/apk/repositories && \
+28
View File
@@ -24,6 +24,7 @@ import express from 'express';
import * as OpenApiValidator from 'express-openapi-validator';
import type { Store } from 'express-session';
import session from 'express-session';
import fs from 'fs';
import next from 'next';
import path from 'path';
import swaggerUi from 'swagger-ui-express';
@@ -157,6 +158,17 @@ app
logger.error('Failed to initialize icon storage:', error);
}
// Initialize fonts directory for custom fonts
try {
const fontsDir = path.join(process.cwd(), 'config', 'fonts');
if (!fs.existsSync(fontsDir)) {
fs.mkdirSync(fontsDir, { recursive: true });
logger.info('Created fonts directory successfully');
}
} catch (error) {
logger.error('Failed to initialize fonts directory:', error);
}
// Initialize base poster storage directory
try {
const { plexBasePosterManager } = await import(
@@ -518,6 +530,22 @@ app
})
);
// Serve custom fonts
const customFontsPath = path.join(process.cwd(), 'config', 'fonts');
server.use(
'/custom-fonts',
express.static(customFontsPath, {
setHeaders: (res, path) => {
if (path.endsWith('.ttf')) {
res.setHeader('Content-Type', 'font/ttf');
} else if (path.endsWith('.otf')) {
res.setHeader('Content-Type', 'font/otf');
}
res.setHeader('Access-Control-Allow-Origin', '*');
},
})
);
server.post('/upload-icon', async (req, res) => {
try {
const multer = (await import('multer')).default;
+19 -6
View File
@@ -1,6 +1,7 @@
import logger from '@server/logger';
import { exec } from 'child_process';
import { Router } from 'express';
import path from 'path';
import { promisify } from 'util';
const execAsync = promisify(exec);
@@ -48,8 +49,8 @@ fontsRoutes.get('/', async (req, res) => {
continue;
}
// Only include TTF fonts for web serving
if (filePath.endsWith('.ttf')) {
// Include both TTF and OTF fonts for web serving
if (filePath.endsWith('.ttf') || filePath.endsWith('.otf')) {
// Prioritize system fonts over local fonts for unified behavior
if (
!fontMap.has(family) ||
@@ -62,18 +63,30 @@ fontsRoutes.get('/', async (req, res) => {
}
// Convert to final format with exact CSS values and font URLs
const configFontsPath = path.join(process.cwd(), 'config', 'fonts');
const fonts: FontInfo[] = [];
for (const [family, filePath] of fontMap) {
// Only include fonts from /usr/share/fonts/ for unified Docker/local behavior
if (!filePath.startsWith('/usr/share/fonts/')) {
// Include fonts from system directory OR custom directory
if (
!filePath.startsWith('/usr/share/fonts/') &&
!filePath.startsWith(configFontsPath)
) {
continue;
}
// Store clean font name - quotes will be added during CSS/SVG generation when needed
const cssValue = family;
// Convert system path to web URL
const fontUrl = filePath.replace('/usr/share/fonts/', '/fonts/');
// Convert path to web URL
let fontUrl: string;
if (filePath.startsWith('/usr/share/fonts/')) {
fontUrl = filePath.replace('/usr/share/fonts/', '/fonts/');
} else if (filePath.startsWith(configFontsPath)) {
fontUrl = filePath.replace(configFontsPath, '/custom-fonts');
} else {
continue;
}
fonts.push({
family,