diff --git a/core/client.js b/core/client.js index 6b2a70a..58893de 100644 --- a/core/client.js +++ b/core/client.js @@ -7,6 +7,8 @@ const buttonExtensibleContainer = document.getElementById('button-container-exte const buttonTimeContainer = document.getElementById('button-container-time') const buttonClose = document.getElementById('stop-code') const buttonWiki = document.getElementById('button-wiki') +const leftButtons = document.getElementById('left-button') +const textVersion = document.getElementById('span-version') const languageSelector = document.getElementById('language-selector') const switchTheme = document.getElementById('switch-theme') const titleCrono = document.getElementById('crono-title') @@ -36,10 +38,23 @@ socket.addEventListener('message', (event) => { translateElements = message.translateElements // Configuration and translation - switchTheme.checked = message.config.themedark + switchTheme.checked = message.config.themeDark buttonClose.title = translateElements.home.close + textVersion.textContent = message.config.version + if (message.config.version !== 'Error' && message.config.versionRelease !== 'Error' && compareVersions(message.config.version, message.config.versionRelease) === 1) { + const link = document.createElement('a') + link.href = 'https://github.com/BrowserSourcesForOBS/obs-timer-controller/releases/latest' + link.target = '_blank' + link.id = 'link-newVersion' + const button = document.createElement('button') + button.className = 'button-versionRelease' + button.title = translateElements.home.newVersionTitle + button.textContent = translateElements.home.newVersion + message.config.versionRelease + link.appendChild(button) + leftButtons.appendChild(link) + } buttonWiki.title = translateElements.home.wiki - if (message.config.themedark) { + if (message.config.themeDark) { document.body.classList.remove('light-theme') document.body.classList.add('dark-theme') } else { @@ -96,7 +111,7 @@ buttonClose.addEventListener('click', () => { }) switchTheme.addEventListener('change', () => { - socket.send(JSON.stringify({ action: 'themeChange', themedark: switchTheme.checked })) + socket.send(JSON.stringify({ action: 'themeChange', themeDark: switchTheme.checked })) }) languageSelector.addEventListener('change', () => { @@ -291,3 +306,15 @@ function showNotification (message, button) { notification.remove() }, 2000) } + +function compareVersions (versionA, versionB) { + const a = versionA.split('v')[1].split('.').map(Number) + const b = versionB.split('v')[1].split('.').map(Number) + + for (let i = 0; i < 3; i++) { + if (a[i] < b[i]) return 1 // B es más moderna que A + if (a[i] > b[i]) return -1 // B es más antigua que A + } + + return 0 // Son la misma versión +} diff --git a/core/index.html b/core/index.html index ce61dc5..df3bd9c 100644 --- a/core/index.html +++ b/core/index.html @@ -18,7 +18,7 @@
- + @@ -40,6 +40,7 @@ + diff --git a/core/template/cdown/control/control.js b/core/template/cdown/control/control.js index 7f23421..9ace36a 100644 --- a/core/template/cdown/control/control.js +++ b/core/template/cdown/control/control.js @@ -59,8 +59,8 @@ socket.addEventListener('message', (event) => { translateElements = message.translateElements // Config and translates - switchTheme.checked = message.config.themedark - if (message.config.themedark) { + switchTheme.checked = message.config.themeDark + if (message.config.themeDark) { document.body.classList.remove('light-theme') document.body.classList.add('dark-theme') } else { @@ -149,7 +149,7 @@ socket.addEventListener('close', (event) => { }) switchTheme.addEventListener('change', () => { - socket.send(JSON.stringify({ action: 'themeChange', themedark: switchTheme.checked })) + socket.send(JSON.stringify({ action: 'themeChange', themeDark: switchTheme.checked })) }) selectorLang.addEventListener('change', () => { diff --git a/core/template/cdowntime/control/control.js b/core/template/cdowntime/control/control.js index 1943afb..fd6dcb6 100644 --- a/core/template/cdowntime/control/control.js +++ b/core/template/cdowntime/control/control.js @@ -58,8 +58,8 @@ socket.addEventListener('message', (event) => { translateElements = message.translateElements // Config and translates - switchTheme.checked = message.config.themedark - if (message.config.themedark) { + switchTheme.checked = message.config.themeDark + if (message.config.themeDark) { document.body.classList.remove('light-theme') document.body.classList.add('dark-theme') } else { @@ -139,7 +139,7 @@ socket.addEventListener('close', (event) => { }) switchTheme.addEventListener('change', () => { - socket.send(JSON.stringify({ action: 'themeChange', themedark: switchTheme.checked })) + socket.send(JSON.stringify({ action: 'themeChange', themeDark: switchTheme.checked })) }) selectorLang.addEventListener('change', () => { diff --git a/core/template/crono/control/control.js b/core/template/crono/control/control.js index bd8270c..7f21442 100644 --- a/core/template/crono/control/control.js +++ b/core/template/crono/control/control.js @@ -57,8 +57,8 @@ socket.addEventListener('message', (event) => { translateElements = message.translateElements // Configuration and translates - switchTheme.checked = message.config.themedark - if (message.config.themedark) { + switchTheme.checked = message.config.themeDark + if (message.config.themeDark) { document.body.classList.remove('light-theme') document.body.classList.add('dark-theme') } else { @@ -131,7 +131,7 @@ socket.addEventListener('close', (event) => { }) switchTheme.addEventListener('change', () => { - socket.send(JSON.stringify({ action: 'themeChange', themedark: switchTheme.checked })) + socket.send(JSON.stringify({ action: 'themeChange', themeDark: switchTheme.checked })) }) languageSelector.addEventListener('change', () => { diff --git a/core/template/extensible/control/control.js b/core/template/extensible/control/control.js index 5ee63fd..af55c1f 100644 --- a/core/template/extensible/control/control.js +++ b/core/template/extensible/control/control.js @@ -64,8 +64,8 @@ socket.addEventListener('message', (event) => { translateElements = message.translateElements // Config and translates - switchTheme.checked = message.config.themedark - if (message.config.themedark) { + switchTheme.checked = message.config.themeDark + if (message.config.themeDark) { document.body.classList.remove('light-theme') document.body.classList.add('dark-theme') } else { @@ -171,7 +171,7 @@ socket.addEventListener('close', (event) => { }) switchTheme.addEventListener('change', () => { - socket.send(JSON.stringify({ action: 'themeChange', themedark: switchTheme.checked })) + socket.send(JSON.stringify({ action: 'themeChange', themeDark: switchTheme.checked })) }) selectorLang.addEventListener('change', () => { diff --git a/core/template/time/control/control.js b/core/template/time/control/control.js index 31b4d47..83a2d61 100644 --- a/core/template/time/control/control.js +++ b/core/template/time/control/control.js @@ -55,8 +55,8 @@ socket.addEventListener('message', (event) => { // translateElements = message.translateElements; // Configuration and translations - switchTheme.checked = message.config.themedark - if (message.config.themedark) { + switchTheme.checked = message.config.themeDark + if (message.config.themeDark) { document.body.classList.remove('light-theme') document.body.classList.add('dark-theme') } else { @@ -128,7 +128,7 @@ socket.addEventListener('close', (event) => { }) switchTheme.addEventListener('change', () => { - socket.send(JSON.stringify({ action: 'themeChange', themedark: switchTheme.checked })) + socket.send(JSON.stringify({ action: 'themeChange', themeDark: switchTheme.checked })) }) langSelector.addEventListener('change', () => { diff --git a/core/topbar.css b/core/topbar.css index 1dc1897..7c1916d 100644 --- a/core/topbar.css +++ b/core/topbar.css @@ -17,7 +17,7 @@ border-radius: 5px; color: white; vertical-align: bottom; - margin-top: 3.5px; + margin-top: 4.5px; cursor: pointer; flex-grow: 1; } @@ -34,13 +34,47 @@ border-radius: 5px; color: white; vertical-align: bottom; - margin-top: 3.5px; + margin-top: 4.5px; cursor: pointer; flex-grow: 1; margin-right: 2.5px; margin-left: 2.5px; } +.span-version { + font-size: 18px; + background-color: #007bff; + border: 2px solid #007bff; + border-radius: 5px; + color: white; + position: relative; + top: -1.5px; + flex-grow: 1; + margin-right: 2.5px; + margin-left: 2.5px; + padding: 0px 10px; +} + +.button-versionRelease { + font-size: 16.5px; + background-color: #4caf50; + border: 2px solid #4caf50; + border-radius: 5px; + color: white; + vertical-align: bottom; + margin-top: 4.5px; + cursor: pointer; + flex-grow: 1; + margin-right: 2.5px; + margin-left: 2.5px; + padding: 0px 10px; +} + +.button-versionRelease:hover { + background-color: #388e3c; /* Fondo gris más oscuro al pasar el ratón */ + border: 2px solid #388e3c; +} + .link-button:hover { background-color: #444; /* Fondo gris más oscuro al pasar el ratón */ border: 2px solid #444; diff --git a/core/translates/en.yaml b/core/translates/en.yaml index fdfc1d9..bfadc1e 100644 --- a/core/translates/en.yaml +++ b/core/translates/en.yaml @@ -1,6 +1,8 @@ home: close: Close the window and stop the code wiki: Documentation + newVersionTitle: Download the new update + newVersion: "New update available: " cronoTitle: CHRONOMETERS cdownTitle: COUNTDOWNS cdowntimeTitle: TIME UNTIL... diff --git a/core/translates/es.yaml b/core/translates/es.yaml index b6c2536..d10b763 100644 --- a/core/translates/es.yaml +++ b/core/translates/es.yaml @@ -1,6 +1,8 @@ home: close: Cierra la ventana y detiene el código wiki: Documentación + newVersionTitle: Descarga la nueva actualización + newVersion: "Nueva actualización disponible: " cronoTitle: CRONÓMETROS cdownTitle: TEMPORIZADORES cdowntimeTitle: TIEMPO HASTA... diff --git a/functions.js b/functions.js index ca9a408..1cc9e13 100644 --- a/functions.js +++ b/functions.js @@ -5,6 +5,7 @@ const exec = util.promisify(require('child_process').exec) const WebSocket = require('ws') const { getMs } = require('util-tiempo') const fontkit = require('fontkit') +const axios = require('axios') const argsv = process.argv.slice(2) @@ -53,6 +54,41 @@ async function darkThemeCheck () { } } +// Read the package.json file +async function getVersion () { + try { + const data = await fs.promises.readFile((argsv[0] === 'test') ? './package.json' : './resources/app/package.json', 'utf8') + + // Parse the content of the JSON file + const packageJson = await JSON.parse(data) + const packageVersion = `v${packageJson.version}` + + // Extract the project version + console.log(`Project version: ${packageVersion}`) + return packageVersion + } catch (jsonError) { + console.error('Error parsing package.json:', jsonError) + return 'Error' + } +} + +async function getVersionRelease () { + // Set the GitHub repository URL (make sure to replace 'owner' and 'repo' with your information) + const repoOwner = 'BrowserSourcesForOBS' // Replace 'owner' with the name of the repository owner + const repoName = 'obs-timer-controller' // Replace 'repo' with the name of the repository + + // Make a request to the public releases page + try { + const response = await axios.get(`https://api.github.com/repos/${repoOwner}/${repoName}/releases/latest`) + const latestTag = response.data.tag_name + console.log(`Latest release tag on GitHub: ${latestTag}`) + return latestTag + } catch (error) { + console.error('Error getting latest release tag:', error) + return 'Error' + } +} + // Get a list of installed fonts exports.getFonts = () => { const fontDirectories = [ @@ -93,7 +129,9 @@ exports.getFonts = () => { exports.initConfig = async () => { const Config = { lang: await getLanguage(), - themedark: await darkThemeCheck() + themeDark: await darkThemeCheck(), + version: await getVersion(), + versionRelease: await getVersionRelease() } this.saveConfig(Config) diff --git a/package-lock.json b/package-lock.json index e4e32ba..cf3c9c1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,14 +1,15 @@ { "name": "obs-timer-controller", - "version": "1.0.2", + "version": "1.0.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "obs-timer-controller", - "version": "1.0.2", + "version": "1.0.4", "license": "ISC", "dependencies": { + "axios": "^1.5.1", "child_process": "^1.0.2", "express": "^4.18.2", "fontkit": "^2.0.2", @@ -131,6 +132,15 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/@electron/get/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@electron/get/node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -443,6 +453,11 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "node_modules/at-least-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", @@ -461,6 +476,16 @@ "node": ">=0.8" } }, + "node_modules/axios": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz", + "integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -631,6 +656,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", @@ -814,6 +850,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -985,21 +1029,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/electron-packager/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/electron/node_modules/@types/node": { "version": "18.18.4", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.4.tgz", @@ -1354,6 +1383,25 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/fontkit": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.2.tgz", @@ -1370,6 +1418,19 @@ "unicode-trie": "^2.0.0" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1565,22 +1626,6 @@ "node": ">=10.0" } }, - "node_modules/global-agent/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "optional": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/globalthis": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", @@ -2288,6 +2333,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -2468,12 +2518,18 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/semver-compare": { diff --git a/package.json b/package.json index 81b0416..7fd3849 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "obs-timer-controller", - "version": "1.0.3", + "version": "1.0.4", "description": "Handling browser fonts for OBS related to timers and countdowns.", "main": "server.js", "repository": { @@ -8,6 +8,7 @@ "url": "https://github.com/BrowserSourcesForOBS/obs-timer-controller.git" }, "dependencies": { + "axios": "^1.5.1", "child_process": "^1.0.2", "express": "^4.18.2", "fontkit": "^2.0.2", @@ -22,7 +23,7 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "node": "node . test", - "pkg-win": "electron-packager . OBS-Timer-Controller --platform=win32 --arch=x64 --app-version=1.0.3 --out=dist --overwrite --icon=icon.ico --author=\"XtoManuel\" --description=\"Handling browser fonts for OBS related to timers and countdowns.\"" + "pkg-win": "electron-packager . OBS-Timer-Controller --platform=win32 --arch=x64 --app-version=1.0.4 --out=dist --overwrite --icon=icon.ico --author=\"XtoManuel\" --description=\"Handling browser fonts for OBS related to timers and countdowns.\"" }, "author": "XtoManuel", "license": "ISC", diff --git a/server.js b/server.js index 55986ef..d0d7863 100644 --- a/server.js +++ b/server.js @@ -83,7 +83,7 @@ wss.on('connection', (ws) => { } }) } else if (data.action === 'themeChange') { - Config.themedark = data.themedark + Config.themeDark = data.themeDark saveConfig(Config) wss.clients.forEach((client) => { if (client.readyState === WebSocket.OPEN) {