Add CI/CD pipelines, NSIS installer, ES module bundling, and ruff linting
Lint & Test / test (push) Failing after 9s
Release / create-release (push) Successful in 1s
Release / build-windows (push) Successful in 59s

- Add Gitea Actions workflows: test.yml (lint + test on push/PR) and
  release.yml (build + NSIS installer + upload on v* tags)
- Add NSIS installer with optional desktop shortcut and auto-start
- Add esbuild bundler: ES module migration with IIFE bundle output
- Add build-dist-windows.sh for cross-building Windows distribution
- Fix all ruff lint errors (import sorting, unused imports, line length)
- Remove redundant scripts (start-server.bat, stop-server.bat,
  start-server-background.vbs)
- Update CLAUDE.md with CI/CD and release documentation
This commit is contained in:
2026-03-23 02:01:28 +03:00
parent be48318212
commit 5439af1955
41 changed files with 1702 additions and 310 deletions
+20 -13
View File
@@ -2,9 +2,16 @@
// Scripts: CRUD, quick access, execution dialog
// ============================================================
let scriptFormDirty = false;
import {
t, showToast, escapeHtml, closeDialog, showConfirm,
resolveMdiIcons, fetchMdiIcon,
scripts, setScripts,
} from './core.js';
async function loadScripts() {
export let scriptFormDirty = false;
export function setScriptFormDirty(value) { scriptFormDirty = value; }
export async function loadScripts() {
const token = localStorage.getItem('media_server_token');
try {
@@ -15,7 +22,7 @@ async function loadScripts() {
});
if (response.ok) {
scripts = await response.json();
setScripts(await response.json());
displayQuickAccess();
}
} catch (error) {
@@ -24,7 +31,7 @@ async function loadScripts() {
}
let _quickAccessGen = 0;
async function displayQuickAccess() {
export async function displayQuickAccess() {
const gen = ++_quickAccessGen;
const grid = document.getElementById('scripts-grid');
@@ -150,7 +157,7 @@ async function executeScript(scriptName, buttonElement) {
// ============================================================
let _loadScriptsPromise = null;
async function loadScriptsTable() {
export async function loadScriptsTable() {
if (_loadScriptsPromise) return _loadScriptsPromise;
_loadScriptsPromise = _loadScriptsTableImpl();
_loadScriptsPromise.finally(() => { _loadScriptsPromise = null; });
@@ -206,7 +213,7 @@ async function _loadScriptsTableImpl() {
}
}
function showAddScriptDialog() {
export function showAddScriptDialog() {
const dialog = document.getElementById('scriptDialog');
const form = document.getElementById('scriptForm');
const title = document.getElementById('dialogTitle');
@@ -224,7 +231,7 @@ function showAddScriptDialog() {
dialog.showModal();
}
async function showEditScriptDialog(scriptName) {
export async function showEditScriptDialog(scriptName) {
const token = localStorage.getItem('media_server_token');
const dialog = document.getElementById('scriptDialog');
const title = document.getElementById('dialogTitle');
@@ -274,7 +281,7 @@ async function showEditScriptDialog(scriptName) {
}
}
async function closeScriptDialog() {
export async function closeScriptDialog() {
if (scriptFormDirty) {
if (!await showConfirm(t('scripts.confirm.unsaved'))) {
return;
@@ -287,7 +294,7 @@ async function closeScriptDialog() {
document.body.classList.remove('dialog-open');
}
async function saveScript(event) {
export async function saveScript(event) {
event.preventDefault();
const submitBtn = event.target.querySelector('button[type="submit"]');
@@ -341,7 +348,7 @@ async function saveScript(event) {
}
}
async function deleteScriptConfirm(scriptName) {
export async function deleteScriptConfirm(scriptName) {
if (!await showConfirm(t('scripts.confirm.delete').replace('{name}', scriptName))) {
return;
}
@@ -373,7 +380,7 @@ async function deleteScriptConfirm(scriptName) {
// Execution Result Dialog (shared by scripts and callbacks)
// ============================================================
function closeExecutionDialog() {
export function closeExecutionDialog() {
const dialog = document.getElementById('executionDialog');
closeDialog(dialog);
document.body.classList.remove('dialog-open');
@@ -435,7 +442,7 @@ function showExecutionResult(name, result, type = 'script') {
dialog.showModal();
}
async function executeScriptDebug(scriptName) {
export async function executeScriptDebug(scriptName) {
const token = localStorage.getItem('media_server_token');
const dialog = document.getElementById('executionDialog');
const title = document.getElementById('executionDialogTitle');
@@ -486,7 +493,7 @@ async function executeScriptDebug(scriptName) {
}
}
async function executeCallbackDebug(callbackName) {
export async function executeCallbackDebug(callbackName) {
const token = localStorage.getItem('media_server_token');
const dialog = document.getElementById('executionDialog');
const title = document.getElementById('executionDialogTitle');