From d20199758787fea4ac5d761c499a0d178d457f56 Mon Sep 17 00:00:00 2001 From: Philipp Wagner Date: Thu, 9 Jul 2026 16:12:29 +0200 Subject: [PATCH] added automatic Changelog XML to new Website. also now the XML gets pulled from new Website --- .../kst4contest/ApplicationConstants.java | 2 +- website/src/_data/version-history.xml | 382 ++++++++++++++++++ website/src/_data/version-legacy-sections.xml | 131 ++++++ website/src/_data/versionInfo.js | 183 +++++++++ website/src/version-info.njk | 5 + 5 files changed, 702 insertions(+), 1 deletion(-) create mode 100644 website/src/_data/version-history.xml create mode 100644 website/src/_data/version-legacy-sections.xml create mode 100644 website/src/_data/versionInfo.js create mode 100644 website/src/version-info.njk diff --git a/src/main/java/kst4contest/ApplicationConstants.java b/src/main/java/kst4contest/ApplicationConstants.java index 5286e59..b595494 100644 --- a/src/main/java/kst4contest/ApplicationConstants.java +++ b/src/main/java/kst4contest/ApplicationConstants.java @@ -22,7 +22,7 @@ public class ApplicationConstants { */ public static final double APPLICATION_CURRENTVERSIONNUMBER = 1.42; - public static final String VERSIONINFOURLFORUPDATES_KST4CONTEST = "https://do5amf.funkerportal.de/kst4ContestVersionInfo.xml"; + public static final String VERSIONINFOURLFORUPDATES_KST4CONTEST = "https://kst4contest.hamradioonline.de/kst4ContestVersionInfo.xml"; public static final String VERSIONINFDOWNLOADEDLOCALFILE = "kst4ContestVersionInfo.xml"; public static final String STYLECSSFILE_DEFAULT_DAYLIGHT = "KST4ContestDefaultDay.css"; diff --git a/website/src/_data/version-history.xml b/website/src/_data/version-history.xml new file mode 100644 index 0000000..2beccd4 --- /dev/null +++ b/website/src/_data/version-history.xml @@ -0,0 +1,382 @@ + + + + + 1.41 + 2026-07-01 + Map view and path calculations + +Band and Frequency Detection per Chatmember, Band alert, Win-Test SKED Push via UDP, +Win-Test Broadcast Defaults and SKed Workflow, Chat History at Startup, Station Map / Map View +Local Leaflet /-TileProxy Backend, Maidenhead /-Grid Overlay, Path calculation, path profile, +Reachability filters, NAC filters (grid sqaure marking) + + +button housing, it works now on smaller screens / plus: detecting maximum screen size + + +9A2HM reported that 23cm qsos with N1MM are not marked correctly, ist fixed + + + + + 1.40 + 2026-02-16 + Much changes and fixes + +- win-test support (not deactivable yet, beta) +- QSO sniffer which filters changable callsigns lists messages to your pm window +- Chatmember Score system. Each chatmember gets a score depending to antenna direction, activity time, + activity msgcount, positive signals, active bands, active frequencies, his sked direction (degrees), + self handed rate, sked-made-rate and some others +- Chatmember Band and frequency recognition: now we list all active bands of each other chatmember +- Band alert for logged stations +- Sked reminder ALERT with automatic messages in 2+1 / 5+2+1 / 10+5+2+1 minutes +- PSTRotator interface +- AirPlane Timeline +- Skedfail button in furtherinfo panel +- Wintest logsynch interface can now be activated and deactivated in the preferences +- load chat history on startup + + +- added save option: ServerDNS / Port +- added save option: activate/deactivate pstRotator interface +- added save option: activate/deactivate wintest interface +- added save option: callsign sniffer +- added save option: boolean GUI_darkModeActiveByDefault = false +- added AP notes at the internal DX cluster spots +- Generic Autoanswer fires maximum once in 45 seconds per rx callsign + + +- Userlist sort automatically on new member signon +- Posonpill-messages now kills only exactly one Client instance (bugreport 9A2HM) +- Crash of wtkst by disconnection of kst4Contest +- wtKST crashes when kst4contest is running (many reporters) +- wintest: logged per band excludes pre worked band (bugreport SM6VTZ) +- PSTRotator SOCKET Close on DISCONNECT BUTTON works now +- AirScout Map had not been updated (bugreport SM0RJV) +- QTFDefault had been not saved correctly (bugreport SM0RJV) +- Show path in AS button worked only with fixed server Strings (bugreport 9A2HM) +- Version number had been displayed wrong +- suffixes like /p, -2, etc. problem now fixed everywhere +- Dark mode: passing for qrg fields fix + + +- No more date display. Not needed. Saving space, only time is important + + + + 1.31 + 2025-12-13 + Much changes and a hotfix + +- win-test support (not deactivable yet, beta) +- pstRotator support (not deactivable yet, beta) +- airScout fix (calculations depends to cpu load now) +- QSO sniffer + + +- DNS from www.on4kst.info to www.on4kst.org (hotfix, now configurable in preferences) + + +- Endless loop in error case lets freeze the client +- PSTRotator SOCKET Close on DISCONNECT BUTTON +- Dark mode: passing for qrg fields fix + + + + + 1.266 + 2025-10-03 + Airscout interface did not work with multi-signons + nothing + nothing + +Fixed by using raw callsign (without -2 suffix etc.) when communicating with AirScout. +Thank you very much for testing this, Kreso 9A2HM! + + + + + 1.265 + 2025-09-28 + Direction buttons stay now colored, if activated + nothing + nothing + The buttons stay now colored, if activated + + + + 1.264 + 2025-08-02 + Changed the callsign recognition pattern for Simplelogfile + nothing + nothing + +Callsigns like S53CC, S51A etc. are now correctly marked as worked in SimpleLogFile.txt. +(bugreport Boris, S53CC) + + + + + 1.263 + 2025-06-08 + Airscout communication and Loginname + nothing + +Only entries with QRB lower than max-QRB are sent to AirScout in 60s intervals (was 12s for all). + + +- AS communication message count hugely reduced +- Name in chat is now saveable +- Fixed AS client name (was hard-wired to "KST") +73 / DO5AMF + + + + + 1.262 + 2025-05-21 + Freezes caused by getting messages before user login should be fixed now + nothing + nothing + +ON4KST delivers messages of stations not yet logged in. That caused a freeze at the message +processing engine which is now fixed. + + + + + 1.26 + 2025-05 + Login to multiple Channels via single signon / spend some colors + +1. UI: Dark mode. Switch in "Window -> use dark mode" +2. Usage of two Chatcategories at the same time +3. opposite station multi-callsign login-tagging +73 / DO5AMF + + +- Coloring mechanic of the software. Modify colors via css by yourself... + + +- Station tagging fixed completely + + + + + 1.251 + 2025-02 + BUGFIX of 1.25, tnx Steve Clements! + +- Steve spotted a problem in udp broadcast spot info reading, its now fixed! +73 / DO5AMF + + + - Station tagging + + + + 1.25 + 2025-02 + Wishlist-time + +- New configuration Tab: Messagehandling (auto-answering, CQ qrg auto-answer) +- Coloured lines: new pm rows appear in red, fade rainbow-like to white over 30s (tnx Gianluca) +73 / DO5AMF + + + +- Users with suffixes like "-2 and -70" are now correctly marked as worked + + + + + 1.24 + 2024-11 + Wishlist-time + +- Button to show qrz.com profile of a selected station +- Button to show qrzcq.com profile of a selected station + + + + + + + 1.23 + 2024-10 + DXCluster Server is now implemented + +- DXCluster Server (tnx OMAAO): KST4Contest now provides a DXCluster server to feed + your log client with station-reachable warnings. + + + + + + + 1.22 + 2024-05 + Increase usability, fixed AS button + - Variables (tnx OMAAO): MYLOCATORSHORT, MYQRGSHORT, QRZNAME + - Sendtext-field focus on callsign click + +- Worked-station-filter (tnx Gianluca): filter is now live +- Chatters list sorting by QRB (tnx Alessandro): fixed to numeric sort +- Airscout showpath button now maximizes AS and shows the path + + + + + 1.21 + 2024-04 + Increase usability + + +- Window sizes and divider positions are now stored and restored on next startup +- Filters section is now a flowpane for lower resolutions + + + + + + 1.2 + 2024-04 + Increase usability + +- Selectable bands +- Unworkable tags for each callsign per band +- QTF-Arrow on the "show path in AS" button + + + + + + + 1.1 + 2024-03 + Increased workflow + +- Reachable warning function +- Variables FIRSTAP and SECONDAP for predefined texts +- Marking new connected stations (bold) and away-state (brackets) +- Activity-timer since last message of a chatter + + - QRB/QTF info in pm-window + +- Behaviour of messagefilter-radiobutton corrected (tnx Gian) +- Error sending macros on selected stations in pm window (tnx Gian) + + - boot sound + + + 1.0 + 2024-02 + First stable release + +- audio notification support +- update-available warning +- changelog displaying +- known-bugs displaying +- message filters for selected station +- stationlist-filters (show by qtf / textstring, hide by qrb, qtf, workedstate) +- 10 macros (textsnippets available by hitting strg+numberkey) + + + + + + + 0.9 + 2024-02 + Now the chat is disconnectable without closing it + + + disconnect-button, Textsnippets in CQ Window, "/CQ" at click on own sendtexts, +setname "qrg" works now + + + + 0.8 + 2023-10 + savesettings function and disconnect function added. MYCALL-Highlighting fixed + savesettings function, disconnect function + + MYCALL-Highlighting + + + + 0.7 + 2023-07 + Internal database for worked stations, shortcut and textsnippet editor + database, shortcut-editor, textsnipped-editor + + + + + + 0.6 + 2023-07 + Added periodically sent beacon function + beacon to public channel + + + + + + 0.5 + 2023-02 + Airscout interface, UDP interfaces for worked-station data and TRX info, shortcuts + Airscout-interface, packetreceiver for ucxlog, n1mm, qartest + + + + + + 0.4 + 2022-12 + Worked info by logfile via universal pattern matching logfile interpreter + simple-logfile + + + + + + 0.3 + 2022-10 + Added a GUI, chat was text based only + Graphical user interface + + + + + + 0.2 + 2022-10 + Pattern matching system for frequency information, frequency collection per chatmember + frequency-extraction for every callsign + + + + + + 0.15 + 2022-09 + Researched the Chatprotocol and developed the base communication with the chatserver + + + + + + + 0.1 + 2022-09 + Primary architecture of the chat, message bus system for handling the message queues + + + + + + diff --git a/website/src/_data/version-legacy-sections.xml b/website/src/_data/version-legacy-sections.xml new file mode 100644 index 0000000..cfeffe8 --- /dev/null +++ b/website/src/_data/version-legacy-sections.xml @@ -0,0 +1,131 @@ + + + + + + Cyclic update of own name in chat to actual QRG + 2024-02 + open + + + Acoustic warnings + 2023-12 + added + + + Airscout support + 2023-03 + added + + + cyclic beacon messages in public chat + 2023-03 + added + + + + + +stations like ol7c-7 and ol7c-2 will not be marked as worked if only "ol7c" +is in the log. Need to interprete that. May ignore suffix starting with "-" + solved + + + +worked callsigns table is updated only once after connected to chat +Should be available directly after program started. +But Reset works all time + open + + + feature request: language-specific strings, maybe based to an xml file + + open + + + feature request: Macros + + added + + + feature request: + Automatic elimination of calls already connected from the log + + added + + + feature request: + Limitation of users beyond a certain QRB + + added + + + feature request: + User division for QTF perhaps settable based on the antenna lobe + + added + + + feature request: + Notification of new incoming users + added + + + feature request: + Evidence of a call which was written but not responded to. + + added + + + feature request: + direction based reachable-warnings: + if the chatclient detects a realised qso between two stations which both must have + directed their beams to my station, there should be an instant warning to me for + working at least one of the stations at the detected qrg + open + + + feature request: + implement ASShowpath message to airacout; + by doubleclicking a callsign in the chatmember list, the path and plane state should be + provided by airscout + open + + + feature request: + make chatlines copyable to the clipboard... + open + + + feature request: + adding an activity detection for sensing if another chatmembers alive-state + added + + + On sql error close the connection to make a clean exit + open + + + SETNAME /MYQRG in options menu doesnt work + solved + + + Disconnect button does not work (DL5ZK) + solved + + + Password-wrong error not displayed (DO5SA) + solved + + + /CQ isnt written on own PMs + solved + + + rightclick-textsnippets arent available in cq-table + solved + + + diff --git a/website/src/_data/versionInfo.js b/website/src/_data/versionInfo.js new file mode 100644 index 0000000..77413ba --- /dev/null +++ b/website/src/_data/versionInfo.js @@ -0,0 +1,183 @@ +const fs = require("fs"); +const path = require("path"); + +const REPO = "praktimarc/kst4contest"; +const API = `https://api.github.com/repos/${REPO}`; +const LABEL_MAP = { enhancement: "added", bug: "fixed" }; + +async function githubGet(urlPath) { + const headers = { Accept: "application/vnd.github+json" }; + if (process.env.GITHUB_TOKEN) { + headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`; + } + const res = await fetch(`${API}${urlPath}`, { headers }); + if (!res.ok) { + throw new Error(`GitHub API ${urlPath} failed: ${res.status}`); + } + return res.json(); +} + +// UpdateChecker.java parses with Double.parseDouble() and +// compares it against ApplicationConstants.APPLICATION_CURRENTVERSIONNUMBER, +// which encodes patch releases by appending the patch digit(s) instead of a +// third dot (e.g. tag v1.41.1 -> app version 1.411, v1.41.0 -> 1.41). See +// commit 38ef50c ("...set to 1.41.1 for upcoming hotfix" -> 1.411). +function toAppVersionNumber(tag) { + const cleaned = tag.replace(/^v/, ""); + const [major, minor, ...rest] = cleaned.split("."); + if (rest.length === 0) return cleaned; + const patch = rest.join(""); + return /^0*$/.test(patch) ? `${major}.${minor}` : `${major}.${minor}${patch}`; +} + +function escapeXml(value) { + return String(value ?? "") + .replace(/&/g, "&") + .replace(//g, ">"); +} + +// Strips GitHub's auto-generated release-notes markdown noise (headings, +// "Full Changelog" links, PR author attributions) down to plain text. +function cleanReleaseBody(body) { + const lines = []; + for (let line of (body || "").split("\n")) { + if (/^#{1,3}\s/.test(line)) continue; + if (line.trim().startsWith("**Full Changelog**")) continue; + line = line.replace(/\s+by @\S+ in https:\/\/\S+/, ""); + line = line.replace(/^\* /, "- "); + if (line.trim()) lines.push(line); + } + return lines.join("\n").replace(/\n{3,}/g, "\n\n").trim(); +} + +// Groups closed issues (excluding PRs) in the (since, until] window by +// label into "added" (enhancement) / "fixed" (bug) bullet lists. +async function getIssuesForRelease(since, until) { + const buckets = { added: [], fixed: [] }; + let page = 1; + for (;;) { + const items = await githubGet(`/issues?state=closed&per_page=100&page=${page}`); + if (!items.length) break; + for (const issue of items) { + if (issue.pull_request) continue; + const closed = issue.closed_at || ""; + if (!(closed > since && closed <= until)) continue; + const labels = issue.labels.map((l) => l.name); + const bucket = Object.keys(LABEL_MAP).find((l) => labels.includes(l)); + if (bucket) buckets[LABEL_MAP[bucket]].push(`- ${issue.title}`); + } + if (items.length < 100) break; + page++; + } + return { added: buckets.added.join("\n"), fixed: buckets.fixed.join("\n") }; +} + +// version-history.xml holds hand-written entries for releases +// published before GitHub Releases existed; re-emitted verbatim here. +function loadHistoryEntries() { + const historyPath = path.join(__dirname, "version-history.xml"); + const xml = fs.readFileSync(historyPath, "utf-8"); + return [...xml.matchAll(/[\s\S]*?<\/changeLog>/g)].map((m) => m[0]); +} + +function historyEntryVersion(entryXml) { + const m = entryXml.match(/([\s\S]*?)<\/changedVersionNumber>/); + return m ? m[1].trim() : null; +} + +// Static / sections carried over from the previous +// hand-maintained XML on do5amf.funkerportal.de. UpdateChecker.java doesn't +// parse these, kept only so the migration doesn't drop existing content. +function loadLegacySections() { + const legacyPath = path.join(__dirname, "version-legacy-sections.xml"); + const xml = fs.readFileSync(legacyPath, "utf-8"); + const roadmap = xml.match(/[\s\S]*?<\/roadmap>/); + const bugsReported = xml.match(/[\s\S]*?<\/bugsReported>/); + return [roadmap ? roadmap[0] : null, bugsReported ? bugsReported[0] : null].filter(Boolean); +} + +// Builds kst4ContestVersionInfo.xml (the update-checker feed read by +// UpdateChecker.java) from GitHub releases + closed issues, falling back to +// version-history.xml for releases that predate GitHub Releases. +module.exports = async function () { + const fallback = '\n'; + + try { + const historyEntries = loadHistoryEntries(); + + const rawReleases = await githubGet("/releases?per_page=100"); + const releases = rawReleases + .map((r) => ({ + tagName: r.tag_name, + publishedAt: r.published_at || "", + name: r.name || r.tag_name, + body: r.body || "", + isPrerelease: r.prerelease + })) + .sort((a, b) => (a.publishedAt < b.publishedAt ? 1 : -1)); + + const stableReleases = releases.filter((r) => !r.isPrerelease); + const stable = stableReleases[0]; + const ghVersions = new Set(stableReleases.map((r) => toAppVersionNumber(r.tagName))); + + const parts = []; + parts.push(''); + parts.push(""); + + const latestTag = stable ? stable.tagName : null; + const winFilename = latestTag ? `praktiKST-${latestTag}-windows-x64.zip` : ""; + + parts.push(" "); + if (stable) { + const latestIssues = await getIssuesForRelease("1970-01-01T00:00:00Z", stable.publishedAt); + parts.push(` ${escapeXml(toAppVersionNumber(latestTag))}`); + parts.push(" "); + parts.push(` ${escapeXml(latestIssues.added.slice(0, 300))}`); + parts.push( + ` https://github.com/${REPO}/releases/download/${latestTag}/${winFilename}` + ); + } + parts.push(" "); + + // UpdateChecker.parseUpdateXMLFile() never actually reads this field + // (setNeedUpdateResourcesSinceLastVersion is never called); the + // previous server always hardcoded "nothing" here, so we match that. + parts.push(" "); + parts.push(" nothing"); + parts.push(" "); + + for (const section of loadLegacySections()) { + parts.push(section); + } + + for (let i = 0; i < stableReleases.length; i++) { + const rel = stableReleases[i]; + const until = rel.publishedAt; + const since = stableReleases[i + 1] ? stableReleases[i + 1].publishedAt : "1970-01-01T00:00:00Z"; + const issues = await getIssuesForRelease(since, until); + + parts.push(" "); + parts.push(` ${escapeXml(toAppVersionNumber(rel.tagName))}`); + parts.push(` ${escapeXml(until.slice(0, 10))}`); + parts.push(` ${escapeXml(rel.name)}`); + parts.push(` ${escapeXml(issues.added)}`); + parts.push(` ${escapeXml(cleanReleaseBody(rel.body))}`); + parts.push(` ${escapeXml(issues.fixed)}`); + parts.push(" "); + parts.push(" "); + } + + for (const entry of historyEntries) { + const version = historyEntryVersion(entry); + if (version && ghVersions.has(version)) continue; + parts.push(entry); + } + + parts.push(""); + return parts.join("\n"); + } catch (err) { + console.warn(`[versionInfo] Could not generate version info XML, using empty fallback: ${err.message}`); + return fallback; + } +}; diff --git a/website/src/version-info.njk b/website/src/version-info.njk new file mode 100644 index 0000000..c4ba89e --- /dev/null +++ b/website/src/version-info.njk @@ -0,0 +1,5 @@ +--- +permalink: /kst4ContestVersionInfo.xml +eleventyExcludeFromCollections: true +--- +{{ versionInfo | safe }}