diff --git a/html/locales/locale-es_VA.json b/html/locales/locale-es_VA.json
new file mode 100644
index 00000000..2b75c4ef
--- /dev/null
+++ b/html/locales/locale-es_VA.json
@@ -0,0 +1,191 @@
+{
+ "WEBSITE_TITLE": "Interfície d'usuari web de MineOS",
+ "NOTIFICACIONES": "Notificacions",
+ "REFRESH_SERVER_LIST": "Actualitzar llista de servidors",
+ "REFRESH_PROFILE_LIST": "Actualitzar llista de perfils",
+ "LOG_OFF": "Tancar sesió",
+
+ "HOST_SETTINGS": "Configuració de 'Host'",
+ "DASHBOARD": "Tauler",
+ "CREATE_NEW_SERVER": "Crear Nou Servidor",
+ "IMPORT_SERVER": "Importar un Servidor",
+ "PROFILES": "Perfils",
+ "BUILDTOOLS": "Ferramentes de Construcció",
+ "CALENDAR": "Calendari",
+
+ "SERVER_SETTINGS": "Configuració del servidor",
+ "SERVER_STATUS": "Estat del Servidor",
+ "BACKUPS_AND_RESTORES": "Copies de seguretat",
+ "SERVER.PROPERTIES": "server.properties",
+ "RESTORE_POINT": "Punt de restauració",
+ "RESTORE_POINTS": "Punts de restauració",
+ "ARCHIVES": "Archius",
+ "SCHEDULING": "Scheduling",
+ "CONFIGURATION": "Programació",
+ "JAVA": "Java",
+ "GAME_MAINTENANCE": "Manteniment del joc",
+ "LOGGING": "Registre",
+ "CONSOLE": "Consola",
+ "OTHER_FILES": "Atres Archius",
+ "PLAYER_INTERACTION": "Interacció del Jugador",
+
+ "CURRENTLY_SELECTED_SERVER": "Servidor actualment seleccionat",
+ "SERVER_OVERVIEW": "Descripció general del servidor",
+ "SERVERS_RUNNING": "Servidors en marxa",
+ "PLAYERS_ONLINE": "Jugadors en llínia",
+ "UPTIME": "Temps Actiu",
+ "RAM_FREE": "RAM Lliure",
+
+ "LOAD_AVERAGES": "'Càrrega Mitjana'",
+ "SERVER": "Servidor",
+ "TYPE": "Tipus",
+ "perT": "pert",
+ "STATUS": "Estat",
+ "MEMORY": "memòria (RAM)",
+ "UP": "Encés",
+ "DOWN": "Apagat",
+
+ "SERVER_NAME": "Nom del servidor",
+ "CREATE_HELP": "Només lletres, números y guions baixos.",
+ "UNCONVENTIONAL_SERVER_TYPE": "Este es un servidor no convencional, com un servidor proxy/de balanceig de càrrega.",
+
+ "OFFICIAL_MOJANG_SERVER_JARS": "Jars Oficials Servidores Mojang",
+ "AVAILABLE_SERVER_JARS": "Jars/Paquets de Servidor Disponibles",
+ "NO_PROFILES_DOWNLOADED": "No hi ha perfils disponibles; comprova la conexió a Internet i actualitza la llista de perfils.",
+ "IDENTIFIER": "ID",
+ "RELEASE_TIMESTAMP": "Temps en Marxa",
+ "RELEASE_TYPE": "Tipus de versió",
+ "RELEASE": "Release",
+ "OLD_VERSION": "Versió Anterior",
+ "SNAPSHOT": "Snapshot",
+ "SHOW_ALL_RELEASES": "Mostrar tot",
+ "DOWNLOADED_PROFILES": "Perfils Descarregats",
+ "CURRENTLY_USING_PROFILE": "Perfil Utilitzat Actualment:",
+ "PROFILE": "Perfil",
+ "PROFILE_DESC": "Descripció del Perfil",
+ "DOWNLOADED": "Descarregat",
+
+ "SPIGOT_CRAFTBUKKIT": "Spigot",
+ "BUILDTOOLS_INSTRUCTIONS": "Descarregue l'últim archiu jar del constructor i després seleccione la versió de Minecraft per a compilar Spigot. Una vegada que hi haja acabat, copie els archius jar compilats del servidor a qualsevol servidor. El seu servidor no necessitarà un perfil.",
+ "DOWNLOAD_BUILDTOOLS": "Descarregar l'últim BuildTools.jar",
+ "DOWNLOAD_PAPERTOOLS": "Descarregar l'últim PaperTools.jar",
+ "BUILD_JAR": "Crear archiu Jar",
+ "BUILD_SPIGOT": "Construir Spigot",
+ "BUILD_PAPER": "Construir PaperSpigot",
+ "OUTPUT_FROM_BUILDTOOLS": "Eixida de BuildTools.jar",
+ "JAR_COPY_DESC": "Copiar binaris compilats al directori del servidor",
+ "COPY_TO_SERVER": "Copiar al servidor",
+
+ "GLANCE": "Servidor d'una ullada",
+ "INVALID_SERVER_NAME": "El servidor pot contindre només lletres, números i guions baixos. Este servidor no es pot administrar amb MineOS sense canviar-li el nom.",
+ "LOG_TAILING_RATE_LIMITED": "El servidor ha estat generant registres més enllà de l'umbral del límit de velocitat. El seguimient de registres s'ha detingut i es pot tornar a habilitar actualitzant la pàgina",
+ "VERSION": "Versió",
+ "REperTED_VERSION": "Versió de ping",
+ "MEMORY_FOOTPRINT": "Emprenta de memória",
+
+ "SERVER_ACTIONS": "Accions del Servidor",
+ "START": "Inici",
+ "STOP": "Aturar",
+ "RESTART": "Reiniciar",
+ "STOP_AND_BACKUP": "Aturar i fer còpia de seguretat",
+ "KILL":"Matar",
+ "BROADCAST_TO_LAN": "Transmetre en LAN",
+ "START_ON_BOOT": "Iniciar servidor a l'iniciar",
+ "UNCONVENTIONAL_SERVER": "Este no és un servidor de Minecraft convencional",
+ "COPY_PROFILE": "Copiar perfil a archius de servidor en viu",
+ "COMMIT_INTERVAL": "Minuts entre committing el món al disc via 'save-all' (buit per a desactivar)",
+
+ "JAVA_SETTINGS": "Configuració de Java",
+ "MEMORY_ALLOCATION": "Asignació de memòria (tamany heap)",
+ "JAVA_XMX": "-Xmx",
+ "JAVA_XMS": "-Xms",
+ "MB_ABBREVIATION": "MB",
+ "SELECT_SERVER_PROFILE": "Seleccionar perfil de servidor",
+ "CHANGE_PROFILE_TO": "Canviar perfil a:",
+ "CHANGE_JARFILE_TO": "Canviar jar executable a:",
+ "CURRENT_JAVA_VERSION": "Versió de Java en Us",
+ "ADDITIONAL_JAVA_ARGS": "Arguments Java Adicionals:",
+ "ADDITIONAL_JAR_ARGS": "Arguments Jar Adicionals:",
+ "CHANGE_NICENESS": "Canviar amabilitat del procés",
+ "NICENESS_DESC": "Amabilitat pot anat des de -20 (alta prioritat) a 19 (baixa prioritat). Per defecte es 0.",
+
+ "MOST_RECENT_RESTORE_POINT": "Punt de restauració més recent",
+ "OLDEST_RESTORE_POINT": "Punt de restauració més antic",
+ "SPACE_USED_RESTORES": "Espai utilitzat per Punts de restauració",
+ "SUCCESS": "éxit",
+ "RESTORE_POINT_CREATED": "Punt de restauració creat",
+ "FAILURE": "Oh oh",
+ "RESTORE_POINT_FAILED": "Intent de Punt de restauració fallit",
+ "CREATE_NEW_RESTORE_POINT": "Crear un nou punt de restauració",
+ "GET_INCREMENT_SIZES": "Obtindre tamanys de punts de restauració (lent)",
+
+ "MOST_RECENT_ARCHIVE": "Archiu més Nou",
+ "OLDEST_ARCHIVE": "Archiu més Antic",
+ "SPACE_USED_ARCHIVES": "Espai utilitzat per Archius",
+ "ARCHIVE_CREATED": "Archiu Creat",
+ "ARCHIVE_FAILED": "Intent de Archivar Fallit",
+ "CREATE_NEW_ARCHIVE": "Crear un nou Archiu",
+ "COMMIT_THEN_CREATE_ARCHIVE": "Guardar Tot i Després Crear Archiu",
+
+ "OWNERSHIP_AND_DISK_USAGE": "Propietat i Ús del Disc",
+ "SERVER_OWNER": "Propietari del Servidor",
+ "GROUP_OWNER": "Propietari del Grup",
+ "SPACE_USED_LIVE": "Espai utilitzat per Archius de servidor en viu",
+
+ "DELETE_SERVER": "Eliminar Servidor",
+ "DELETE": "Eliminar",
+ "EDIT": "Editar",
+ "SETTINGS": "Ajustos",
+ "DELETE_ARCHIVES": "Esborrar Archius:",
+ "DELETE_RESTORE_POINTS": "Eliminar Punts de restauració:",
+ "DELETE_LIVE_FILES": "Eliminar Archius del Servidor en viu:",
+
+ "AVAILABLE_RESTORE_POINTS": "Punts de restauració Disponibles",
+ "STEP": "Pas",
+ "TIMESTAMP": "Marca de temps",
+ "SIZE": "Tamany",
+ "CUMULATIVE_SIZE": "Tamany Acumulatiu",
+ "RESTORE": "Restaurar",
+ "PRUNE": "Eliminar més antics que este",
+
+ "AVAILABLE_ARCHIVES": "Archius Disponibles",
+ "FILENAME": "Nom de Archiu",
+ "ACTIONS": "Accions",
+ "DELETE_THIS_ARCHIVE": "Eliminar este Archiu",
+ "CREATE_FROM_ARCHIVE": "Crear Servidor des de Archiu",
+
+ "CRONTAB_SCHEDULE": "Horari Crontab",
+ "CRON_EXPRESSION": "Expresió de Cron",
+ "COMMAND_TO_RUN": "Comando a Executar",
+ "SEND_TO_CONSOLE": "Enviar a Consola",
+ "ADDITIONAL_ARGUMENT": "Argument Adicional",
+ "SUBMIT_CRONJOB": "Enviar cronjob",
+ "SUSPEND": "Suspendre",
+
+ "CREDITS": "MineOS creat i mantingut per William Dizon | traducció al valencià per Tsolete",
+
+ "CHANGE_LOCALE": "Canviar idioma",
+
+ "EULA_DETECTED": "EULA de Minecraft",
+ "EULA_MUST_BE_ACCEPTED": "Mojang requerix que els administradors del servidor de Minecraft accepten l'Acuerd de llicéncia d'usuari final abans d'allotjar un servidor de Minecraft. Açò es fa canviant 'eula=false' a 'eula=true' en eula.txt en l'arrel del seu servidor",
+ "ACCEPT_EULA": "Acceptar EULA",
+ "READ_THE_EULA": "Llisca l'EULA de Minecraft",
+
+ "STARTING_A_NEW_SERVER": "Iniciant un nou servidor",
+ "NEW_SERVER_OVERVIEW": "Iniciar un nou servidor reqierix al menys la següent configuració inicial: un servidor JAR executable i el tamany màxim de heap de Java. Seleccione un perfil per a expandir Archius JAR Adicionals.",
+
+ "CREATE_SERVER_FROM_ARCHIVE": "Crear un Nou Servidor a partir d'un Archiu Existent",
+ "SERVER_FROM_ARCHIVE_DESC": "Escriba el Nom del Nou Servidor a Crear",
+
+ "ADD_SP_ATTRIBUTE": "Agregar Nou Atribut",
+ "SP_DESCRIPTION": "Agregar un nou par atribut/valor a server.properties.",
+ "SP_ADD": "Agregar",
+
+ "SUCCEEDED": "èxit",
+ "FAILED": "fallit",
+ "!up": "És possible que el servidor no estiga actiu al realitzar esta acció.",
+ "up": "El servidor deu estar actiu al realitzar esta acció.",
+ "!exists": "És posible que el servidor no exisiscaa al realiztar esta acció.",
+ "exists": "No es pot trobar el servidor per a actuar.",
+ "eula": "Deus acceptar l'Acuerdo de llicència d'usuari final de Mojang per a iniciar este servidor"
+}
\ No newline at end of file
diff --git a/profiles.d/papertemplate.js b/profiles.d/papertemplate.js
index e97317fb..1f565e51 100644
--- a/profiles.d/papertemplate.js
+++ b/profiles.d/papertemplate.js
@@ -3,55 +3,133 @@ var fs = require('fs-extra');
var profile = require('./template');
var axios = require('axios');
-module.exports = function papertemplate (name){
+module.exports = function papertemplate(name) {
const lowername = name.toLowerCase();
const titlename = name.charAt(0).toUpperCase() + lowername.substr(1);
-return {
- name: titlename,
- request_args: {
- url: `https://papermc.io/api/v2/projects/${lowername}/`,
- json: true
- },
- handler: function (profile_dir, body, callback) {
- var p = [];
- var weight = 0;
-
- try {
- for (var index in body.versions) {
- var version = body.versions[index];
-
- p.push(axios({ url: `https://papermc.io/api/v2/projects/${lowername}/versions/${version}/`}).catch((err) => {
- console.log(err);
- }));
+ return {
+ name: titlename,
+ request_args: {
+ url: `https://fill.papermc.io/v3/projects/${lowername}`,
+ json: true
+ },
+ handler: function(profile_dir, body, callback) {
+ var p = [];
+ var weight = 0;
+
+ try {
+ const allVersions = [];
+ if (body.versions && typeof body.versions === 'object') {
+ Object.values(body.versions).forEach(groupVersions => {
+ if (Array.isArray(groupVersions)) {
+ allVersions.push(...groupVersions);
+ }
+ });
+ }
+
+ // ✅ 1. ÚLTIMA build estable (build más alto de latest)
+ p.push(axios({
+ url: `https://fill.papermc.io/v3/projects/${lowername}/versions/latest`,
+ json: true
+ }).catch(() => null));
+
+ // ✅ 2. Builds más recientes por versión específica (top 8)
+ if (allVersions.length > 0) {
+ allVersions.sort((a, b) => {
+ const va = a.split('.').map(Number);
+ const vb = b.split('.').map(Number);
+ for (let i = 0; i < Math.max(va.length, vb.length); i++) {
+ const vaPart = va[i] || 0;
+ const vbPart = vb[i] || 0;
+ if (vaPart !== vbPart) return vbPart - vaPart;
+ }
+ return 0;
+ });
+
+ allVersions.slice(0, 8).forEach(version => {
+ p.push(axios({
+ url: `https://fill.papermc.io/v3/projects/${lowername}/versions/${version}`,
+ json: true
+ }).catch(() => null));
+ });
+ }
+
+ Promise.all(p).then(responses => {
+ var items = [];
+
+ responses.forEach((response, index) => {
+ if (!response || response === null) return;
+
+ const data = response.data;
+
+ if (!data || data.ok === false || !data.builds || !Array.isArray(data.builds)) {
+ return;
+ }
+
+ // ✅ ORDENAR BUILDS por número (más alto = más reciente)
+ const builds = [...data.builds].sort((a, b) => {
+ const buildA = a.build || a;
+ const buildB = b.build || b;
+ return buildB - buildA; // DESCENDENTE: mayor build primero
+ });
+
+ if (builds.length === 0) return;
+
+ const latestBuildObj = builds[0]; // PRIMERA = MÁS RECIENTE
+ const buildNumber = latestBuildObj.build || latestBuildObj;
+
+ // Extraer versión correctamente
+ let version;
+ if (index === 0) { // latest
+ version = data.version?.id || data.version_name || data.version || 'latest';
+ if (typeof version === 'object') {
+ version = version.id || version.name || version.version || 'latest';
+ }
+ } else {
+ version = allVersions[index - 1];
+ }
+
+ const isLatest = index === 0;
+ const item = new profile();
+
+ item['id'] = `${titlename}-${version}-${buildNumber}`;
+ item['group'] = lowername;
+ item['webui_desc'] = isLatest
+ ? `LATEST ${titlename} (${version}) build #${buildNumber}`
+ : `${titlename} ${version} latest build #${buildNumber}`;
+ item['weight'] = weight;
+ item['filename'] = `${lowername}-${version}-${buildNumber}.jar`;
+
+ let downloadUrl = '';
+ if (latestBuildObj.downloads?.application?.url) {
+ downloadUrl = latestBuildObj.downloads.application.url;
+ } else {
+ const verForUrl = isLatest ? version : allVersions[index - 1];
+ downloadUrl = `https://fill.papermc.io/v3/projects/${lowername}/versions/${verForUrl}/builds/${buildNumber}/downloads/${lowername}-${verForUrl}-${buildNumber}.jar`;
+ }
+
+ item['url'] = downloadUrl;
+ item['downloaded'] = fs.existsSync(path.join(profile_dir, item.id, item.filename));
+ item['version'] = version;
+ item['release_version'] = version;
+ item['type'] = 'release';
+
+ items.push(item);
+ weight++;
+ });
+
+ console.log(`Generated ${items.length} Paper endpoints (latest builds)`);
+ callback(null, items);
+ }).catch(err => {
+ console.error('Error:', err);
+ callback(err, []);
+ });
+
+ } catch (e) {
+ console.error('Error:', e);
+ callback(e, []);
}
- Promise.all(p).then(responses => {
- p = [];
- responses.forEach(response => {
- var build = response.data.builds[ response.data.builds.length -1 ];
- const splitPath = response.request.path.split('/');
- var ver =splitPath[splitPath.length - 2];
- var item = new profile();
-
- item['id'] = `${titlename}-${ver}-${build}`;
- item['group'] = lowername;
- item['webui_desc'] = `Latest ${titlename} build for ${ver}`;
- item['weight'] = weight;
- item['filename'] = `${lowername}-${ver}-${build}.jar`;
- item['url'] = `${response.request.res.responseUrl}builds/${build}/downloads/${lowername}-${ver}-${build}.jar`;
- item['downloaded'] = fs.existsSync(path.join(profile_dir, item.id, item.filename));
- item['version'] = ver;
- item['release_version'] = ver;
- item['type'] = 'release'
-
- p.push(item);
- weight++;
- })
- }).then(() => { callback(null, p)})
- .catch((err) => {console.error(err)});
-
- } catch (e) { console.log(e) }
- } //end handler
-}
-}
+ }
+ };
+};
\ No newline at end of file
diff --git a/webui.js b/webui.js
index e4f225e8..cdd8b4cd 100755
--- a/webui.js
+++ b/webui.js
@@ -238,9 +238,11 @@ mineos.dependencies(function(err, binaries) {
res.end();
});
- app.get('/logout', function(req, res){
- req.logout();
- res.redirect('/admin/login.html');
+ app.get('/logout', function(req, res, next) {
+ req.logout(function(err) {
+ if (err) { return next(err); }
+ res.redirect('/');
+ });
});
app.use('/socket.io', express.static(__dirname + '/node_modules/socket.io'));