diff --git a/CHANGELOG.md b/CHANGELOG.md index 997b36ac..407d943a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Changelog ## 2026-01-31 +- Added adapter AppID lookup for Workshop search so the picker can query Steam even when the server XML lacks a clear default installer entry. +- Switched Workshop picker results to checkbox selection, letting customers toggle multiple mods directly from the search list. - Added a hardened Workshop scraping helper (the same HTML workflow we validated manually) and wired it into the Steam Workshop service as a fallback whenever the official API errors out or returns empty data. - Added a native PHP HTTP scraper fallback (auto-selected when bash/proc_open is unavailable, e.g., on Windows XAMPP installs) so the Game Monitor search stops showing “Unable to contact the Steam Workshop” when the API dies but the HTML workflow still works. - Surface scraper vs API attempts (including shell commands, exit codes, and stderr) in the JSON response so the Game Monitor can show exactly which backend produced the results. diff --git a/docs/COPILOT_TODO.md b/docs/COPILOT_TODO.md index f8a442e1..21f28cdb 100644 --- a/docs/COPILOT_TODO.md +++ b/docs/COPILOT_TODO.md @@ -2,3 +2,4 @@ - Allow players/admins to reorder selected Workshop mods in the new picker UI so load order matches game expectations. - Surface pagination controls in the Workshop picker so users can request additional batches from the new Steam Web API search endpoint. - Add an admin-facing toggle that makes it clear when the HTML scraper fallback is in use and lets staff force API-only mode if Valve ever objects. +- Add Workshop result preview thumbnails and author links in the picker for easier browsing. diff --git a/modules/billing/timestamp.txt b/modules/billing/timestamp.txt index c1ed03b0..470a54ae 100644 --- a/modules/billing/timestamp.txt +++ b/modules/billing/timestamp.txt @@ -1 +1 @@ -Last Updated at 11:40am on 2025-06-12 +Last Updated at 6:32pm on 2026-01-31 diff --git a/modules/steam_workshop/lib/SteamWorkshopService.php b/modules/steam_workshop/lib/SteamWorkshopService.php index 8cae708e..6441ff7a 100644 --- a/modules/steam_workshop/lib/SteamWorkshopService.php +++ b/modules/steam_workshop/lib/SteamWorkshopService.php @@ -620,6 +620,20 @@ class SteamWorkshopService public function getSteamAppIdForGameKey(string $gameKey): ?string { + $gameKey = trim($gameKey); + if ($gameKey === '') { + return null; + } + + $adapterKey = $this->getAdapterKeyForGame($gameKey); + if ($adapterKey !== null && $adapterKey !== '') { + $adapter = $this->getAdapterByKey($adapterKey); + $adapterAppId = isset($adapter['steam_app_id']) ? trim((string)$adapter['steam_app_id']) : ''; + if ($adapterAppId !== '') { + return $adapterAppId; + } + } + $xml = $this->loadServerConfigXml($gameKey); if ($xml === null) { return null; diff --git a/modules/steam_workshop/steam_workshop.css b/modules/steam_workshop/steam_workshop.css index 6025491c..70433164 100644 --- a/modules/steam_workshop/steam_workshop.css +++ b/modules/steam_workshop/steam_workshop.css @@ -514,6 +514,12 @@ overflow-x: auto; } +.sw-picker__results-hint { + margin: 0.35rem 0 0.6rem; + color: #555; + font-size: 0.9rem; +} + .sw-picker__request-row { margin-top: 0.75rem; } @@ -563,6 +569,17 @@ color: #fff; } +.sw-picker__result-toggle { + display: inline-flex; + align-items: center; + gap: 0.35rem; + font-size: 0.85rem; +} + +.sw-picker__result-toggle input { + width: auto; +} + .sw-picker__empty { color: #777; font-size: 0.9rem; diff --git a/modules/steam_workshop/steam_workshop.js b/modules/steam_workshop/steam_workshop.js index f816275f..29d8673d 100644 --- a/modules/steam_workshop/steam_workshop.js +++ b/modules/steam_workshop/steam_workshop.js @@ -109,17 +109,22 @@ }); } if (this.resultsBody) { - this.resultsBody.addEventListener('click', function (event) { + this.resultsBody.addEventListener('change', function (event) { var target = event.target; - if (!(target instanceof HTMLElement)) { + if (!(target instanceof HTMLInputElement)) { return; } - if (target.matches('.js-sw-add')) { + if (target.matches('.js-sw-result-toggle')) { var payload = target.getAttribute('data-payload'); if (payload) { try { var data = JSON.parse(payload); - _this.addSelected(data); + if (target.checked) { + _this.addSelected(data); + } + else { + _this.removeSelected(String(data.id)); + } } catch (err) { console.warn('Invalid payload', err); @@ -208,15 +213,18 @@ }; var row = document.createElement('tr'); var selectCell = document.createElement('td'); - var action = document.createElement('button'); - action.type = 'button'; - action.className = 'btn btn-xs sw-picker__action js-sw-add'; - action.textContent = this_1.lang.add; - action.setAttribute('data-payload', JSON.stringify(normalized)); - if (this_1.isSelected(normalized.id)) { - action.disabled = true; - } - selectCell.appendChild(action); + var toggle = document.createElement('label'); + toggle.className = 'sw-picker__result-toggle'; + var checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.className = 'js-sw-result-toggle'; + checkbox.setAttribute('data-payload', JSON.stringify(normalized)); + checkbox.checked = this_1.isSelected(normalized.id); + toggle.appendChild(checkbox); + var toggleText = document.createElement('span'); + toggleText.textContent = this_1.lang.add; + toggle.appendChild(toggleText); + selectCell.appendChild(toggle); var titleCell = document.createElement('td'); titleCell.innerHTML = '' + this_1.escape(normalized.label) + '
'; var authorCell = document.createElement('td'); @@ -261,14 +269,12 @@ }); this.persist(); this.renderSelected(); - this.renderResults(this.lastResults || []); }; Picker.prototype.removeSelected = function (id) { var next = this.state.selected.filter(function (item) { return item.id !== id; }); this.state.selected = next; this.persist(); this.renderSelected(); - this.renderResults(this.lastResults || []); }; Picker.prototype.toggleSelected = function (id, enabled) { var changed = false; diff --git a/modules/steam_workshop/views/partials/mod_picker.php b/modules/steam_workshop/views/partials/mod_picker.php index d7d734b5..648264ac 100644 --- a/modules/steam_workshop/views/partials/mod_picker.php +++ b/modules/steam_workshop/views/partials/mod_picker.php @@ -80,6 +80,7 @@ $langAttrs = [