reaper-arcade-hub 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.html CHANGED
@@ -173,20 +173,14 @@
173
173
  <input type="text" id="opium-search-input" class="opium-search-input" placeholder="Search 780+ games or topics..." autocomplete="off" onkeydown="if(event.key==='Enter') app.handleOpiumSearch()">
174
174
  </div>
175
175
 
176
- <!-- Quick Navigation Tiles & Save Manager -->
177
- <div style="display: flex; gap: 0.85rem; flex-wrap: wrap; justify-content: center; max-width: 650px; margin-bottom: 1.25rem;">
176
+ <!-- Quick Navigation Tiles -->
177
+ <div style="display: flex; gap: 0.85rem; flex-wrap: wrap; justify-content: center; max-width: 580px; margin-bottom: 1.25rem;">
178
178
  <button class="btn-primary" style="padding: 0.75rem 1.4rem; font-size: 0.88rem;" onclick="app.switchTab('games')">
179
179
  BROWSE 788 GAMES
180
180
  </button>
181
181
  <button class="btn-stealth" style="padding: 0.75rem 1.4rem; font-size: 0.88rem;" onclick="app.switchTab('leaderboard')">
182
182
  PLAYTIME LEADERBOARD
183
183
  </button>
184
- <button class="btn-stealth" style="padding: 0.75rem 1.4rem; font-size: 0.88rem; color: #00ffaa; border-color: rgba(0,255,170,0.3);" onclick="app.exportSaveData()" title="Backup your game saves">
185
- 💾 BACKUP SAVES
186
- </button>
187
- <button class="btn-stealth" style="padding: 0.75rem 1.4rem; font-size: 0.88rem; color: #ffd700; border-color: rgba(255,215,0,0.3);" onclick="app.importSaveData()" title="Restore game save data">
188
- 📥 RESTORE SAVES
189
- </button>
190
184
  </div>
191
185
  </div>
192
186
  </section>
@@ -604,7 +598,6 @@
604
598
  <div style="display: flex; border-bottom: 1px solid var(--blue-border); background: #030a18; padding: 0.5rem 1.4rem; gap: 0.5rem; overflow-x: auto;">
605
599
  <button class="nav-tab-btn active" id="st-tab-btn-shield" onclick="app.switchSettingsTab('shield')" style="padding: 0.45rem 1rem; font-size: 0.82rem;">🛡️ Security Shield</button>
606
600
  <button class="nav-tab-btn" id="st-tab-btn-prefs" onclick="app.switchSettingsTab('prefs')" style="padding: 0.45rem 1rem; font-size: 0.82rem;">⚡ Preferences &amp; Audio</button>
607
- <button class="nav-tab-btn" id="st-tab-btn-saves" onclick="app.switchSettingsTab('saves')" style="padding: 0.45rem 1rem; font-size: 0.82rem;">💾 Game Saves</button>
608
601
  <button class="nav-tab-btn" id="st-tab-btn-identity" onclick="app.switchSettingsTab('identity')" style="padding: 0.45rem 1rem; font-size: 0.82rem;">🔑 Device &amp; Rank</button>
609
602
  </div>
610
603
 
@@ -659,6 +652,26 @@
659
652
  <!-- SUBTAB 2: PREFERENCES & AUDIO -->
660
653
  <div id="st-content-prefs" style="display: none;">
661
654
  <div style="display: flex; flex-direction: column; gap: 1.2rem;">
655
+
656
+ <!-- Auto about:blank toggle -->
657
+ <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px; display: flex; justify-content: space-between; align-items: center;">
658
+ <div>
659
+ <strong style="color: #fff; font-size: 0.95rem;">🌐 Auto-Cloak in about:blank on Visit</strong>
660
+ <p style="color: #88aacc; font-size: 0.8rem;">Automatically opens Reaper Hub in an undetectable about:blank tab every time you visit.</p>
661
+ </div>
662
+ <input type="checkbox" id="auto-aboutblank-toggle" style="width: 22px; height: 22px; cursor: pointer; accent-color: #00d2ff;" onchange="app.toggleAutoAboutBlank(this.checked)">
663
+ </div>
664
+
665
+ <!-- Launch in about:blank button -->
666
+ <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px; display: flex; justify-content: space-between; align-items: center;">
667
+ <div>
668
+ <strong style="color: #00d2ff; font-size: 0.95rem;">🚀 Launch Site in about:blank Tab</strong>
669
+ <p style="color: #88aacc; font-size: 0.8rem;">Spawn this entire portal inside a clean Google Classroom disguised about:blank window.</p>
670
+ </div>
671
+ <button class="btn-primary" onclick="app.openSiteAboutBlank()" style="font-size: 0.82rem; padding: 0.5rem 1.2rem;">LAUNCH CLOAK</button>
672
+ </div>
673
+
674
+ <!-- SFX toggle -->
662
675
  <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px; display: flex; justify-content: space-between; align-items: center;">
663
676
  <div>
664
677
  <strong style="color: #fff; font-size: 0.95rem;">🔊 Sci-Fi Synthesizer Sound FX</strong>
@@ -676,24 +689,7 @@
676
689
  </div>
677
690
  </div>
678
691
 
679
- <!-- SUBTAB 3: GAME SAVES -->
680
- <div id="st-content-saves" style="display: none;">
681
- <div style="display: flex; flex-direction: column; gap: 1.2rem;">
682
- <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px;">
683
- <strong style="color: #00ffaa; font-size: 0.95rem;">💾 Export &amp; Backup Game Save Data</strong>
684
- <p style="color: #88aacc; font-size: 0.8rem; margin: 0.4rem 0 0.85rem 0;">Download a single backup file containing all your local progress for Slope, Subway Surfers, BitLife, Retro Bowl, 1v1.LOL, and more.</p>
685
- <button class="btn-primary" onclick="app.exportSaveData()" style="background: #00ffaa; color: #000; border-color: #00ffaa; font-size: 0.82rem;">💾 DOWNLOAD SAVE BACKUP</button>
686
- </div>
687
-
688
- <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px;">
689
- <strong style="color: #ffd700; font-size: 0.95rem;">📥 Import &amp; Restore Game Save Data</strong>
690
- <p style="color: #88aacc; font-size: 0.8rem; margin: 0.4rem 0 0.85rem 0;">Upload a previously downloaded JSON save backup file to restore all your game saves instantly.</p>
691
- <button class="btn-primary" onclick="app.importSaveData()" style="background: #ffd700; color: #000; border-color: #ffd700; font-size: 0.82rem;">📥 RESTORE SAVE BACKUP</button>
692
- </div>
693
- </div>
694
- </div>
695
-
696
- <!-- SUBTAB 4: IDENTITY & HWID -->
692
+ <!-- SUBTAB 3: IDENTITY & HWID -->
697
693
  <div id="st-content-identity" style="display: none;">
698
694
  <div style="display: flex; flex-direction: column; gap: 1rem;">
699
695
  <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px;">
package/js/app.js CHANGED
@@ -179,6 +179,18 @@ class ReaperHubApp {
179
179
 
180
180
  this.syncPlaytimeToDB();
181
181
 
182
+ // 10. Auto about:blank Cloak on Visit Check
183
+ const isAutoAboutBlank = localStorage.getItem('reaper_auto_about_blank') === 'true';
184
+ const autoBlankToggle = document.getElementById('auto-aboutblank-toggle');
185
+ if (autoBlankToggle) autoBlankToggle.checked = isAutoAboutBlank;
186
+
187
+ if (isAutoAboutBlank && window.self === window.top && !window.location.protocol.includes('about:')) {
188
+ if (sessionStorage.getItem('reaper_cloaked_session') !== 'true') {
189
+ sessionStorage.setItem('reaper_cloaked_session', 'true');
190
+ this.openSiteAboutBlank();
191
+ }
192
+ }
193
+
182
194
  console.log(`[REAPER HUB] System Online. Role: ${this.currentUser.rank.toUpperCase()}`);
183
195
  }
184
196
 
@@ -949,7 +961,7 @@ class ReaperHubApp {
949
961
  localStorage.setItem('reaper_playtime_' + this.currentUser.username, this.playtimeSeconds.toString());
950
962
  this.updatePlaytimeStatusUI();
951
963
 
952
- if (this.playtimeSeconds % 10 === 0) {
964
+ if (this.playtimeSeconds % 5 === 0) {
953
965
  this.syncPlaytimeToDB();
954
966
  }
955
967
  }
@@ -1366,47 +1378,6 @@ class ReaperHubApp {
1366
1378
  this.showToast("Recently played list cleared.");
1367
1379
  }
1368
1380
 
1369
- exportSaveData() {
1370
- const backup = {};
1371
- for (let i = 0; i < localStorage.length; i++) {
1372
- const key = localStorage.key(i);
1373
- backup[key] = localStorage.getItem(key);
1374
- }
1375
- const blob = new Blob([JSON.stringify(backup, null, 2)], { type: 'application/json' });
1376
- const url = URL.createObjectURL(blob);
1377
- const a = document.createElement('a');
1378
- a.href = url;
1379
- a.download = `reaper_save_backup_${new Date().toISOString().slice(0,10)}.json`;
1380
- a.click();
1381
- URL.revokeObjectURL(url);
1382
- this.showToast("Game save data downloaded! 💾");
1383
- }
1384
-
1385
- importSaveData() {
1386
- const input = document.createElement('input');
1387
- input.type = 'file';
1388
- input.accept = '.json';
1389
- input.onchange = (e) => {
1390
- const file = e.target.files[0];
1391
- if (!file) return;
1392
- const reader = new FileReader();
1393
- reader.onload = (event) => {
1394
- try {
1395
- const data = JSON.parse(event.target.result);
1396
- Object.entries(data).forEach(([k, v]) => {
1397
- localStorage.setItem(k, v);
1398
- });
1399
- this.showToast("Save data restored! Reloading...");
1400
- setTimeout(() => window.location.reload(), 1200);
1401
- } catch (err) {
1402
- alert("Invalid backup file.");
1403
- }
1404
- };
1405
- reader.readAsText(file);
1406
- };
1407
- input.click();
1408
- }
1409
-
1410
1381
  toggleSoundFX() {
1411
1382
  if (window.reaperSFX) {
1412
1383
  const enabled = window.reaperSFX.toggleSound();
@@ -1525,55 +1496,96 @@ class ReaperHubApp {
1525
1496
  async openGameAboutBlank() {
1526
1497
  if (!this.currentGame) return;
1527
1498
  const filename = this.currentGame.url.split('/').pop();
1499
+ const gameName = this.currentGame.name;
1500
+ const siteUrl = window.location.href;
1528
1501
  const win = window.open('about:blank', '_blank');
1529
1502
  if (win) {
1530
1503
  const doc = win.document;
1531
- doc.title = "Google Classroom";
1532
- const link = doc.createElement('link');
1533
- link.rel = 'icon';
1534
- link.href = 'https://ssl.gstatic.com/classroom/favicon.png';
1535
- doc.head.appendChild(link);
1536
-
1537
- const frame = doc.createElement('iframe');
1538
- frame.style.border = 'none';
1539
- frame.style.width = '100vw';
1540
- frame.style.height = '100vh';
1541
- frame.style.margin = '0';
1542
- frame.style.position = 'fixed';
1543
- frame.style.top = '0';
1544
- frame.style.left = '0';
1545
- frame.allow = 'autoplay; fullscreen; gamepad';
1504
+ doc.title = "Home - Google Classroom";
1546
1505
 
1506
+ let gameHtml = '';
1547
1507
  try {
1548
1508
  const res = await fetch(`https://raw.githubusercontent.com/gn-math/html/main/${filename}`);
1549
1509
  if (res.ok) {
1550
- let html = await res.text();
1551
- if (html && html.length > 50) {
1552
- html = html.replace(/https?:\/\/cdn\.jsdelivr\.net\/gh\//g, 'https://fastly.jsdelivr.net/gh/');
1553
- html = html.replace(/https?:\/\/cdn\.jsdelivr\.net\/npm\//g, 'https://fastly.jsdelivr.net/npm/');
1554
- frame.srcdoc = html;
1555
- } else {
1556
- frame.src = `https://fastly.jsdelivr.net/gh/gn-math/html@main/${filename}`;
1510
+ gameHtml = await res.text();
1511
+ if (gameHtml && gameHtml.length > 50) {
1512
+ gameHtml = gameHtml.replace(/https?:\/\/cdn\.jsdelivr\.net\/gh\//g, 'https://fastly.jsdelivr.net/gh/');
1513
+ gameHtml = gameHtml.replace(/https?:\/\/cdn\.jsdelivr\.net\/npm\//g, 'https://fastly.jsdelivr.net/npm/');
1557
1514
  }
1558
- } else {
1559
- frame.src = `https://fastly.jsdelivr.net/gh/gn-math/html@main/${filename}`;
1560
1515
  }
1561
- } catch (e) {
1562
- frame.src = `https://fastly.jsdelivr.net/gh/gn-math/html@main/${filename}`;
1516
+ } catch (e) {}
1517
+
1518
+ doc.open();
1519
+ doc.write(`
1520
+ <!DOCTYPE html>
1521
+ <html>
1522
+ <head>
1523
+ <title>Home - Google Classroom</title>
1524
+ <link rel="icon" href="https://ssl.gstatic.com/classroom/favicon.png">
1525
+ <style>
1526
+ * { margin: 0; padding: 0; box-sizing: border-box; }
1527
+ body { background: #000; overflow: hidden; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
1528
+ #game-frame { width: 100vw; height: 100vh; border: none; position: fixed; top: 0; left: 0; z-index: 1; }
1529
+ .reaper-bar {
1530
+ position: fixed; top: 12px; left: 14px; z-index: 9999;
1531
+ display: flex; gap: 8px; align-items: center;
1532
+ background: rgba(3, 8, 18, 0.88); backdrop-filter: blur(8px);
1533
+ border: 1.5px solid rgba(0, 136, 255, 0.4); border-radius: 8px; padding: 6px 12px;
1534
+ box-shadow: 0 4px 20px rgba(0,0,0,0.7);
1535
+ opacity: 0.85; transition: opacity 0.2s ease, border-color 0.2s ease;
1536
+ }
1537
+ .reaper-bar:hover { opacity: 1; border-color: #00d2ff; }
1538
+ .btn-action {
1539
+ background: #041022; color: #00d2ff; border: 1px solid rgba(0, 136, 255, 0.4);
1540
+ padding: 5px 12px; border-radius: 6px; font-size: 11px; font-weight: 800;
1541
+ cursor: pointer; text-decoration: none; display: inline-flex; align-items: center; gap: 4px;
1542
+ transition: all 0.2s ease; font-family: inherit;
1543
+ }
1544
+ .btn-action:hover { background: #0088ff; color: #fff; box-shadow: 0 0 10px rgba(0,136,255,0.6); }
1545
+ .reaper-watermark {
1546
+ position: fixed; bottom: 10px; right: 14px; z-index: 9999;
1547
+ font-family: serif; font-weight: 900; font-size: 13px; letter-spacing: 0.12em;
1548
+ color: rgba(255, 255, 255, 0.35); text-shadow: 0 0 10px rgba(0, 136, 255, 0.6);
1549
+ pointer-events: none; user-select: none;
1550
+ }
1551
+ </style>
1552
+ <script>
1553
+ // Client-Side Ad & Pop-up Blocker
1554
+ window.open = function() { console.log('[REAPER SHIELD] Ad pop-up blocked'); return null; };
1555
+ <\/script>
1556
+ </head>
1557
+ <body>
1558
+ <div class="reaper-bar">
1559
+ <a href="${siteUrl}" class="btn-action" title="Return to Reaper Hub Portal">⚡ BACK TO SITE</a>
1560
+ <button onclick="document.getElementById('game-frame').requestFullscreen()" class="btn-action">⛶ FULLSCREEN</button>
1561
+ <button onclick="document.getElementById('game-frame').contentWindow.location.reload()" class="btn-action">🔄 RELOAD</button>
1562
+ </div>
1563
+ <div class="reaper-watermark">REAPER HUB</div>
1564
+ <iframe id="game-frame" allow="autoplay; fullscreen; gamepad" ${gameHtml ? '' : `src="https://fastly.jsdelivr.net/gh/gn-math/html@main/${filename}"`}></iframe>
1565
+ </body>
1566
+ </html>
1567
+ `);
1568
+ doc.close();
1569
+
1570
+ if (gameHtml) {
1571
+ const f = doc.getElementById('game-frame');
1572
+ if (f) f.srcdoc = gameHtml;
1563
1573
  }
1564
1574
 
1565
- doc.body.style.margin = '0';
1566
- doc.body.style.overflow = 'hidden';
1567
- doc.body.appendChild(frame);
1568
- this.showToast("Game launched in about:blank tab.");
1575
+ this.showToast("Game opened in about:blank tab with watermark & return controls.");
1569
1576
  }
1570
1577
  }
1571
1578
 
1579
+ toggleAutoAboutBlank(enabled) {
1580
+ localStorage.setItem('reaper_auto_about_blank', enabled ? 'true' : 'false');
1581
+ this.showToast(enabled ? "Auto about:blank cloak enabled on every visit." : "Auto about:blank disabled.");
1582
+ }
1583
+
1572
1584
  openSiteAboutBlank() {
1573
1585
  const win = window.open('about:blank', '_blank');
1574
1586
  if (win) {
1575
1587
  const doc = win.document;
1576
- doc.title = "Classes";
1588
+ doc.title = "Home - Google Classroom";
1577
1589
  const link = doc.createElement('link');
1578
1590
  link.rel = 'icon';
1579
1591
  link.href = 'https://ssl.gstatic.com/classroom/favicon.png';
@@ -1977,7 +1989,7 @@ class ReaperHubApp {
1977
1989
  }
1978
1990
 
1979
1991
  switchSettingsTab(tabName) {
1980
- ['shield', 'prefs', 'saves', 'identity'].forEach(t => {
1992
+ ['shield', 'prefs', 'identity'].forEach(t => {
1981
1993
  const btn = document.getElementById(`st-tab-btn-${t}`);
1982
1994
  const content = document.getElementById(`st-content-${t}`);
1983
1995
  if (btn) btn.classList.toggle('active', t === tabName);
@@ -217,6 +217,15 @@
217
217
  count++;
218
218
  }
219
219
  }
220
+
221
+ // Kill client-side third-party ad script injections & tracking pop-up tags
222
+ const adNodes = document.querySelectorAll('script[src*="googlesyndication"], script[src*="doubleclick"], script[src*="adnxs"], script[src*="monetag"], script[src*="popcash"], script[src*="propellerads"], div[class*="ad-banner" i], div[id*="ad-container" i]');
223
+ for (let i = 0; i < adNodes.length; i++) {
224
+ if (adNodes[i] && adNodes[i].parentNode) {
225
+ adNodes[i].parentNode.removeChild(adNodes[i]);
226
+ count++;
227
+ }
228
+ }
220
229
  } catch (e) {}
221
230
 
222
231
  this.blockedCount += count;
package/main/index.html CHANGED
@@ -173,20 +173,14 @@
173
173
  <input type="text" id="opium-search-input" class="opium-search-input" placeholder="Search 780+ games or topics..." autocomplete="off" onkeydown="if(event.key==='Enter') app.handleOpiumSearch()">
174
174
  </div>
175
175
 
176
- <!-- Quick Navigation Tiles & Save Manager -->
177
- <div style="display: flex; gap: 0.85rem; flex-wrap: wrap; justify-content: center; max-width: 650px; margin-bottom: 1.25rem;">
176
+ <!-- Quick Navigation Tiles -->
177
+ <div style="display: flex; gap: 0.85rem; flex-wrap: wrap; justify-content: center; max-width: 580px; margin-bottom: 1.25rem;">
178
178
  <button class="btn-primary" style="padding: 0.75rem 1.4rem; font-size: 0.88rem;" onclick="app.switchTab('games')">
179
179
  BROWSE 788 GAMES
180
180
  </button>
181
181
  <button class="btn-stealth" style="padding: 0.75rem 1.4rem; font-size: 0.88rem;" onclick="app.switchTab('leaderboard')">
182
182
  PLAYTIME LEADERBOARD
183
183
  </button>
184
- <button class="btn-stealth" style="padding: 0.75rem 1.4rem; font-size: 0.88rem; color: #00ffaa; border-color: rgba(0,255,170,0.3);" onclick="app.exportSaveData()" title="Backup your game saves">
185
- 💾 BACKUP SAVES
186
- </button>
187
- <button class="btn-stealth" style="padding: 0.75rem 1.4rem; font-size: 0.88rem; color: #ffd700; border-color: rgba(255,215,0,0.3);" onclick="app.importSaveData()" title="Restore game save data">
188
- 📥 RESTORE SAVES
189
- </button>
190
184
  </div>
191
185
  </div>
192
186
  </section>
@@ -604,7 +598,6 @@
604
598
  <div style="display: flex; border-bottom: 1px solid var(--blue-border); background: #030a18; padding: 0.5rem 1.4rem; gap: 0.5rem; overflow-x: auto;">
605
599
  <button class="nav-tab-btn active" id="st-tab-btn-shield" onclick="app.switchSettingsTab('shield')" style="padding: 0.45rem 1rem; font-size: 0.82rem;">🛡️ Security Shield</button>
606
600
  <button class="nav-tab-btn" id="st-tab-btn-prefs" onclick="app.switchSettingsTab('prefs')" style="padding: 0.45rem 1rem; font-size: 0.82rem;">⚡ Preferences &amp; Audio</button>
607
- <button class="nav-tab-btn" id="st-tab-btn-saves" onclick="app.switchSettingsTab('saves')" style="padding: 0.45rem 1rem; font-size: 0.82rem;">💾 Game Saves</button>
608
601
  <button class="nav-tab-btn" id="st-tab-btn-identity" onclick="app.switchSettingsTab('identity')" style="padding: 0.45rem 1rem; font-size: 0.82rem;">🔑 Device &amp; Rank</button>
609
602
  </div>
610
603
 
@@ -659,6 +652,26 @@
659
652
  <!-- SUBTAB 2: PREFERENCES & AUDIO -->
660
653
  <div id="st-content-prefs" style="display: none;">
661
654
  <div style="display: flex; flex-direction: column; gap: 1.2rem;">
655
+
656
+ <!-- Auto about:blank toggle -->
657
+ <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px; display: flex; justify-content: space-between; align-items: center;">
658
+ <div>
659
+ <strong style="color: #fff; font-size: 0.95rem;">🌐 Auto-Cloak in about:blank on Visit</strong>
660
+ <p style="color: #88aacc; font-size: 0.8rem;">Automatically opens Reaper Hub in an undetectable about:blank tab every time you visit.</p>
661
+ </div>
662
+ <input type="checkbox" id="auto-aboutblank-toggle" style="width: 22px; height: 22px; cursor: pointer; accent-color: #00d2ff;" onchange="app.toggleAutoAboutBlank(this.checked)">
663
+ </div>
664
+
665
+ <!-- Launch in about:blank button -->
666
+ <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px; display: flex; justify-content: space-between; align-items: center;">
667
+ <div>
668
+ <strong style="color: #00d2ff; font-size: 0.95rem;">🚀 Launch Site in about:blank Tab</strong>
669
+ <p style="color: #88aacc; font-size: 0.8rem;">Spawn this entire portal inside a clean Google Classroom disguised about:blank window.</p>
670
+ </div>
671
+ <button class="btn-primary" onclick="app.openSiteAboutBlank()" style="font-size: 0.82rem; padding: 0.5rem 1.2rem;">LAUNCH CLOAK</button>
672
+ </div>
673
+
674
+ <!-- SFX toggle -->
662
675
  <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px; display: flex; justify-content: space-between; align-items: center;">
663
676
  <div>
664
677
  <strong style="color: #fff; font-size: 0.95rem;">🔊 Sci-Fi Synthesizer Sound FX</strong>
@@ -676,24 +689,7 @@
676
689
  </div>
677
690
  </div>
678
691
 
679
- <!-- SUBTAB 3: GAME SAVES -->
680
- <div id="st-content-saves" style="display: none;">
681
- <div style="display: flex; flex-direction: column; gap: 1.2rem;">
682
- <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px;">
683
- <strong style="color: #00ffaa; font-size: 0.95rem;">💾 Export &amp; Backup Game Save Data</strong>
684
- <p style="color: #88aacc; font-size: 0.8rem; margin: 0.4rem 0 0.85rem 0;">Download a single backup file containing all your local progress for Slope, Subway Surfers, BitLife, Retro Bowl, 1v1.LOL, and more.</p>
685
- <button class="btn-primary" onclick="app.exportSaveData()" style="background: #00ffaa; color: #000; border-color: #00ffaa; font-size: 0.82rem;">💾 DOWNLOAD SAVE BACKUP</button>
686
- </div>
687
-
688
- <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px;">
689
- <strong style="color: #ffd700; font-size: 0.95rem;">📥 Import &amp; Restore Game Save Data</strong>
690
- <p style="color: #88aacc; font-size: 0.8rem; margin: 0.4rem 0 0.85rem 0;">Upload a previously downloaded JSON save backup file to restore all your game saves instantly.</p>
691
- <button class="btn-primary" onclick="app.importSaveData()" style="background: #ffd700; color: #000; border-color: #ffd700; font-size: 0.82rem;">📥 RESTORE SAVE BACKUP</button>
692
- </div>
693
- </div>
694
- </div>
695
-
696
- <!-- SUBTAB 4: IDENTITY & HWID -->
692
+ <!-- SUBTAB 3: IDENTITY & HWID -->
697
693
  <div id="st-content-identity" style="display: none;">
698
694
  <div style="display: flex; flex-direction: column; gap: 1rem;">
699
695
  <div style="background: #040e1e; border: 1px solid var(--blue-border); padding: 1rem 1.25rem; border-radius: 8px;">
package/main/js/app.js CHANGED
@@ -179,6 +179,18 @@ class ReaperHubApp {
179
179
 
180
180
  this.syncPlaytimeToDB();
181
181
 
182
+ // 10. Auto about:blank Cloak on Visit Check
183
+ const isAutoAboutBlank = localStorage.getItem('reaper_auto_about_blank') === 'true';
184
+ const autoBlankToggle = document.getElementById('auto-aboutblank-toggle');
185
+ if (autoBlankToggle) autoBlankToggle.checked = isAutoAboutBlank;
186
+
187
+ if (isAutoAboutBlank && window.self === window.top && !window.location.protocol.includes('about:')) {
188
+ if (sessionStorage.getItem('reaper_cloaked_session') !== 'true') {
189
+ sessionStorage.setItem('reaper_cloaked_session', 'true');
190
+ this.openSiteAboutBlank();
191
+ }
192
+ }
193
+
182
194
  console.log(`[REAPER HUB] System Online. Role: ${this.currentUser.rank.toUpperCase()}`);
183
195
  }
184
196
 
@@ -949,7 +961,7 @@ class ReaperHubApp {
949
961
  localStorage.setItem('reaper_playtime_' + this.currentUser.username, this.playtimeSeconds.toString());
950
962
  this.updatePlaytimeStatusUI();
951
963
 
952
- if (this.playtimeSeconds % 10 === 0) {
964
+ if (this.playtimeSeconds % 5 === 0) {
953
965
  this.syncPlaytimeToDB();
954
966
  }
955
967
  }
@@ -1366,47 +1378,6 @@ class ReaperHubApp {
1366
1378
  this.showToast("Recently played list cleared.");
1367
1379
  }
1368
1380
 
1369
- exportSaveData() {
1370
- const backup = {};
1371
- for (let i = 0; i < localStorage.length; i++) {
1372
- const key = localStorage.key(i);
1373
- backup[key] = localStorage.getItem(key);
1374
- }
1375
- const blob = new Blob([JSON.stringify(backup, null, 2)], { type: 'application/json' });
1376
- const url = URL.createObjectURL(blob);
1377
- const a = document.createElement('a');
1378
- a.href = url;
1379
- a.download = `reaper_save_backup_${new Date().toISOString().slice(0,10)}.json`;
1380
- a.click();
1381
- URL.revokeObjectURL(url);
1382
- this.showToast("Game save data downloaded! 💾");
1383
- }
1384
-
1385
- importSaveData() {
1386
- const input = document.createElement('input');
1387
- input.type = 'file';
1388
- input.accept = '.json';
1389
- input.onchange = (e) => {
1390
- const file = e.target.files[0];
1391
- if (!file) return;
1392
- const reader = new FileReader();
1393
- reader.onload = (event) => {
1394
- try {
1395
- const data = JSON.parse(event.target.result);
1396
- Object.entries(data).forEach(([k, v]) => {
1397
- localStorage.setItem(k, v);
1398
- });
1399
- this.showToast("Save data restored! Reloading...");
1400
- setTimeout(() => window.location.reload(), 1200);
1401
- } catch (err) {
1402
- alert("Invalid backup file.");
1403
- }
1404
- };
1405
- reader.readAsText(file);
1406
- };
1407
- input.click();
1408
- }
1409
-
1410
1381
  toggleSoundFX() {
1411
1382
  if (window.reaperSFX) {
1412
1383
  const enabled = window.reaperSFX.toggleSound();
@@ -1525,55 +1496,96 @@ class ReaperHubApp {
1525
1496
  async openGameAboutBlank() {
1526
1497
  if (!this.currentGame) return;
1527
1498
  const filename = this.currentGame.url.split('/').pop();
1499
+ const gameName = this.currentGame.name;
1500
+ const siteUrl = window.location.href;
1528
1501
  const win = window.open('about:blank', '_blank');
1529
1502
  if (win) {
1530
1503
  const doc = win.document;
1531
- doc.title = "Google Classroom";
1532
- const link = doc.createElement('link');
1533
- link.rel = 'icon';
1534
- link.href = 'https://ssl.gstatic.com/classroom/favicon.png';
1535
- doc.head.appendChild(link);
1536
-
1537
- const frame = doc.createElement('iframe');
1538
- frame.style.border = 'none';
1539
- frame.style.width = '100vw';
1540
- frame.style.height = '100vh';
1541
- frame.style.margin = '0';
1542
- frame.style.position = 'fixed';
1543
- frame.style.top = '0';
1544
- frame.style.left = '0';
1545
- frame.allow = 'autoplay; fullscreen; gamepad';
1504
+ doc.title = "Home - Google Classroom";
1546
1505
 
1506
+ let gameHtml = '';
1547
1507
  try {
1548
1508
  const res = await fetch(`https://raw.githubusercontent.com/gn-math/html/main/${filename}`);
1549
1509
  if (res.ok) {
1550
- let html = await res.text();
1551
- if (html && html.length > 50) {
1552
- html = html.replace(/https?:\/\/cdn\.jsdelivr\.net\/gh\//g, 'https://fastly.jsdelivr.net/gh/');
1553
- html = html.replace(/https?:\/\/cdn\.jsdelivr\.net\/npm\//g, 'https://fastly.jsdelivr.net/npm/');
1554
- frame.srcdoc = html;
1555
- } else {
1556
- frame.src = `https://fastly.jsdelivr.net/gh/gn-math/html@main/${filename}`;
1510
+ gameHtml = await res.text();
1511
+ if (gameHtml && gameHtml.length > 50) {
1512
+ gameHtml = gameHtml.replace(/https?:\/\/cdn\.jsdelivr\.net\/gh\//g, 'https://fastly.jsdelivr.net/gh/');
1513
+ gameHtml = gameHtml.replace(/https?:\/\/cdn\.jsdelivr\.net\/npm\//g, 'https://fastly.jsdelivr.net/npm/');
1557
1514
  }
1558
- } else {
1559
- frame.src = `https://fastly.jsdelivr.net/gh/gn-math/html@main/${filename}`;
1560
1515
  }
1561
- } catch (e) {
1562
- frame.src = `https://fastly.jsdelivr.net/gh/gn-math/html@main/${filename}`;
1516
+ } catch (e) {}
1517
+
1518
+ doc.open();
1519
+ doc.write(`
1520
+ <!DOCTYPE html>
1521
+ <html>
1522
+ <head>
1523
+ <title>Home - Google Classroom</title>
1524
+ <link rel="icon" href="https://ssl.gstatic.com/classroom/favicon.png">
1525
+ <style>
1526
+ * { margin: 0; padding: 0; box-sizing: border-box; }
1527
+ body { background: #000; overflow: hidden; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
1528
+ #game-frame { width: 100vw; height: 100vh; border: none; position: fixed; top: 0; left: 0; z-index: 1; }
1529
+ .reaper-bar {
1530
+ position: fixed; top: 12px; left: 14px; z-index: 9999;
1531
+ display: flex; gap: 8px; align-items: center;
1532
+ background: rgba(3, 8, 18, 0.88); backdrop-filter: blur(8px);
1533
+ border: 1.5px solid rgba(0, 136, 255, 0.4); border-radius: 8px; padding: 6px 12px;
1534
+ box-shadow: 0 4px 20px rgba(0,0,0,0.7);
1535
+ opacity: 0.85; transition: opacity 0.2s ease, border-color 0.2s ease;
1536
+ }
1537
+ .reaper-bar:hover { opacity: 1; border-color: #00d2ff; }
1538
+ .btn-action {
1539
+ background: #041022; color: #00d2ff; border: 1px solid rgba(0, 136, 255, 0.4);
1540
+ padding: 5px 12px; border-radius: 6px; font-size: 11px; font-weight: 800;
1541
+ cursor: pointer; text-decoration: none; display: inline-flex; align-items: center; gap: 4px;
1542
+ transition: all 0.2s ease; font-family: inherit;
1543
+ }
1544
+ .btn-action:hover { background: #0088ff; color: #fff; box-shadow: 0 0 10px rgba(0,136,255,0.6); }
1545
+ .reaper-watermark {
1546
+ position: fixed; bottom: 10px; right: 14px; z-index: 9999;
1547
+ font-family: serif; font-weight: 900; font-size: 13px; letter-spacing: 0.12em;
1548
+ color: rgba(255, 255, 255, 0.35); text-shadow: 0 0 10px rgba(0, 136, 255, 0.6);
1549
+ pointer-events: none; user-select: none;
1550
+ }
1551
+ </style>
1552
+ <script>
1553
+ // Client-Side Ad & Pop-up Blocker
1554
+ window.open = function() { console.log('[REAPER SHIELD] Ad pop-up blocked'); return null; };
1555
+ <\/script>
1556
+ </head>
1557
+ <body>
1558
+ <div class="reaper-bar">
1559
+ <a href="${siteUrl}" class="btn-action" title="Return to Reaper Hub Portal">⚡ BACK TO SITE</a>
1560
+ <button onclick="document.getElementById('game-frame').requestFullscreen()" class="btn-action">⛶ FULLSCREEN</button>
1561
+ <button onclick="document.getElementById('game-frame').contentWindow.location.reload()" class="btn-action">🔄 RELOAD</button>
1562
+ </div>
1563
+ <div class="reaper-watermark">REAPER HUB</div>
1564
+ <iframe id="game-frame" allow="autoplay; fullscreen; gamepad" ${gameHtml ? '' : `src="https://fastly.jsdelivr.net/gh/gn-math/html@main/${filename}"`}></iframe>
1565
+ </body>
1566
+ </html>
1567
+ `);
1568
+ doc.close();
1569
+
1570
+ if (gameHtml) {
1571
+ const f = doc.getElementById('game-frame');
1572
+ if (f) f.srcdoc = gameHtml;
1563
1573
  }
1564
1574
 
1565
- doc.body.style.margin = '0';
1566
- doc.body.style.overflow = 'hidden';
1567
- doc.body.appendChild(frame);
1568
- this.showToast("Game launched in about:blank tab.");
1575
+ this.showToast("Game opened in about:blank tab with watermark & return controls.");
1569
1576
  }
1570
1577
  }
1571
1578
 
1579
+ toggleAutoAboutBlank(enabled) {
1580
+ localStorage.setItem('reaper_auto_about_blank', enabled ? 'true' : 'false');
1581
+ this.showToast(enabled ? "Auto about:blank cloak enabled on every visit." : "Auto about:blank disabled.");
1582
+ }
1583
+
1572
1584
  openSiteAboutBlank() {
1573
1585
  const win = window.open('about:blank', '_blank');
1574
1586
  if (win) {
1575
1587
  const doc = win.document;
1576
- doc.title = "Classes";
1588
+ doc.title = "Home - Google Classroom";
1577
1589
  const link = doc.createElement('link');
1578
1590
  link.rel = 'icon';
1579
1591
  link.href = 'https://ssl.gstatic.com/classroom/favicon.png';
@@ -1977,7 +1989,7 @@ class ReaperHubApp {
1977
1989
  }
1978
1990
 
1979
1991
  switchSettingsTab(tabName) {
1980
- ['shield', 'prefs', 'saves', 'identity'].forEach(t => {
1992
+ ['shield', 'prefs', 'identity'].forEach(t => {
1981
1993
  const btn = document.getElementById(`st-tab-btn-${t}`);
1982
1994
  const content = document.getElementById(`st-content-${t}`);
1983
1995
  if (btn) btn.classList.toggle('active', t === tabName);
@@ -217,6 +217,15 @@
217
217
  count++;
218
218
  }
219
219
  }
220
+
221
+ // Kill client-side third-party ad script injections & tracking pop-up tags
222
+ const adNodes = document.querySelectorAll('script[src*="googlesyndication"], script[src*="doubleclick"], script[src*="adnxs"], script[src*="monetag"], script[src*="popcash"], script[src*="propellerads"], div[class*="ad-banner" i], div[id*="ad-container" i]');
223
+ for (let i = 0; i < adNodes.length; i++) {
224
+ if (adNodes[i] && adNodes[i].parentNode) {
225
+ adNodes[i].parentNode.removeChild(adNodes[i]);
226
+ count++;
227
+ }
228
+ }
220
229
  } catch (e) {}
221
230
 
222
231
  this.blockedCount += count;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reaper-arcade-hub",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Reaper Hub - 788 High-Speed HTML5 Games, Realtime Chat, Playtime Leaderboard & Verification Gateway",
5
5
  "main": "main/index.html",
6
6
  "unpkg": "main/index.html",
@@ -217,6 +217,15 @@
217
217
  count++;
218
218
  }
219
219
  }
220
+
221
+ // Kill client-side third-party ad script injections & tracking pop-up tags
222
+ const adNodes = document.querySelectorAll('script[src*="googlesyndication"], script[src*="doubleclick"], script[src*="adnxs"], script[src*="monetag"], script[src*="popcash"], script[src*="propellerads"], div[class*="ad-banner" i], div[id*="ad-container" i]');
223
+ for (let i = 0; i < adNodes.length; i++) {
224
+ if (adNodes[i] && adNodes[i].parentNode) {
225
+ adNodes[i].parentNode.removeChild(adNodes[i]);
226
+ count++;
227
+ }
228
+ }
220
229
  } catch (e) {}
221
230
 
222
231
  this.blockedCount += count;