Skip to content

Commit 8a11549

Browse files
committed
Asset Uploads & Webpage adjustments / Auto scheduler BXT news fix
- Made various visual and functionality improvements to the BXT Trade Corner, Battle Tower and Rankings pages. - Added basic mobile support to the crystal pages. - Removed exchange.php and replaced it with tradecorner.php - Added icons and background images for various games, and removed the backgrounds for the trainer sprites. - Changed the gbwars3 pages to use the gbwars font and gave it a background. - Prettified the Mario Kart page and made it use the mkgba font. - Fixed a bug related to rankings table purging when the next news issue comes into effect (it should now purge correctly) - There is an issue with the locale dropdown on these new pages, I have not yet figured out why.
1 parent fec94dc commit 8a11549

180 files changed

Lines changed: 4507 additions & 396 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/auto-schedule/index.js

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1764,17 +1764,31 @@ async function mirrorVanillaToCustom(conn, region, vanillaId, existingCustomId)
17641764
return res.insertId;
17651765
}
17661766

1767-
async function clearRankingsForNewsId(conn, region, newsId) {
1768-
if (newsId == null) return;
1769-
await conn.execute("DELETE FROM bxt_ranking WHERE game_region = ? AND news_id = ?", [
1770-
region,
1771-
newsId,
1772-
]);
1767+
async function clearRankingsForRegion(conn, region, reason) {
1768+
if (!region) return;
1769+
await conn.execute("DELETE FROM bxt_ranking WHERE game_region = ?", [region]);
17731770
console.log(
1774-
`[news] Cleared bxt_ranking entries for region=${region} news_id=${newsId}`
1771+
`[news] Cleared bxt_ranking entries for region=${region}` +
1772+
(reason ? ` (${reason})` : "")
17751773
);
17761774
}
17771775

1776+
function allRegionsUpdatedForRun(regionFolderMap, updatedByRegion) {
1777+
const regions = Object.keys(regionFolderMap || {});
1778+
if (!regions.length) return false;
1779+
for (const region of regions) {
1780+
if (!updatedByRegion || !updatedByRegion[region]) {
1781+
return false;
1782+
}
1783+
}
1784+
return true;
1785+
}
1786+
1787+
async function clearAllRankings(conn, reason) {
1788+
await conn.execute("DELETE FROM bxt_ranking");
1789+
console.log(`[news] Cleared full bxt_ranking table (${reason})`);
1790+
}
1791+
17781792
async function processPokemonNewsCycle(
17791793
conn,
17801794
encoding,
@@ -2063,6 +2077,7 @@ async function finalizePokemonNewsCustomAndRankings(
20632077
customEnabled
20642078
) {
20652079
const regions = Object.keys(vanillaCfg.region_folder_map || {});
2080+
const customMirroredByRegion = {};
20662081

20672082
for (const region of regions) {
20682083
const vanillaRow = await getLatestBxtNewsRow(conn, region, false);
@@ -2086,6 +2101,7 @@ async function finalizePokemonNewsCustomAndRankings(
20862101
if (!customEnabled && vanillaUpdated && vanillaUpdated[region]) {
20872102
await mirrorVanillaToCustom(conn, region, vanillaRow.id, customRow ? customRow.id : null);
20882103
customRow = await getLatestBxtNewsRow(conn, region, true);
2104+
customMirroredByRegion[region] = true;
20892105
console.log(
20902106
`[news] Mirrored vanilla -> custom for region=${region} (custom track disabled)`
20912107
);
@@ -2096,22 +2112,27 @@ async function finalizePokemonNewsCustomAndRankings(
20962112
const shareRankings = arraysEqual(vanillaSig, customSig);
20972113

20982114
const vUpd = !!(vanillaUpdated && vanillaUpdated[region]);
2099-
const cUpd = !!(customUpdatedReal && customUpdatedReal[region]);
2115+
const cUpd =
2116+
!!(customUpdatedReal && customUpdatedReal[region]) ||
2117+
!!customMirroredByRegion[region];
21002118

21012119
if (shareRankings) {
2102-
// If they share ranking categories, wipe only when BOTH tracks update together.
2120+
// Shared ranking categories: wipe once when both tracks roll over together.
21032121
if (vUpd && cUpd) {
2104-
await clearRankingsForNewsId(conn, region, vanillaRow.id);
2105-
await clearRankingsForNewsId(conn, region, customRow ? customRow.id : null);
2106-
}
2107-
} else {
2108-
// Split rankings when category sets differ; wipe only the track(s) that updated.
2109-
if (vUpd) {
2110-
await clearRankingsForNewsId(conn, region, vanillaRow.id);
2111-
}
2112-
if (cUpd) {
2113-
await clearRankingsForNewsId(conn, region, customRow ? customRow.id : null);
2122+
await clearRankingsForRegion(
2123+
conn,
2124+
region,
2125+
"shared ranking categories; vanilla+custom rolled together"
2126+
);
21142127
}
2128+
} else if (vUpd || cUpd) {
2129+
// Split ranking categories: wipe once when either relevant track updates.
2130+
const source = vUpd && cUpd ? "vanilla+custom" : (vUpd ? "vanilla" : "custom");
2131+
await clearRankingsForRegion(
2132+
conn,
2133+
region,
2134+
`split ranking categories; ${source} track updated`
2135+
);
21152136
}
21162137
}
21172138
}
@@ -2180,6 +2201,13 @@ async function main() {
21802201
pokemonNewsCustomEnabled
21812202
);
21822203

2204+
if (allRegionsUpdatedForRun(newsCfg.region_folder_map, vanillaRes.updatedByRegion)) {
2205+
await clearAllRankings(
2206+
conn,
2207+
`all vanilla news regions updated for ${todayDate.toISOString().slice(0, 10)}`
2208+
);
2209+
}
2210+
21832211
// Persist cycle state (for slot-based regions), file rotations, and timed feature windows.
21842212
if (rotationCfg) {
21852213
processFileRotations(rootDir, rotationCfg, cycleState, todayDate);

web/classes/SessionUtil.php

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,32 @@ public function initSession($userId) {
2424
}
2525

2626
public function setLocale($locale) {
27-
$_SESSION["locale"] = $lang;
27+
$supported = array("en", "ja", "de", "es", "it", "fr");
28+
$normalized = strtolower(trim((string)$locale));
29+
if (!in_array($normalized, $supported, true)) {
30+
$normalized = "en";
31+
}
32+
$_SESSION["locale"] = $normalized;
2833
// TODO: Persist to user prefs if signed in
2934
return;
3035
}
3136

3237
public function getLocale() {
38+
$supported = array("en", "ja", "de", "es", "it", "fr");
3339
// TODO: Initial value from user prefs if signed in
3440
if(isset($_GET["lang"])) {
35-
$_SESSION["locale"] = $_GET["lang"];
41+
$this->setLocale($_GET["lang"]);
3642
}
3743
elseif (!isset($_SESSION["locale"])) {
3844
if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) && strlen($_SERVER['HTTP_ACCEPT_LANGUAGE'])>0) {
39-
$_SESSION["locale"] = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
45+
$this->setLocale(substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2));
46+
} else {
47+
$_SESSION["locale"] = "en";
4048
}
4149
}
50+
elseif (!in_array(strtolower((string)$_SESSION["locale"]), $supported, true)) {
51+
$_SESSION["locale"] = "en";
52+
}
4253
return $_SESSION["locale"];
4354
}
4455

web/classes/TemplateUtil.php

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ class TemplateUtil {
66

77
private static $instance;
88
private $twig;
9-
private $translator;
9+
private static $translator = null;
1010

1111
private final function __construct() {
1212
$loader = new \Twig\Loader\FilesystemLoader(dirname(__DIR__)."/templates");
@@ -32,15 +32,50 @@ public static function translate(?string $id, array $parameters = [], ?string $d
3232
}
3333

3434
public static function getTranslator() {
35+
if (self::$translator !== null) {
36+
return self::$translator;
37+
}
38+
3539
$locale = SessionUtil::getInstance()->getLocale();
3640
$translator = new \Symfony\Component\Translation\Translator($locale);
3741
$translator->setFallbackLocales(['en']);
42+
43+
if (!class_exists('\Symfony\Component\Translation\Loader\YamlFileLoader')) {
44+
error_log("Translation YAML loader class unavailable; locale resources cannot be loaded.");
45+
self::$translator = $translator;
46+
return self::$translator;
47+
}
48+
3849
$translator->addLoader('yaml', new \Symfony\Component\Translation\Loader\YamlFileLoader());
39-
$supported_locales = ['en', 'es', 'de', 'ja', 'it', 'fr'];
40-
foreach($supported_locales as $l) {
41-
$translator->addResource('yaml', dirname(__DIR__).'/locales/'.$l.'.yml', $l);
50+
51+
$supported_locales = ['en', 'es', 'de', 'ja', 'it', 'fr'];
52+
foreach ($supported_locales as $l) {
53+
$path = dirname(__DIR__) . '/locales/' . $l . '.yml';
54+
if (!is_file($path)) {
55+
continue;
56+
}
57+
58+
try {
59+
if (class_exists('\Symfony\Component\Yaml\Yaml')) {
60+
$raw = @file_get_contents($path);
61+
if (!is_string($raw) || $raw === '') {
62+
throw new \RuntimeException("Locale file is empty or unreadable");
63+
}
64+
65+
$sanitized = preg_replace('/^\xEF\xBB\xBF/', '', $raw);
66+
$sanitized = preg_replace('/^\s*---\s*(\r?\n)/m', '', $sanitized);
67+
$sanitized = preg_replace('/^\s*\.\.\.\s*(\r?\n)/m', '', $sanitized);
68+
\Symfony\Component\Yaml\Yaml::parse($sanitized);
69+
}
70+
71+
$translator->addResource('yaml', $path, $l);
72+
} catch (\Throwable $e) {
73+
error_log("Skipping invalid locale YAML [{$l}] at {$path}: " . $e->getMessage());
74+
}
4275
}
43-
return $translator;
76+
77+
self::$translator = $translator;
78+
return self::$translator;
4479
}
4580

4681
}

0 commit comments

Comments
 (0)