Files
jellyfin-plugin-skin-manager/Jellyfin.Plugin.SkinManager/Configuration/MainController.js
Daniel 7bdf39f0fa V.3
2025-12-22 00:07:16 +01:00

389 lines
14 KiB
JavaScript

class MainController {
constructor(jsonUrl) {
this.jsonUrl = jsonUrl;
this.skins = [];
this.currentSkin = null;
this.selectElement = document.getElementById("cssOptions");
this.descriptionElement = document.getElementById("description");
this.optionsElement = document.getElementById("options");
this.setSkinButton = document.getElementById("setSkin");
this.configController = new ConfigController();
}
async init() {
try {
const [json, currentSkin] = await Promise.all([
this.fetchJson(),
this.loadCurrentSkinFromHistory()
]);
this.loadSkins(json);
this.injectCurrentSkin(currentSkin);
this.populateSelect();
this.initEventListeners();
} catch (error) {
console.error("Error cargando las skins:", error);
}
}
async fetchJson() {
const response = await fetch(this.jsonUrl);
if (!response.ok) throw new Error(`Error HTTP: ${response.status}`);
return await response.json();
}
async loadCurrentSkinFromHistory() {
try {
const history = await this.configController.loadHistorySkins();
if (!Array.isArray(history) || history.length === 0) {
return null;
}
const latest = history[0];
return this.cloneAsCurrentSkin(latest);
} catch (error) {
console.warn("No se pudo cargar la skin actual:", error);
return null;
}
}
loadSkins(json) {
this.skins = json.skins.map(s => new Skin(s));
}
injectCurrentSkin(currentSkin) {
if (!currentSkin) {
return;
}
this.skins.unshift(currentSkin);
}
cloneAsCurrentSkin(skin) {
if (!skin) {
return null;
}
const plainSkin = JSON.parse(JSON.stringify(skin));
const baseName = this.extractSkinBaseName(plainSkin.name);
plainSkin.name = `Current Skin - ${baseName}`;
plainSkin.description = plainSkin.description || "Skin currently applied with your saved settings.";
if (Array.isArray(plainSkin.categories)) {
plainSkin.categories = plainSkin.categories.filter(cat => cat && cat.name !== "Custom CSS");
}
return new Skin(plainSkin);
}
extractSkinBaseName(name) {
if (!name) {
return "unknown";
}
const match = String(name).match(/-\s*(.+)$/);
if (match && match[1]) {
return match[1].trim();
}
return String(name).trim();
}
populateSelect() {
this.selectElement.innerHTML = ""; // Limpiar por si acaso
this.skins.forEach((skin, index) => {
const option = document.createElement("option");
option.value = index;
option.textContent = skin.name;
this.selectElement.appendChild(option);
});
// Mostrar la primera skin por defecto si existe
if (this.skins.length > 0) {
this.selectElement.value = 0;
this.currentSkin = this.skins[0];
this.showSkin();
}
}
showSkin() {
this.optionsElement.innerHTML = this.currentSkin.generateHTML();
this.currentSkin.attachEventListeners();
}
updateSkinInfo(index) {
const skin = this.skins[index];
if (!skin) return;
// Actualizar descripción
this.descriptionElement.textContent = `Skin: ${skin.name}`;
// Actualizar categorías
this.optionsElement.innerHTML = "";
skin.categories.forEach(cat => {
const div = document.createElement("div");
div.textContent = cat;
this.optionsElement.appendChild(div);
});
// Aplicar el CSS
this.applySkin(skin.css);
}
changeSkin() {
const selectedIndex = parseInt(this.selectElement.value, 10);
if (Number.isNaN(selectedIndex) || !this.skins[selectedIndex]) {
return;
}
this.currentSkin = this.skins[selectedIndex];
this.showSkin();
console.log(`Skin changed to: ${this.currentSkin.name}`);
}
async applyCurrentSkin() {
if (!this.currentSkin) return;
const css = this.currentSkin.generateCSS();
const appliedSkinName = this.currentSkin.name;
try {
const serverConfig = await ApiClient.getServerConfiguration();
await ApiClient.updateServerConfiguration(serverConfig);
const brandingConfig = await ApiClient.getNamedConfiguration("branding");
const existingCss = brandingConfig && typeof brandingConfig.CustomCss === "string"
? brandingConfig.CustomCss
: "";
if (existingCss && !this.configController.isManagedCss(existingCss)) {
await this.configController.saveUserCss(existingCss);
}
brandingConfig.CustomCss = css;
await ApiClient.updateNamedConfiguration("branding", brandingConfig);
Dashboard.processServerConfigurationUpdateResult();
// Save the skin to history after a successful update
await this.configController.saveSkin(this.currentSkin);
await this.configController.setSelectedSkin(appliedSkinName);
window.location.reload(true);
} catch (error) {
console.error("Error applying skin:", error);
}
}
initEventListeners() {
this.setSkinButton.addEventListener('click', () => {
if (this.currentSkin) {
this.applyCurrentSkin();
}
});
this.selectElement.addEventListener('change', () => {
this.changeSkin();
});
}
async initDebug() {
try {
const json = `{
"skins": [
{
"name": "Finimalism",
"description": "A modern, customizable skin for Jellyfin.",
"css":"",
"categories": [
{
"name": "Default",
"controls": [
{
"type": "select",
"label": "Mode",
"description": "Select light or dark mode",
"id": "mode",
"default": "@import url('https://cdn.jsdelivr.net/gh/tedhinklater/finimalism@latest/finimalism10.11.css');",
"css": "%value%",
"options": [
{
"label": "Colour",
"value": "@import url('https://cdn.jsdelivr.net/gh/tedhinklater/finimalism@latest/finimalism10.11.css');"
},
{
"label": "Black",
"value": "@import url('https://cdn.jsdelivr.net/gh/tedhinklater/finimalism@latest/finimalism10.11-black.css');"
}
]
}
]
}
]
},
{
"name": "JellySkin",
"description": "A modern, customizable skin for Jellyfin.",
"css": "@import url('https://cdn.jsdelivr.net/npm/jellyskin@latest/dist/main.css');",
"previews": [
{
"name": "Login Page",
"url": "https://raw.githubusercontent.com/danieladov/jellyfin-plugin-skin-manager/master/src/img/Default/1.png"
},
{
"name": "Home/Index Page",
"url": "https://raw.githubusercontent.com/danieladov/jellyfin-plugin-skin-manager/master/src/img/Default/2.png"
},
{
"name": "Library Page",
"url": "https://raw.githubusercontent.com/danieladov/jellyfin-plugin-skin-manager/master/src/img/Default/3.png"
},
{
"name": "Title page",
"url": "https://raw.githubusercontent.com/danieladov/jellyfin-plugin-skin-manager/master/src/img/Default/4.png"
}
],
"categories": [
{
"name": "Default",
"controls": [
{
"type": "fontPicker",
"label": "Base Font",
"description": "Select the base font for the skin",
"id": "baseFont",
"default": "Arial, sans-serif",
"css": ":root { --base-font: %value%; }"
},
{
"type": "color",
"label": "Background Color",
"description": "Set the background color of the skin",
"id": "bgColor",
"default": "#ffffff",
"css": ":root { --bg-color: %value%; }"
},
{
"type": "color",
"label": "Text Color",
"id": "textColor",
"default": "#000000",
"css": ":root { --text-color: %value%; }"
},
{
"type": "slider",
"label": "Font Size",
"id": "fontSize",
"min": 10,
"max": 30,
"default": 16,
"css": ":root { --font-size: %value%px; }"
},
{
"type": "checkbox",
"label": "Dark Mode",
"description": "Enable dark mode",
"id": "checkbox",
"default": true,
"css": ":root { --dark-mode: %value%; }"
},
{
"type": "number",
"label": "Border Radius",
"description": "Set the border radius",
"id": "borderRadius",
"min": 0,
"max": 50,
"default": 0,
"css": ":root { --border-radius: %value%px; }"
},
{
"type": "select",
"label": "Font Family",
"description": "Select the font family",
"id": "fontFamily",
"default": "Arial",
"css": ":root { --font-family: %value%; }",
"options": [
{
"label": "Arial",
"value": "Arial"
},
{
"label": "Verdana",
"value": "Verdana"
},
{
"label": "Georgia",
"value": "Georgia"
},
{
"label": "Times New Roman",
"value": "Times New Roman"
},
{
"label": "Trebuchet MS",
"value": "Trebuchet MS"
},
{
"label": "Arial Black",
"value": "Arial Black"
},
{
"label": "Impact",
"value": "Impact"
},
{
"label": "Comic Sans MS",
"value": "Comic Sans MS"
},
{
"label": "Courier New",
"value": "Courier New"
},
{
"label": "Lucida Console",
"value": "Lucida Console"
}
]
}
]
}
]
},
{ "name": "DarkSkin",
"description": "A sleek dark theme for Jellyfin.",
"css": "@import url('https://cdn.jsdelivr.net/npm/jellyskin@latest/dist/dark.css');",
"previews": [],
"categories": [
{
"name": "Dark Mode",
"controls": [
{
"type": "color",
"label": "Background Color",
"description": "Set the background color of the skin",
"id": "bgColor",
"default": "#121212",
"css": ":root { --bg-color: %value%; }"
}
]
}
]
}
]
}`;
const jsonObj = JSON.parse(json);
this.loadSkins(jsonObj);
const currentSkin = await this.loadCurrentSkinFromHistory();
this.injectCurrentSkin(currentSkin);
this.populateSelect();
this.initEventListeners();
} catch (error) {
console.error("Error cargando las skins:", error);
}
}
}