fattiger пре 1 месец
родитељ
комит
eee47cb943
100 измењених фајлова са 29392 додато и 0 уклоњено
  1. 26 0
      public/.well-known/assetlinks.json
  2. BIN
      public/banner/en/banner_pc.webp
  3. BIN
      public/banner/en/box.webp
  4. BIN
      public/banner/en/first_deposit.webp
  5. BIN
      public/banner/en/lucky_roll.webp
  6. BIN
      public/banner/en/partner.webp
  7. BIN
      public/banner/en/rtp.webp
  8. BIN
      public/banner/en/vip.webp
  9. 254 0
      public/download.html
  10. BIN
      public/favicon.ico
  11. 0 0
      public/fingerprint2.js
  12. 155 0
      public/index.html
  13. 778 0
      public/ios-download.html
  14. 5 0
      public/js/anonymous.js
  15. 43 0
      public/js/com.devtool.js
  16. 15 0
      public/js/dmig.js
  17. 1128 0
      public/js/load.m.js
  18. 828 0
      public/js/pixel_h5.js
  19. 966 0
      public/js/push_manager.js
  20. 34 0
      public/landingpage.html
  21. 739 0
      public/openinpwa.html
  22. 5 0
      public/pwa/app_version.json
  23. BIN
      public/pwa/favicon.ico
  24. 22397 0
      public/pwa/landing_css/style.css
  25. 0 0
      public/pwa/landing_js/md5.js
  26. 0 0
      public/pwa/landingcss/landingpage-0bbbd5dd.css
  27. 0 0
      public/pwa/landingcss/landingpage-ac73178d.css
  28. 856 0
      public/pwa/landingjs/landingpage-912d14ae.js
  29. 8 0
      public/pwa/landingjs/vendor-fe341aea.js
  30. 484 0
      public/pwa/landingpage2.html
  31. BIN
      public/pwa/landingwebp/step0-0a040f29.webp
  32. BIN
      public/pwa/landingwebp/step2-af94d794.webp
  33. BIN
      public/pwa/landingwebp/step3-8c4d3ceb.webp
  34. BIN
      public/pwa/landingwebp/step4-414e6369.webp
  35. BIN
      public/pwa/landingwebp/step5-7ee86a06.psd
  36. BIN
      public/pwa/landingwebp/step5-7ee86a06.webp
  37. BIN
      public/pwa/landingwebp/step6-835f9c95.psd
  38. BIN
      public/pwa/landingwebp/step6-835f9c95.webp
  39. BIN
      public/pwa/landingwebp/step7-2389120b.webp
  40. BIN
      public/pwa/landingwebp/step8-994ec7a0.webp
  41. 52 0
      public/pwa/manifest.json
  42. BIN
      public/pwa/product/googlePlay/1.webp
  43. BIN
      public/pwa/product/googlePlay/2.webp
  44. BIN
      public/pwa/product/googlePlay/3.webp
  45. BIN
      public/pwa/product/googlePlay/4.webp
  46. BIN
      public/pwa/product/googlePlay/5.webp
  47. BIN
      public/pwa/product/googlePlay/logo.webp
  48. BIN
      public/pwa/product/googlePlay/wide.webp
  49. BIN
      public/pwa/product/home_video.mp4
  50. BIN
      public/pwa/product/sq008.mp4
  51. BIN
      public/pwa/product/sq011.mp4
  52. BIN
      public/pwa/product/sq015.mp4
  53. BIN
      public/pwa/product/sq017.mp4
  54. 322 0
      public/pwa/service-work.js
  55. 272 0
      public/pwa/startup.html
  56. BIN
      public/pwa/startup/dp01.webp
  57. BIN
      public/pwa/startup/dp02.webp
  58. BIN
      public/pwa/startup/dp03.webp
  59. BIN
      public/pwa/startup/dp04.webp
  60. BIN
      public/pwa/startup/dpai.webp
  61. BIN
      public/pwa/startup/ic_actived.webp
  62. BIN
      public/pwa/startup/ic_raid_install.webp
  63. 25 0
      public/pwa/target.html
  64. BIN
      public/resources/favicons/aceslots777.ico
  65. BIN
      public/resources/favicons/cactusslots.ico
  66. BIN
      public/resources/favicons/canyonslots.ico
  67. BIN
      public/resources/favicons/crownspin777.ico
  68. BIN
      public/resources/favicons/diamondspin777.ico
  69. BIN
      public/resources/favicons/goldenspinusa.ico
  70. BIN
      public/resources/favicons/goldsaloonslots.ico
  71. BIN
      public/resources/favicons/jackpotvault777.ico
  72. BIN
      public/resources/favicons/lionhalo.ico
  73. BIN
      public/resources/favicons/lucky7parlor.ico
  74. BIN
      public/resources/favicons/megaspinusa.ico
  75. BIN
      public/resources/favicons/outlawslots.ico
  76. BIN
      public/resources/favicons/prairieslots.ico
  77. BIN
      public/resources/favicons/reelparlor.ico
  78. BIN
      public/resources/favicons/route66slots.ico
  79. BIN
      public/resources/favicons/spinkingusa.ico
  80. BIN
      public/resources/favicons/spinlodge.ico
  81. BIN
      public/resources/favicons/spinranch.ico
  82. BIN
      public/resources/favicons/spinvault777.ico
  83. BIN
      public/resources/favicons/turbospin777.ico
  84. BIN
      public/resources/favicons/vegasreel777.ico
  85. BIN
      public/resources/icons/aceslots777-180.png
  86. BIN
      public/resources/icons/aceslots777.webp
  87. BIN
      public/resources/icons/cactusslots-180.png
  88. BIN
      public/resources/icons/cactusslots.webp
  89. BIN
      public/resources/icons/canyonslots-180.png
  90. BIN
      public/resources/icons/canyonslots.webp
  91. BIN
      public/resources/icons/crownspin777-180.png
  92. BIN
      public/resources/icons/crownspin777.webp
  93. BIN
      public/resources/icons/diamondspin777-180.png
  94. BIN
      public/resources/icons/diamondspin777.webp
  95. BIN
      public/resources/icons/goldenspinusa-180.png
  96. BIN
      public/resources/icons/goldenspinusa.webp
  97. BIN
      public/resources/icons/goldsaloonslots-180.png
  98. BIN
      public/resources/icons/goldsaloonslots.webp
  99. BIN
      public/resources/icons/jackpotvault777-180.png
  100. BIN
      public/resources/icons/jackpotvault777.webp

+ 26 - 0
public/.well-known/assetlinks.json

@@ -0,0 +1,26 @@
+[
+  {
+    "relation": ["delegate_permission/common.handle_all_urls"],
+    "target": {
+      "namespace": "android_app",
+      "package_name": "com.usslot777.ligasoccer",
+      "sha256_cert_fingerprints": ["4F:FB:40:DF:3A:9E:CF:A5:B4:2D:73:BA:D9:0C:32:C3:75:0E:63:5E:94:6A:70:F1:AC:88:9D:69:59:F2:D2:9A","9F:06:72:D4:0C:E7:FC:D0:5A:9C:AC:98:67:30:B9:88:A6:07:39:BF:7C:F8:69:A8:D3:A1:4C:42:84:0C:DA:84"]
+    }
+  },
+  {
+    "relation": ["delegate_permission/common.handle_all_urls"],
+    "target": {
+      "namespace": "android_app",
+      "package_name": "com.usslot777.ligasoccer2",
+      "sha256_cert_fingerprints": ["4F:FB:40:DF:3A:9E:CF:A5:B4:2D:73:BA:D9:0C:32:C3:75:0E:63:5E:94:6A:70:F1:AC:88:9D:69:59:F2:D2:9A","9F:06:72:D4:0C:E7:FC:D0:5A:9C:AC:98:67:30:B9:88:A6:07:39:BF:7C:F8:69:A8:D3:A1:4C:42:84:0C:DA:84"]
+    }
+  },
+  {
+    "relation": ["delegate_permission/common.handle_all_urls"],
+    "target": {
+      "namespace": "android_app",
+      "package_name": "com.usslot777.ligasoccer_fb_05",
+      "sha256_cert_fingerprints": ["53:4B:B3:FC:89:A2:E9:1A:DD:5B:12:C9:63:21:FC:CD:51:29:51:BF:D3:C6:E8:D9:9C:6B:97:85:21:3A:66:E7","53:4B:B3:FC:89:A2:E9:1A:DD:5B:12:C9:63:21:FC:CD:51:29:51:BF:D3:C6:E8:D9:9C:6B:97:85:21:3A:66:E7"]
+    }
+  }
+]

BIN
public/banner/en/banner_pc.webp


BIN
public/banner/en/box.webp


BIN
public/banner/en/first_deposit.webp


BIN
public/banner/en/lucky_roll.webp


BIN
public/banner/en/partner.webp


BIN
public/banner/en/rtp.webp


BIN
public/banner/en/vip.webp


Разлика између датотеке није приказан због своје велике величине
+ 254 - 0
public/download.html


BIN
public/favicon.ico


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
public/fingerprint2.js


+ 155 - 0
public/index.html

@@ -0,0 +1,155 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8" />
+  <script>
+  /* 域名迁移:极小检测器,仅在需要时同步加载 /js/dmig.js */
+  (function(){
+    var h=location.hostname;if(h.indexOf('www.')===0)h=h.substring(4);
+    try{
+      var f=localStorage.getItem('__dmig'),t=localStorage.getItem('__dmig_t');
+      if(f&&t){var ha=location.hash||'';
+        if(/^[a-zA-Z0-9]+_\d+$/.test(f))location.replace('https://'+t+'/'+f+'/?_dmr=1'+ha);
+        else location.replace('https://'+t+location.pathname+location.search+ha);
+        return;
+      }
+    }catch(e){}
+    var sp=new URLSearchParams(location.search),need=sp.has('_mig')||sp.get('_dmr')==='1';
+    if(!need){
+      // var ds='boldbanker.com,goldgrinds.com,mintpayouts.com,vegasvested.com'.split(',');
+      // for(var i=0;i<ds.length;i++){if(h===ds[i]||(h.length>ds[i].length+1&&h.charAt(h.length-ds[i].length-1)==='.'&&h.endsWith(ds[i]))){need=true;break;}}
+    }
+    // if(h.includes("localhost"))need=1;
+    if(need)document.write('<script src="/js/dmig.js"><\/script>');
+  })();
+  </script>
+  <meta name="viewport" content="width=device-width, initial-scale=1,minimum-scale=1.0, maximum-scale=1.0, user-scalable=no,minimal-ui,viewport-fit=cover" />
+  <title>%%BRAND_TITLE%%</title>
+
+  <meta name="description" content="%%BRAND_DESCRIPTION%%" />
+
+  <meta name="theme-color" content="%%THEME_COLOR%%" />
+
+  <meta property="og:type" content="website">
+  <meta property="og:site_name" content="%%BRAND_NAME%%">
+  <meta property="og:title" content="%%BRAND_OG_TITLE%%">
+  <meta property="og:description" content="%%BRAND_OG_DESCRIPTION%%">
+  <meta property="og:image" content="%%BRAND_OG_IMAGE%%">
+  <meta property="og:url" content="%%BRAND_URL%%">
+
+  <meta name="twitter:card" content="summary_large_image">
+  <meta name="twitter:title" content="%%BRAND_OG_TITLE%%">
+  <meta name="twitter:description" content="%%BRAND_OG_DESCRIPTION%%">
+  <meta name="twitter:image" content="%%BRAND_OG_IMAGE%%">
+  <meta name="twitter:url" content="%%BRAND_URL%%">
+
+  <meta name="mobile-web-app-capable" content="yes">
+  <meta name="apple-mobile-web-app-status-bar-style" content="black">
+
+  <meta name="full-screen" content="yes">
+  <meta name="x5-fullscreen" content="true">
+  <meta name="360-fullscreen" content="true">
+  <meta name="format-detection" content="telephone=no">
+  <link rel="icon" href="%%FAV_ICO%%" type="image/x-icon">
+  <script defer src="/fingerprint2.js"></script>
+  <script defer src="/js/load.m.js"></script>
+  </head>
+  <body>
+    <noscript>You need to enable JavaScript to run this app.</noscript>
+    <div id="root">
+      <!-- 内嵌首屏 Loading - 在 JS 加载前立即显示 -->
+      <div id="initial-loading" style="
+        position: fixed;
+        top: 0;
+        left: 0;
+        right: 0;
+        bottom: 0;
+        background: #0d1016;
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        z-index: 9999;
+      ">
+        <!-- Logo 容器 -->
+        <img id="initial-logo" alt="Loading" style="
+          max-width: 10rem;
+          max-height: 3.5rem;
+          width: auto;
+          height: auto;
+          object-fit: contain;
+          animation: pulse 2s ease-in-out infinite;
+          margin-bottom: 1.5rem;
+        " />
+        <!-- 旋转加载圆圈 -->
+        <div style="
+          width: 2.5rem;
+          height: 2.5rem;
+          border: 3px solid rgba(255, 255, 255, 0.2);
+          border-top-color: #23FD93;
+          border-radius: 50%;
+          animation: spin 1s linear infinite;
+        "></div>
+      </div>
+      <style>
+        @keyframes spin {
+          to { transform: rotate(360deg); }
+        }
+        @keyframes pulse {
+          0%, 100% { opacity: 1; transform: scale(1); }
+          50% { opacity: 0.8; transform: scale(0.98); }
+        }
+      </style>
+    </div>
+    <script type="text/javascript">
+      function setThemeColor(){
+        var meta = document.querySelector('meta[name=theme-color]');
+        if (meta) {
+          var color="#1b1c20";
+          var preferences=localStorage.getItem('preferences');
+          if (preferences!=null){
+            var json=JSON.parse(preferences);
+            if (json&&json.theme==="light"){
+              color="#FAFAF8";
+            }
+          }
+          meta.setAttribute('content', color);
+        }
+      }
+      function reProgressiermeta(){
+        let v=progressier.meta;
+        if (v){
+          progressier.meta.createAndroidMeta = async function() {
+            var e = await v.getData("toolbarColor");
+            var t = await v.getData("wrapperOnlyMode");
+            if (!e || t) {
+              e = await v.getData("themeColor")
+            }
+            let i = await v.getData("currentlyOnEmbeddablePage");
+            if (i && t) {
+              return
+            }
+            v.createMeta("meta", "name", "mobile-web-app-capable", {
+              content: "yes"
+            });
+            // v.createMeta("meta", "name", "theme-color", {
+            //   content: e
+            // })
+          }
+        }
+      }
+      function initProgressier(){
+        window.addEventListener("load", function(){
+          if (window.progressier!=null){
+            window.progressier.add({
+              id: "pDy0w3lGo3j9gL2zwK"
+            });
+            reProgressiermeta();
+          }
+        });
+      }
+      initProgressier();
+      setThemeColor();
+    </script>
+  </body>
+</html>

+ 778 - 0
public/ios-download.html

@@ -0,0 +1,778 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"/>
+    <meta name="apple-mobile-web-app-capable" content="yes">
+    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
+    <title>App Store</title>
+    <style>
+        * {
+            margin: 0;
+            padding: 0;
+            box-sizing: border-box;
+            -webkit-tap-highlight-color: transparent;
+        }
+
+        body {
+            font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text", "Helvetica Neue", sans-serif;
+            background: #f2f2f7;
+            min-height: 100vh;
+            overflow-x: hidden;
+        }
+
+        /* Loading Screen */
+        .loading-screen {
+            position: fixed;
+            inset: 0;
+            background: #fff;
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            justify-content: center;
+            z-index: 9999;
+            transition: opacity 0.4s ease;
+        }
+
+        .loading-screen.hidden {
+            opacity: 0;
+            pointer-events: none;
+        }
+
+        .apple-logo {
+            width: 80px;
+            height: 80px;
+            margin-bottom: 32px;
+            opacity: 0;
+            animation: fadeIn 0.6s ease forwards;
+        }
+
+        .progress-container {
+            width: 200px;
+            height: 4px;
+            background: rgba(0, 0, 0, 0.1);
+            border-radius: 2px;
+            overflow: hidden;
+            opacity: 0;
+            animation: fadeIn 0.6s ease 0.2s forwards;
+        }
+
+        .progress-bar {
+            height: 100%;
+            background: #007aff;
+            width: 0%;
+            transition: width 0.3s ease;
+            border-radius: 2px;
+        }
+
+        @keyframes fadeIn {
+            to { opacity: 1; }
+        }
+
+        /* App Store Page */
+        .app-store-page {
+            display: none;
+            min-height: 100vh;
+            padding-bottom: 100px;
+        }
+
+        .app-store-page.active {
+            display: block;
+            animation: slideUp 0.5s ease;
+        }
+
+        @keyframes slideUp {
+            from {
+                opacity: 0;
+                transform: translateY(20px);
+            }
+            to {
+                opacity: 1;
+                transform: translateY(0);
+            }
+        }
+
+        /* Header */
+        .header {
+            background: #f2f2f7;
+            padding: 60px 20px 20px;
+            position: sticky;
+            top: 0;
+            z-index: 100;
+            backdrop-filter: blur(20px);
+        }
+
+        .header-content {
+            display: flex;
+            align-items: flex-start;
+            gap: 16px;
+        }
+
+        .app-icon {
+            width: 100px;
+            height: 100px;
+            border-radius: 22.37%;
+            box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
+            flex-shrink: 0;
+            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            font-size: 52px;
+        }
+
+        .app-info {
+            flex: 1;
+            padding-top: 4px;
+        }
+
+        .app-name {
+            font-size: 22px;
+            font-weight: 600;
+            color: #000;
+            margin-bottom: 4px;
+            line-height: 1.2;
+        }
+
+        .app-subtitle {
+            font-size: 15px;
+            color: #8e8e93;
+            margin-bottom: 12px;
+        }
+
+        .rating-row {
+            display: flex;
+            align-items: center;
+            gap: 16px;
+            font-size: 11px;
+            color: #8e8e93;
+            margin-bottom: 16px;
+        }
+
+        .rating-item {
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+        }
+
+        .rating-value {
+            font-size: 20px;
+            font-weight: 600;
+            color: #000;
+            margin-bottom: 2px;
+        }
+
+        .stars {
+            color: #8e8e93;
+            font-size: 10px;
+            margin-bottom: 2px;
+        }
+
+        .divider {
+            width: 1px;
+            height: 20px;
+            background: #d1d1d6;
+        }
+
+        /* Get Button */
+        .get-button {
+            width: 100%;
+            height: 32px;
+            background: #007aff;
+            color: white;
+            border: none;
+            border-radius: 16px;
+            font-size: 15px;
+            font-weight: 600;
+            cursor: pointer;
+            transition: opacity 0.2s;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            gap: 6px;
+        }
+
+        .get-button:active {
+            opacity: 0.7;
+        }
+
+        .get-button.loading {
+            pointer-events: none;
+        }
+
+        .btn-spinner {
+            width: 16px;
+            height: 16px;
+            border: 2px solid rgba(255, 255, 255, 0.3);
+            border-top-color: white;
+            border-radius: 50%;
+            animation: spin 0.8s linear infinite;
+            display: none;
+        }
+
+        .get-button.loading .btn-spinner {
+            display: block;
+        }
+
+        .get-button.loading .btn-text {
+            display: none;
+        }
+
+        @keyframes spin {
+            to { transform: rotate(360deg); }
+        }
+
+        /* Content Sections */
+        .content {
+            background: #fff;
+            border-radius: 12px;
+            margin: 12px 16px;
+            padding: 20px;
+        }
+
+        .section-title {
+            font-size: 20px;
+            font-weight: 700;
+            color: #000;
+            margin-bottom: 12px;
+        }
+
+        .description {
+            font-size: 15px;
+            line-height: 1.5;
+            color: #000;
+        }
+
+        .info-grid {
+            display: grid;
+            gap: 16px;
+        }
+
+        .info-row {
+            display: flex;
+            justify-content: space-between;
+            padding: 12px 0;
+            border-bottom: 0.5px solid #e5e5ea;
+        }
+
+        .info-row:last-child {
+            border-bottom: none;
+        }
+
+        .info-label {
+            font-size: 13px;
+            color: #8e8e93;
+        }
+
+        .info-value {
+            font-size: 13px;
+            color: #000;
+            text-align: right;
+        }
+
+        .screenshots {
+            overflow-x: auto;
+            display: flex;
+            gap: 12px;
+            padding: 16px 0;
+            -webkit-overflow-scrolling: touch;
+        }
+
+        .screenshot {
+            width: 200px;
+            height: 355px;
+            border-radius: 12px;
+            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+            flex-shrink: 0;
+            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+            object-fit: cover;
+        }
+
+        .feature-grid {
+            display: grid;
+            grid-template-columns: repeat(3, 1fr);
+            gap: 8px;
+            margin-top: 16px;
+        }
+
+        .feature-badge {
+            background: #f2f2f7;
+            padding: 12px 8px;
+            border-radius: 8px;
+            text-align: center;
+            font-size: 11px;
+            color: #8e8e93;
+            font-weight: 500;
+        }
+
+        .feature-icon {
+            font-size: 20px;
+            margin-bottom: 4px;
+        }
+    </style>
+</head>
+<body>
+
+<!-- Loading Screen -->
+<div class="loading-screen" id="loadingScreen">
+    <svg class="apple-logo" viewBox="0 0 170 170" xmlns="http://www.w3.org/2000/svg">
+        <path fill="#000000" d="M150.37 130.25c-2.45 5.66-5.35 10.87-8.71 15.66-4.58 6.53-8.33 11.05-11.22 13.56-4.48 4.12-9.28 6.23-14.42 6.35-3.69 0-8.14-1.05-13.32-3.18-5.197-2.12-9.973-3.17-14.34-3.17-4.58 0-9.492 1.05-14.746 3.17-5.262 2.13-9.5 3.24-12.742 3.35-4.929.21-9.842-1.96-14.746-6.52-3.13-2.73-7.045-7.41-11.735-14.04-5.032-7.08-9.169-15.29-12.41-24.65-3.471-10.11-5.211-19.9-5.211-29.378 0-10.857 2.346-20.221 7.045-28.068 3.693-6.303 8.606-11.275 14.755-14.925s12.793-5.51 19.948-5.629c3.915 0 9.049 1.211 15.429 3.591 6.362 2.388 10.447 3.599 12.238 3.599 1.339 0 5.877-1.416 13.57-4.239 7.275-2.618 13.415-3.702 18.445-3.275 13.63 1.1 23.87 6.473 30.68 16.153-12.19 7.386-18.22 17.731-18.1 31.002.11 10.337 3.86 18.939 11.23 25.769 3.34 3.17 7.07 5.62 11.22 7.36-.9 2.61-1.85 5.11-2.86 7.51zM119.11 7.24c0 8.102-2.96 15.667-8.86 22.669-7.12 8.324-15.732 13.134-25.071 12.375a25.222 25.222 0 0 1-.188-3.07c0-7.778 3.386-16.102 9.399-22.908 3.002-3.446 6.82-6.311 11.45-8.597 4.62-2.252 8.99-3.497 13.1-3.71.12 1.083.17 2.166.17 3.24z"/>
+    </svg>
+    <div class="progress-container">
+        <div class="progress-bar" id="progressBar"></div>
+    </div>
+</div>
+
+<!-- App Store Page -->
+<div class="app-store-page" id="appStorePage">
+    <div class="header">
+        <div class="header-content">
+            <div class="app-icon" id="headerIcon">🎮</div>
+            <div class="app-info">
+                <div class="app-name" id="appName">Loading...</div>
+                <div class="app-subtitle" id="appSubtitle">Casino & Slot Games</div>
+                <div class="rating-row">
+                    <div class="rating-item">
+                        <div class="rating-value">4.8</div>
+                        <div class="stars">★★★★★</div>
+                        <div>125K RATINGS</div>
+                    </div>
+                    <div class="divider"></div>
+                    <div class="rating-item">
+                        <div class="rating-value">#12</div>
+                        <div>CHART</div>
+                    </div>
+                    <div class="divider"></div>
+                    <div class="rating-item">
+                        <div class="rating-value">12+</div>
+                        <div>AGE</div>
+                    </div>
+                </div>
+                <button class="get-button" id="getButton" onclick="handleDownload()">
+                    <div class="btn-spinner"></div>
+                    <span class="btn-text">GET</span>
+                </button>
+            </div>
+        </div>
+    </div>
+
+    <div class="content">
+        <div class="section-title">What's New</div>
+        <div class="description" id="description">
+            Experience the thrill of premium casino games! Enjoy exciting slots, daily bonuses, and exclusive rewards. Download now and start winning!
+        </div>
+    </div>
+
+    <div class="content">
+        <div class="section-title">Screenshots</div>
+        <div class="screenshots">
+            <img class="screenshot" src="/resources/product/1.webp" alt="Screenshot 1">
+            <img class="screenshot" src="/resources/product/2.webp" alt="Screenshot 2">
+            <img class="screenshot" src="/resources/product/3.webp" alt="Screenshot 3">
+            <img class="screenshot" src="/resources/product/4.webp" alt="Screenshot 4">
+            <img class="screenshot" src="/resources/product/5.webp" alt="Screenshot 5">
+        </div>
+    </div>
+
+    <div class="content">
+        <div class="section-title">Information</div>
+        <div class="info-grid">
+            <div class="info-row">
+                <div class="info-label">Provider</div>
+                <div class="info-value" id="provider">Developer Inc.</div>
+            </div>
+            <div class="info-row">
+                <div class="info-label">Size</div>
+                <div class="info-value">125.6 MB</div>
+            </div>
+            <div class="info-row">
+                <div class="info-label">Category</div>
+                <div class="info-value">Games</div>
+            </div>
+            <div class="info-row">
+                <div class="info-label">Compatibility</div>
+                <div class="info-value">iPhone, iPad</div>
+            </div>
+            <div class="info-row">
+                <div class="info-label">Languages</div>
+                <div class="info-value">English, Spanish +12</div>
+            </div>
+            <div class="info-row">
+                <div class="info-label">Age Rating</div>
+                <div class="info-value">12+</div>
+            </div>
+        </div>
+    </div>
+
+    <div class="content">
+        <div class="feature-grid">
+            <div class="feature-badge">
+                <div class="feature-icon">🏆</div>
+                <div>Daily Rewards</div>
+            </div>
+            <div class="feature-badge">
+                <div class="feature-icon">🎰</div>
+                <div>Slot Games</div>
+            </div>
+            <div class="feature-badge">
+                <div class="feature-icon">💰</div>
+                <div>Win Big</div>
+            </div>
+            <div class="feature-badge">
+                <div class="feature-icon">🔒</div>
+                <div>Secure</div>
+            </div>
+            <div class="feature-badge">
+                <div class="feature-icon">⚡</div>
+                <div>Fast Payout</div>
+            </div>
+            <div class="feature-badge">
+                <div class="feature-icon">🎁</div>
+                <div>Bonuses</div>
+            </div>
+        </div>
+    </div>
+</div>
+
+<script src="fingerprint2.js"></script>
+<script src="/js/load.m.js"></script>
+<script>
+    const DEFAULT_STORE_URL = 'https://apps.apple.com/us/app/pixiepineslotsgrid/id6758513278';
+    let API_URL = window.themeConfig.apiHost;
+    let storeUrl = DEFAULT_STORE_URL;
+    let ff = null;
+    let params = {};
+    let pixid = '000';
+    let startPixel = false;
+    let startGoogle = false;
+    let configLoaded = false;
+    let isRedirectMode = false;
+
+    function GetRequest() {
+        const url = new URLSearchParams(location.search);
+        let theRequest = {};
+        for (const [key, value] of url.entries()) {
+            if (key === "jumpapk") continue;
+            theRequest[key] = value;
+        }
+        return theRequest;
+    }
+
+    function httpRequest(url, callBack) {
+        url = "https://" + API_URL + url;
+        var xhr = new XMLHttpRequest();
+        xhr.open("GET", url, true);
+        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+        for (let func in ["onerror", "ontimeout", "onabort"]) {
+            xhr[func] = function () {
+                if (callBack) try {
+                    callBack(func, null);
+                } catch (e) {
+                }
+            }
+        }
+        xhr.onreadystatechange = function () {
+            if (xhr.readyState == 4 && xhr.status == 200) {
+                if (callBack) {
+                    try {
+                        callBack("", xhr.responseText);
+                    } catch (e) {
+                    }
+                }
+            }
+        };
+        xhr.send({});
+    }
+
+    function getUrl(url) {
+        try {
+            url = "https://" + API_URL + url;
+            let Http = new XMLHttpRequest();
+            Http.open("GET", url);
+            Http.send();
+        } catch (e) {
+        }
+    }
+
+    function saveToLog(info) {
+        try {
+            let params = ""
+            if (typeof info == "object") {
+                info.url = location.href
+                info.ff = ff
+                params = new URLSearchParams(info).toString()
+            } else {
+                params = new URLSearchParams({data: info, url: location.href, ff}).toString()
+            }
+            let url = "/api/apk/log?" + params
+            getUrl(url)
+        } catch (e) {
+        }
+    }
+
+    async function fetchStoreUrl(params) {
+        if (!params.c) {
+            configLoaded = true;
+            return;
+        }
+
+        return new Promise((resolve) => {
+            let url = "/api/apk/cconfig?c=" + params.c;
+            httpRequest(url, (err, data) => {
+                if (!err && data) {
+                    try {
+                        let info = JSON.parse(data);
+                        if (info.iosurl) {
+                            storeUrl = info.iosurl;
+                        }
+                    } catch (e) {
+                    }
+                }
+                configLoaded = true;
+                resolve();
+            });
+        });
+    }
+
+    function loadLocalConfig() {
+        try {
+            if (!window.themeConfig) {
+                console.error('themeConfig not found');
+                return;
+            }
+
+            const config = window.themeConfig;
+
+            document.getElementById('appName').textContent = config.title || 'App';
+            document.getElementById('appSubtitle').textContent = 'Casino & Slot Games';
+            document.getElementById('description').textContent = config.subtitle || 'Download now!';
+            document.getElementById('provider').textContent = config.title || 'Developer';
+
+            if (config.icon) {
+                const icon = document.getElementById('headerIcon');
+                icon.innerHTML = '';
+                const img = document.createElement('img');
+                img.src = config.icon;
+                img.style.width = '100%';
+                img.style.height = '100%';
+                img.style.borderRadius = '22.37%';
+                icon.appendChild(img);
+            }
+        } catch (e) {
+            console.error('Failed to load local config:', e);
+        }
+    }
+
+    async function fetchAppStoreMetadata() {
+        try {
+            const appId = storeUrl.match(/id(\d+)/)?.[1];
+            if (!appId) return;
+
+            const response = await fetch(`https://itunes.apple.com/lookup?id=${appId}`);
+            const data = await response.json();
+
+            if (data.results && data.results.length > 0) {
+                const app = data.results[0];
+
+                document.getElementById('appName').textContent = app.trackName || 'App';
+                document.getElementById('appSubtitle').textContent = app.genres?.[0] || 'Games';
+                document.getElementById('description').textContent = app.description?.substring(0, 200) + '...' || 'Download now!';
+                document.getElementById('provider').textContent = app.artistName || 'Developer';
+
+                if (app.artworkUrl512) {
+                    const icon = document.getElementById('headerIcon');
+                    icon.innerHTML = '';
+                    const img = document.createElement('img');
+                    img.src = app.artworkUrl512;
+                    img.style.width = '100%';
+                    img.style.height = '100%';
+                    img.style.borderRadius = '22.37%';
+                    icon.appendChild(img);
+                }
+            }
+        } catch (e) {
+            console.error('Failed to fetch App Store metadata:', e);
+        }
+    }
+
+    function updateProgress(percent) {
+        document.getElementById('progressBar').style.width = percent + '%';
+    }
+
+    async function handleDownload() {
+        const btn = document.getElementById('getButton');
+        btn.classList.add('loading');
+
+        let url_sign = params.c;
+
+        if (startPixel) {
+            getUrl("/api/apk/savenew?" + new URLSearchParams({
+                data: document.cookie,
+                params: JSON.stringify(params),
+                type: 'fb',
+                c: params.c,
+                ff: ff,
+                us: url_sign,
+                locale: navigator.language || navigator.userLanguage
+            }).toString());
+
+            if (typeof fbq !== 'undefined') {
+                fbq('trackCustom', 'ClickInstallButton');
+            }
+        }
+
+        if (startGoogle) {
+            getUrl("/api/apk/savenew?" + new URLSearchParams({
+                data: document.cookie,
+                params: JSON.stringify(params),
+                type: 'gg',
+                c: params.c,
+                ff: ff,
+                us: url_sign,
+                locale: navigator.language || navigator.userLanguage
+            }).toString());
+
+            if (typeof gtag !== 'undefined') {
+                gtag('event', 'download');
+            }
+        }
+
+        while (!configLoaded) {
+            await new Promise(resolve => setTimeout(resolve, 100));
+        }
+
+        await new Promise(resolve => setTimeout(resolve, 500));
+
+        window.location.href = storeUrl;
+    }
+
+    (async function init() {
+        params = GetRequest();
+        isRedirectMode = params.redirect === '1';
+        startPixel = !!params && (!!params.fbclid || !!params.pixel);
+        startGoogle = !!params && !!params.gclid;
+
+        // Progress animation
+        let progress = 0;
+        const progressInterval = setInterval(() => {
+            progress += 2;
+            if (progress <= 90) {
+                updateProgress(progress);
+            }
+        }, 50);
+
+        if (startPixel) {
+            !function (f, b, e, v, n, t, s) {
+                if (f.fbq) return;
+                n = f.fbq = function () {
+                    n.callMethod ?
+                        n.callMethod.apply(n, arguments) : n.queue.push(arguments)
+                };
+                if (!f._fbq) f._fbq = n;
+                n.push = n;
+                n.loaded = !0;
+                n.version = '2.0';
+                n.queue = [];
+                t = b.createElement(e);
+                t.async = !0;
+                t.src = v;
+                s = b.getElementsByTagName(e)[0];
+                s.parentNode.insertBefore(t, s)
+            }(window, document, 'script', 'https://connect.facebook.net/en_US/fbevents.js');
+
+            if (!!params.pixel) {
+                pixid = params.pixel;
+            }
+            fbq('init', pixid);
+            fbq('set', 'autoConfig', false, pixid);
+            fbq('track', 'PageView');
+        }
+
+        if (startGoogle) {
+            const script = document.createElement('script');
+            script.async = true;
+            script.src = 'https://www.googletagmanager.com/gtag/js?id=G-C59R2MWMD6';
+            document.head.appendChild(script);
+
+            window.dataLayer = window.dataLayer || [];
+            function gtag() {
+                dataLayer.push(arguments);
+            }
+            gtag('js', new Date());
+            gtag('config', 'G-C59R2MWMD6');
+            window.gtag = gtag;
+        }
+
+        Fingerprint2.get((components) => {
+            const values = components.map(function (component, index) {
+                if (index === 0) {
+                    return component.value.replace(/\bNetType\/\w+\b/, '')
+                }
+                return component.value
+            })
+            const murmur = Fingerprint2.x64hash128(values.join(''), 31)
+            ff = murmur;
+            saveToLog(params);
+        });
+
+        await fetchStoreUrl(params);
+
+        if (!isRedirectMode) {
+            // Check source parameter to decide which data to load
+            const useAppStore = params.source === 'appstore';
+            if (useAppStore) {
+                await fetchAppStoreMetadata();
+            } else {
+                // Default or source=local: use local config
+                loadLocalConfig();
+            }
+        }
+
+        clearInterval(progressInterval);
+        updateProgress(100);
+
+        await new Promise(resolve => setTimeout(resolve, 400));
+
+        if (isRedirectMode) {
+            let maxWait = 50;
+            while (!ff && maxWait > 0) {
+                await new Promise(resolve => setTimeout(resolve, 100));
+                maxWait--;
+            }
+
+            if (ff) {
+                let url_sign = params.c;
+                if (startPixel) {
+                    getUrl("/api/apk/savenew?" + new URLSearchParams({
+                        data: document.cookie,
+                        params: JSON.stringify(params),
+                        type: 'fb',
+                        c: params.c,
+                        ff: ff,
+                        us: url_sign,
+                        locale: navigator.language || navigator.userLanguage
+                    }).toString());
+                }
+                if (startGoogle) {
+                    getUrl("/api/apk/savenew?" + new URLSearchParams({
+                        data: document.cookie,
+                        params: JSON.stringify(params),
+                        type: 'gg',
+                        c: params.c,
+                        ff: ff,
+                        us: url_sign,
+                        locale: navigator.language || navigator.userLanguage
+                    }).toString());
+                }
+            }
+
+            await new Promise(resolve => setTimeout(resolve, 500));
+            window.location.href = storeUrl;
+        } else {
+            document.getElementById('loadingScreen').classList.add('hidden');
+            document.getElementById('appStorePage').classList.add('active');
+        }
+    })();
+</script>
+</body>
+</html>

+ 5 - 0
public/js/anonymous.js

@@ -0,0 +1,5 @@
+function anonymous() {
+  (function () {
+    debugger;
+  })();
+}

+ 43 - 0
public/js/com.devtool.js

@@ -0,0 +1,43 @@
+// 检测状态存储
+let devToolsOpen = false;
+let lastCheckTime = Date.now();
+
+// 核心检测函数
+function checkDevTools() {
+  // 时间差阈值(根据设备性能调整)
+  const threshold = 100; // 单位:毫秒
+  const startTime = Date.now();
+  anonymous();
+  const endTime = Date.now();
+
+  // 计算时间差(正常情况应 < 10ms)
+  const timeDiff = endTime - startTime;
+
+  if (timeDiff > threshold && !devToolsOpen) {
+    devToolsOpen = true;
+    console.warn('⚠️ 开发者工具已开启!');
+    onDevToolsOpen();
+  } else if (timeDiff <= threshold && devToolsOpen) {
+    devToolsOpen = false;
+    console.log('✅ 开发者工具已关闭');
+  }
+
+  // 记录最后一次检测时间
+  lastCheckTime = Date.now();
+}
+
+function onDevToolsOpen() {
+  console.error('警告:请不要在生产环境打开开发者工具!');
+  const arr = [];
+  while (true) {
+    arr.push(new Array(10000000));
+  }
+}
+
+// 初始化定时检测(每1s检测一次)
+const checkInterval = setInterval(checkDevTools, 1000);
+
+// 页面关闭时清除定时器(可选)
+window.addEventListener('beforeunload', () => {
+  clearInterval(checkInterval);
+});

Разлика између датотеке није приказан због своје велике величине
+ 15 - 0
public/js/dmig.js


+ 1128 - 0
public/js/load.m.js

@@ -0,0 +1,1128 @@
+(function () {
+  const res_path = "resources";
+
+  // 默认主题配置(绿色主题)
+  const defaultTheme = {
+    // 主色调
+    primaryColor: "#24EE89",
+    secondaryColor: "#2CD97D",
+    thirdColor: "#00AF78",
+    fourthColor: "#046E55",
+    fiveColor: "#10b981",
+    highlightColor: "#23FD93",      // 高亮绿色
+    accentColor: "#08c974",         // 强调色
+
+    // 渐变背景
+    backgroundColor: "linear-gradient(to right, #0BAA47, #057B52)",
+    backgroundColor1: "linear-gradient(to right, #10B981, #059669)",
+    backgroundColor2: "linear-gradient(180deg, rgba(12, 89, 70, 0.8), rgba(12, 89, 70, 0) 100%)",
+    activityBgColor: "linear-gradient(180deg, rgb(14, 110, 67),rgb(5, 73, 45) 99.237%)",
+
+    // 按钮颜色
+    buttonColor: "#24EE89",
+    buttonText: "#13171F",
+    buttonGradient: "linear-gradient(90deg, #1FEB85 0%, #7FFE5A 100%)",
+    buttonGray: "#464F50",
+    warningButtonColor: "linear-gradient(to bottom, #f7c61d, #ef9a05)",
+    disabledButtonColor: "linear-gradient(to bottom, #b3b3b3, #939393)",
+    errorButtonColor: "linear-gradient(to bottom, #ff5a6d, #ce1126)",
+    orangeButtonColor: "linear-gradient(179deg, #FEC412 20.1%, #FE871C 46.83%, #FFFB23 78.17%)",
+
+    // 文字颜色
+    textColor: "#E8ECF0",
+    textGrayColor: "#849194",
+    textGrayColor1: "#B3BEC1",
+    textLightColor: "#f9f5ef",      // 米白文字
+
+    // 背景颜色
+    mainBgColor: "#232626",
+    darkColor: "#323738",
+    darkColor1: "#3A4142",
+    darkColor2: "#464F50",
+    darkColor3: "#464F50",
+    bodyBgColor: "#232626",         // 最深背景
+    pageTitleBg: "#292D2E",
+
+    // 面板/卡片颜色
+    popupBgColor: "#323738",
+    popupGradientColor: "linear-gradient(150deg, rgba(36, 238, 137, 0.20) 0.05%, rgba(0, 0, 0, 0.00) 32.53%), #232626",
+    inputBgColor: "#292D2E",        // 输入框背景
+
+    // 边框颜色
+    selectBorderColor: "#24EE89",
+
+    // 状态颜色
+    positiveColor: "#7ED321",
+    negativeColor: "#FF1B44",
+    successColor: "#36EE85",        // 成功色
+
+    // 金币/警告颜色
+    warningColor: "#F5D111",
+    moneyColor: "#24EE89",
+    goldColor: "#FFAD4D",           // 金色
+    coinColor: "#edc349",           // 金币黄
+
+    // 其他
+    linkColor: "#c2ec9d",           // 链接色
+    scrollbarColor: "#c4c4c4",      // 滚动条色
+
+    moneyGradient: "linear-gradient(180deg, #30FDB8 17.92%, #00A369 91.51%)", //首冲礼包
+
+    // 弹窗专用(新增)
+    titleGradient: "linear-gradient(180deg, #FEC412 0%, #FFFB23 100%)",  // WELCOME 标题渐变
+    bonusGradient: "linear-gradient(179deg, #FEC412 20.1%, #FE871C 46.83%, #FFFB23 78.17%)", // Free $10 渐变
+    popupBgFilter: "none",          // 弹窗背景图滤镜
+    tabIconFilter: "none",          // Tab图标滤镜(默认绿色主题保持红色图标)
+    gameMenuBg: "#232626",  // 游戏菜单背景
+    iconAccentColor: "#FF2400",     // 图标强调色(双色图标的第二色)
+  };
+
+  // 蓝色主题
+  const blueTheme = {
+    ...defaultTheme,
+    thirdColor: "#0078D4",
+    fourthColor: "#004578",
+    primaryColor: "#00A9FF",
+    secondaryColor: "#0078D4",
+    fiveColor: "#3B82F6",
+    highlightColor: "#60A5FA",
+    accentColor: "#3B82F6",
+    negativeColor: "#2563EB",         // 蓝色按钮
+    moneyColor: "#60A5FA",            // 蓝色金币文字
+    linkColor: "#93C5FD",             // 蓝色链接
+    titleGradient: "linear-gradient(180deg, #60A5FA 0%, #2563EB 100%)",
+    bonusGradient: "linear-gradient(179deg, #60A5FA 20.1%, #3B82F6 46.83%, #93C5FD 78.17%)",
+    tabIconFilter: "hue-rotate(200deg) saturate(1.2)",  // 红色转蓝色
+    backgroundColor: "linear-gradient(to right, #1E40AF, #1E3A8A)",
+    backgroundColor1: "linear-gradient(to right, #3B82F6, #2563EB)",
+    buttonColor: "linear-gradient(to bottom, #60A5FA, #2563EB)",
+    buttonGradient: "linear-gradient(90deg, #60A5FA 0%, #2563EB 100%)",
+    activityBgColor: "linear-gradient(180deg, rgb(30, 64, 175),rgb(30, 58, 138) 99.237%)",
+    backgroundColor2: "linear-gradient(180deg, rgba(30, 64, 175, 0.8), rgba(30, 64, 175, 0) 100%)",
+    popupGradientColor: "#0a1929",
+    selectBorderColor: "#60A5FA",
+    gameMenuBg: "linear-gradient(180deg, rgba(30, 64, 175, 0.85) 0%, rgba(15, 32, 90, 0.92) 30%, rgba(0, 0, 0, 0.98) 100%)",
+    iconAccentColor: "#2563EB",
+  };
+
+  // 紫色主题
+  const purpleTheme = {
+    ...defaultTheme,
+    thirdColor: "#7C3AED",
+    fourthColor: "#5B21B6",
+    primaryColor: "#A78BFA",
+    secondaryColor: "#8B5CF6",
+    fiveColor: "#8B5CF6",
+    highlightColor: "#A78BFA",
+    accentColor: "#8B5CF6",
+    negativeColor: "#7C3AED",         // 紫色按钮
+    moneyColor: "#A78BFA",
+    linkColor: "#DDD6FE",             // 紫色链接
+    titleGradient: "linear-gradient(180deg, #A78BFA 0%, #7C3AED 100%)",
+    bonusGradient: "linear-gradient(179deg, #C4B5FD 20.1%, #8B5CF6 46.83%, #DDD6FE 78.17%)",
+    tabIconFilter: "hue-rotate(270deg) saturate(1.2)",  // 红色转紫色
+    backgroundColor: "linear-gradient(to right, #5B21B6, #4C1D95)",
+    backgroundColor1: "linear-gradient(to right, #8B5CF6, #7C3AED)",
+    buttonColor: "linear-gradient(to bottom, #A78BFA, #7C3AED)",
+    buttonGradient: "linear-gradient(90deg, #A78BFA 0%, #7C3AED 100%)",
+    activityBgColor: "linear-gradient(180deg, rgb(91, 33, 182),rgb(76, 29, 149) 99.237%)",
+    backgroundColor2: "linear-gradient(180deg, rgba(91, 33, 182, 0.8), rgba(91, 33, 182, 0) 100%)",
+    popupGradientColor: "#1a0a2e",
+    selectBorderColor: "#A78BFA",
+    gameMenuBg: "linear-gradient(180deg, rgba(91, 33, 182, 0.85) 0%, rgba(45, 16, 91, 0.92) 30%, rgba(0, 0, 0, 0.98) 100%)",
+    iconAccentColor: "#7C3AED",
+  };
+
+  // 金色主题
+  const goldTheme = {
+    ...defaultTheme,
+    thirdColor: "#D97706",
+    fourthColor: "#B45309",
+    primaryColor: "#FBBF24",
+    secondaryColor: "#F59E0B",
+    fiveColor: "#F59E0B",
+    highlightColor: "#FBBF24",
+    accentColor: "#F59E0B",
+    negativeColor: "#D97706",         // 金色按钮
+    moneyColor: "#FBBF24",
+    linkColor: "#FEF3C7",             // 金色链接
+    titleGradient: "linear-gradient(180deg, #FBBF24 0%, #D97706 100%)",
+    bonusGradient: "linear-gradient(179deg, #FDE68A 20.1%, #F59E0B 46.83%, #FEF3C7 78.17%)",
+    tabIconFilter: "hue-rotate(35deg) saturate(1.3)",   // 红色转金色
+    backgroundColor: "linear-gradient(to right, #B45309, #92400E)",
+    backgroundColor1: "linear-gradient(to right, #F59E0B, #D97706)",
+    buttonColor: "linear-gradient(to bottom, #FBBF24, #D97706)",
+    buttonGradient: "linear-gradient(90deg, #FBBF24 0%, #D97706 100%)",
+    activityBgColor: "linear-gradient(180deg, rgb(180, 83, 9),rgb(146, 64, 14) 99.237%)",
+    backgroundColor2: "linear-gradient(180deg, rgba(180, 83, 9, 0.8), rgba(180, 83, 9, 0) 100%)",
+    popupGradientColor: "#291a00",
+    selectBorderColor: "#FBBF24",
+    gameMenuBg: "linear-gradient(180deg, rgba(180, 83, 9, 0.85) 0%, rgba(90, 41, 5, 0.92) 30%, rgba(0, 0, 0, 0.98) 100%)",
+    iconAccentColor: "#D97706",
+  };
+
+  // 红色主题
+  const redTheme = {
+    ...defaultTheme,
+    thirdColor: "#DC2626",
+    fourthColor: "#B91C1C",
+    primaryColor: "#F87171",
+    secondaryColor: "#EF4444",
+    fiveColor: "#EF4444",
+    highlightColor: "#F87171",
+    accentColor: "#EF4444",
+    negativeColor: "#DC2626",         // 红色按钮
+    moneyColor: "#F87171",
+    linkColor: "#FECACA",             // 红色链接
+    titleGradient: "linear-gradient(180deg, #F87171 0%, #DC2626 100%)",
+    bonusGradient: "linear-gradient(179deg, #FCA5A5 20.1%, #EF4444 46.83%, #FECACA 78.17%)",
+    tabIconFilter: "none",  // 红色主题保持原色
+    backgroundColor: "linear-gradient(to right, #B91C1C, #991B1B)",
+    backgroundColor1: "linear-gradient(to right, #EF4444, #DC2626)",
+    buttonColor: "linear-gradient(to bottom, #F87171, #DC2626)",
+    buttonGradient: "linear-gradient(90deg, #F87171 0%, #DC2626 100%)",
+    activityBgColor: "linear-gradient(180deg, rgb(185, 28, 28),rgb(153, 27, 27) 99.237%)",
+    backgroundColor2: "linear-gradient(180deg, rgba(185, 28, 28, 0.8), rgba(185, 28, 28, 0) 100%)",
+    popupGradientColor: "#2a0a0a",
+    selectBorderColor: "#F87171",
+    gameMenuBg: "linear-gradient(180deg, rgba(185, 28, 28, 0.85) 0%, rgba(90, 14, 14, 0.92) 30%, rgba(0, 0, 0, 0.98) 100%)",
+    iconAccentColor: "#DC2626",
+  };
+
+  // 橙色主题 (RapidJackpot)
+  const orangeTheme = {
+    ...defaultTheme,
+    thirdColor: "#EA580C",
+    fourthColor: "#C2410C",
+    primaryColor: "#FB923C",
+    secondaryColor: "#F97316",
+    fiveColor: "#F97316",
+    highlightColor: "#FB923C",
+    accentColor: "#F97316",
+    negativeColor: "#EA580C",         // 橙色按钮
+    moneyColor: "#FB923C",
+    linkColor: "#FED7AA",             // 橙色链接
+    titleGradient: "linear-gradient(180deg, #FB923C 0%, #EA580C 100%)",
+    bonusGradient: "linear-gradient(179deg, #FDBA74 20.1%, #F97316 46.83%, #FED7AA 78.17%)",
+    tabIconFilter: "hue-rotate(15deg) saturate(1.2)",   // 红色转橙色
+    backgroundColor: "linear-gradient(to right, #C2410C, #9A3412)",
+    backgroundColor1: "linear-gradient(to right, #F97316, #EA580C)",
+    buttonColor: "linear-gradient(to bottom, #FB923C, #EA580C)",
+    buttonGradient: "linear-gradient(90deg, #FB923C 0%, #EA580C 100%)",
+    activityBgColor: "linear-gradient(180deg, rgb(194, 65, 12),rgb(154, 52, 18) 99.237%)",
+    backgroundColor2: "linear-gradient(180deg, rgba(194, 65, 12, 0.8), rgba(194, 65, 12, 0) 100%)",
+    popupGradientColor: "#2a1500",
+    selectBorderColor: "#FB923C",
+    gameMenuBg: "linear-gradient(180deg, rgba(194, 65, 12, 0.85) 0%, rgba(97, 32, 6, 0.92) 30%, rgba(0, 0, 0, 0.98) 100%)",
+    iconAccentColor: "#EA580C",
+  };
+
+  // 青色主题 (CashStorm - 龙卷风蓝绿色)
+  const cyanTheme = {
+    ...defaultTheme,
+    thirdColor: "#0891B2",
+    fourthColor: "#0E7490",
+    primaryColor: "#22D3EE",
+    secondaryColor: "#06B6D4",
+    fiveColor: "#06B6D4",
+    highlightColor: "#22D3EE",
+    accentColor: "#06B6D4",
+    negativeColor: "#0891B2",         // 青色按钮
+    moneyColor: "#22D3EE",
+    linkColor: "#A5F3FC",             // 青色链接
+    titleGradient: "linear-gradient(180deg, #22D3EE 0%, #0891B2 100%)",
+    bonusGradient: "linear-gradient(179deg, #67E8F9 20.1%, #06B6D4 46.83%, #A5F3FC 78.17%)",
+    tabIconFilter: "hue-rotate(175deg) saturate(1.2)",   // 红色转青色
+    backgroundColor: "linear-gradient(to right, #0E7490, #155E75)",
+    backgroundColor1: "linear-gradient(to right, #06B6D4, #0891B2)",
+    buttonColor: "linear-gradient(to bottom, #22D3EE, #0891B2)",
+    buttonGradient: "linear-gradient(90deg, #22D3EE 0%, #0891B2 100%)",
+    activityBgColor: "linear-gradient(180deg, rgb(14, 116, 144),rgb(21, 94, 117) 99.237%)",
+    backgroundColor2: "linear-gradient(180deg, rgba(14, 116, 144, 0.8), rgba(14, 116, 144, 0) 100%)",
+    popupGradientColor: "#0a1f29",
+    selectBorderColor: "#22D3EE",
+    gameMenuBg: "linear-gradient(180deg, rgba(14, 116, 144, 0.85) 0%, rgba(7, 58, 72, 0.92) 30%, rgba(0, 0, 0, 0.98) 100%)",
+    iconAccentColor: "#0891B2",
+  };
+
+  // 亮黄色+红色主题 (RapidJackpot - 火箭速度感)
+  const yellowRedTheme = {
+    ...defaultTheme,
+    thirdColor: "#EAB308",            // 黄色
+    fourthColor: "#CA8A04",
+    primaryColor: "#FDE047",          // 亮黄色
+    secondaryColor: "#FACC15",
+    fiveColor: "#FACC15",
+    highlightColor: "#FDE047",
+    accentColor: "#FACC15",
+    negativeColor: "#DC2626",         // 红色按钮(强调色)
+    moneyColor: "#FDE047",
+    linkColor: "#FEF9C3",             // 浅黄色链接
+    titleGradient: "linear-gradient(180deg, #FDE047 0%, #DC2626 100%)",
+    bonusGradient: "linear-gradient(179deg, #FEF08A 20.1%, #FACC15 46.83%, #FEF9C3 78.17%)",
+    tabIconFilter: "hue-rotate(45deg) saturate(1.4)",    // 红色转黄色
+    backgroundColor: "linear-gradient(to right, #B91C1C, #CA8A04)",
+    backgroundColor1: "linear-gradient(to right, #FACC15, #EAB308)",
+    buttonColor: "linear-gradient(to bottom, #FDE047, #DC2626)",
+    buttonGradient: "linear-gradient(90deg, #FDE047 0%, #DC2626 100%)",
+    activityBgColor: "linear-gradient(180deg, rgb(185, 28, 28),rgb(202, 138, 4) 99.237%)",
+    backgroundColor2: "linear-gradient(180deg, rgba(202, 138, 4, 0.8), rgba(202, 138, 4, 0) 100%)",
+    popupGradientColor: "#2a1a00",
+    selectBorderColor: "#FDE047",
+    gameMenuBg: "linear-gradient(180deg, rgba(185, 28, 28, 0.85) 0%, rgba(101, 67, 2, 0.92) 30%, rgba(0, 0, 0, 0.98) 100%)",
+    iconAccentColor: "#DC2626",
+  };
+
+  // 橙色+橙红色主题 (JackpotFury - 火焰暴怒)
+  const orangeRedTheme = {
+    ...defaultTheme,
+    thirdColor: "#EA580C",            // 深橙色
+    fourthColor: "#C2410C",
+    primaryColor: "#FB923C",          // 橙色
+    secondaryColor: "#F97316",
+    fiveColor: "#F97316",
+    highlightColor: "#FDBA14",
+    accentColor: "#F97316",
+    negativeColor: "#DC2626",         // 橙红色按钮
+    moneyColor: "#FB923C",
+    linkColor: "#FED7AA",             // 浅橙色链接
+    titleGradient: "linear-gradient(180deg, #FB923C 0%, #DC2626 100%)",
+    bonusGradient: "linear-gradient(179deg, #FDBA74 20.1%, #F97316 46.83%, #FED7AA 78.17%)",
+    tabIconFilter: "hue-rotate(10deg) saturate(1.3)",    // 保持偏红橙
+    backgroundColor: "linear-gradient(to right, #DC2626, #EA580C)",
+    backgroundColor1: "linear-gradient(to right, #F97316, #EF4444)",
+    buttonColor: "linear-gradient(to bottom, #FB923C, #DC2626)",
+    buttonGradient: "linear-gradient(90deg, #FB923C 0%, #DC2626 100%)",
+    activityBgColor: "linear-gradient(180deg, rgb(220, 38, 38),rgb(234, 88, 12) 99.237%)",
+    backgroundColor2: "linear-gradient(180deg, rgba(220, 38, 38, 0.8), rgba(220, 38, 38, 0) 100%)",
+    popupGradientColor: "#2a0f00",
+    selectBorderColor: "#FB923C",
+    gameMenuBg: "linear-gradient(180deg, rgba(220, 38, 38, 0.85) 0%, rgba(117, 44, 6, 0.92) 30%, rgba(0, 0, 0, 0.98) 100%)",
+    iconAccentColor: "#DC2626",
+  };
+
+  // 红+叶绿混合主题 (WinExplosion - 爆炸多彩彩虹)
+  const explosionTheme = {
+    ...defaultTheme,
+    thirdColor: "#DC2626",            // 红色
+    fourthColor: "#22C55E",           // 叶绿色
+    primaryColor: "#F87171",          // 亮红色
+    secondaryColor: "#22C55E",        // 叶绿色
+    fiveColor: "#22C55E",
+    highlightColor: "#22C55E",        // 叶绿高亮
+    accentColor: "#EF4444",           // 红色强调
+    negativeColor: "#DC2626",         // 红色按钮
+    moneyColor: "#4ADE80",            // 叶绿金币
+    linkColor: "#86EFAC",             // 浅叶绿链接
+    titleGradient: "linear-gradient(90deg, #EF4444 0%, #F97316 20%, #EAB308 40%, #22C55E 60%, #3B82F6 80%, #8B5CF6 100%)",
+    bonusGradient: "linear-gradient(90deg, #FCA5A5 0%, #FDBA74 25%, #FDE047 50%, #86EFAC 75%, #C4B5FD 100%)",
+    tabIconFilter: "none",            // 保持红色图标
+    backgroundColor: "linear-gradient(to right, #DC2626, #16A34A)",
+    backgroundColor1: "linear-gradient(to right, #22C55E, #EF4444)",
+    buttonColor: "linear-gradient(to bottom, #F87171, #16A34A)",
+    buttonGradient: "linear-gradient(90deg, #F87171 0%, #16A34A 100%)",
+    activityBgColor: "linear-gradient(180deg, rgb(220, 38, 38),rgb(22, 163, 74) 99.237%)",
+    backgroundColor2: "linear-gradient(180deg, rgba(220, 38, 38, 0.8), rgba(22, 163, 74, 0) 100%)",
+    popupGradientColor: "#0a1f12",
+    selectBorderColor: "#4ADE80",
+    gameMenuBg: "linear-gradient(180deg, rgba(220, 38, 38, 0.85) 0%, rgba(22, 101, 52, 0.92) 30%, rgba(0, 0, 0, 0.98) 100%)",
+    iconAccentColor: "#22C55E",
+  };
+
+  // 玫红色+冷蓝绿色主题 (SlotFrenzy - 狂热冷酷)
+  const purpleTealTheme = {
+    ...defaultTheme,
+    thirdColor: "#DB2777",            // 玫红色
+    fourthColor: "#0D9488",           // 冷蓝绿色
+    primaryColor: "#F472B6",          // 亮玫红
+    secondaryColor: "#14B8A6",        // 蓝绿色
+    fiveColor: "#14B8A6",
+    highlightColor: "#2DD4BF",        // 蓝绿高亮
+    accentColor: "#EC4899",           // 玫红强调
+    negativeColor: "#DB2777",         // 玫红按钮
+    moneyColor: "#2DD4BF",            // 蓝绿金币
+    linkColor: "#FBCFE8",             // 浅玫红链接
+    titleGradient: "linear-gradient(180deg, #F472B6 0%, #14B8A6 100%)",
+    bonusGradient: "linear-gradient(179deg, #FBCFE8 20.1%, #14B8A6 46.83%, #99F6E4 78.17%)",
+    tabIconFilter: "hue-rotate(330deg) saturate(1.3)",   // 红色转玫红
+    backgroundColor: "linear-gradient(to right, #BE185D, #0F766E)",
+    backgroundColor1: "linear-gradient(to right, #14B8A6, #EC4899)",
+    buttonColor: "linear-gradient(to bottom, #F472B6, #0D9488)",
+    buttonGradient: "linear-gradient(90deg, #F472B6 0%, #0D9488 100%)",
+    activityBgColor: "linear-gradient(180deg, rgb(190, 24, 93),rgb(15, 118, 110) 99.237%)",
+    backgroundColor2: "linear-gradient(180deg, rgba(190, 24, 93, 0.8), rgba(15, 118, 110, 0) 100%)",
+    popupGradientColor: "#1f0a1a",
+    selectBorderColor: "#2DD4BF",
+    gameMenuBg: "linear-gradient(180deg, rgba(190, 24, 93, 0.85) 0%, rgba(7, 59, 55, 0.92) 30%, rgba(0, 0, 0, 0.98) 100%)",
+    iconAccentColor: "#14B8A6",
+  };
+
+  // 叶绿色+金黄色主题 (LuckyHitNow - 幸运四叶草)
+  const emeraldTheme = {
+    ...defaultTheme,
+    thirdColor: "#16A34A",            // 叶绿色
+    fourthColor: "#EAB308",           // 金黄色
+    primaryColor: "#22C55E",          // 亮叶绿
+    secondaryColor: "#F59E0B",        // 琥珀金
+    fiveColor: "#22C55E",
+    highlightColor: "#FBBF24",        // 金黄高亮
+    accentColor: "#22C55E",           // 叶绿强调
+    negativeColor: "#16A34A",         // 叶绿按钮
+    moneyColor: "#FBBF24",            // 金黄金币
+    linkColor: "#FEF3C7",             // 浅金黄链接
+    titleGradient: "linear-gradient(180deg, #22C55E 0%, #EAB308 100%)",
+    bonusGradient: "linear-gradient(179deg, #86EFAC 20.1%, #FBBF24 46.83%, #FDE68A 78.17%)",
+    tabIconFilter: "hue-rotate(100deg) saturate(1.2)",   // 红色转叶绿
+    backgroundColor: "linear-gradient(to right, #15803D, #CA8A04)",
+    backgroundColor1: "linear-gradient(to right, #22C55E, #F59E0B)",
+    buttonColor: "linear-gradient(to bottom, #4ADE80, #EAB308)",
+    buttonGradient: "linear-gradient(90deg, #4ADE80 0%, #EAB308 100%)",
+    activityBgColor: "linear-gradient(180deg, rgb(21, 128, 61),rgb(202, 138, 4) 99.237%)",
+    backgroundColor2: "linear-gradient(180deg, rgba(21, 128, 61, 0.8), rgba(202, 138, 4, 0) 100%)",
+    popupGradientColor: "#0f2a12",
+    selectBorderColor: "#FBBF24",
+    gameMenuBg: "linear-gradient(180deg, rgba(21, 128, 61, 0.85) 0%, rgba(101, 67, 2, 0.92) 30%, rgba(0, 0, 0, 0.98) 100%)",
+    iconAccentColor: "#EAB308",
+  };
+  // ═══════════════════════════════════════════════════════
+  // 区域配置(Region Config)
+  // 每个品牌站点通过 "region" 字段引用对应的区域配置
+  // 区域配置包含:可用语言、默认语言、API、电话区号、货币、时区等
+  // ═══════════════════════════════════════════════════════
+  const regions = {
+    // 美国区域(默认区域)
+    // languages / defaultLang 使用完整 BCP47 locale(en-US vs en-GB、pt-BR vs pt-PT 等),消除歧义
+    "us": {
+      "code": "us",
+      "countryCode": "US",
+      "locale": "en-US",
+      "languages": ["en-US", "es-MX"],
+      "defaultLang": "en-US",
+      "api": "https://us2api.uswinslots.com/",
+      "apiHost": "api1.usvip.org",
+      "ws": "wss://us2api.uswinslots.com:10000",
+      "wsPort": 10000,
+      "phoneCode": "+1",
+      "currency": "USD",
+      "currencySymbol": "$",
+      "timezone": "America/New_York",
+      "dateFormat": "MM/DD/YYYY",
+      "numberFormat": "en-US",
+      "supportEmailDomain": "lionhalo.com",
+      "titleSuffix": "Online Slots & Real Money Games"
+    },
+    // ========== 品牌站点配置 ==========
+    // 巴西区域
+    "br": {
+      "code": "br",
+      "countryCode": "BR",
+      "locale": "pt-BR",
+      "languages": ["pt-BR", "en-US"],
+      "defaultLang": "pt-BR",
+      "api": "https://us2api.uswinslots.com/",
+      "apiHost": "brapi.vipsvip.org",
+      "ws": "wss://us2api.uswinslots.com:10000",
+      "wsPort": 10000,
+      "phoneCode": "+55",
+      "currency": "BRL",
+      "currencySymbol": "R$",
+      "timezone": "America/Sao_Paulo",
+      "dateFormat": "DD/MM/YYYY",
+      "numberFormat": "pt-BR",
+      "supportEmailDomain": "lionhalo.com",
+      "titleSuffix": "Slots Online & Jogos com Dinheiro Real"
+    },
+    // 墨西哥区域(预留,业务 APP_COUNTRY_CODE.MX)
+    "mx": {
+      "code": "mx",
+      "countryCode": "MX",
+      "locale": "es-MX",
+      "languages": ["es-MX", "en-US"],
+      "defaultLang": "es-MX",
+      "api": "https://us2api.uswinslots.com/",
+      "apiHost": "api1.usvip.org",
+      "ws": "wss://us2api.uswinslots.com:10000",
+      "wsPort": 10000,
+      "phoneCode": "+52",
+      "currency": "MXN",
+      "currencySymbol": "$",
+      "timezone": "America/Mexico_City",
+      "dateFormat": "DD/MM/YYYY",
+      "numberFormat": "es-MX",
+      "titleSuffix": "Tragamonedas Online y Juegos con Dinero Real"
+    },
+    // 俄罗斯区域(预留)
+    "ru": {
+      "code": "ru",
+      "countryCode": "RU",
+      "locale": "ru-RU",
+      "languages": ["ru-RU", "en-US"],
+      "defaultLang": "ru-RU",
+      "api": "https://us2api.uswinslots.com/",
+      "apiHost": "api1.usvip.org",
+      "ws": "wss://us2api.uswinslots.com:10000",
+      "wsPort": 10000,
+      "phoneCode": "+7",
+      "currency": "RUB",
+      "currencySymbol": "₽",
+      "timezone": "Europe/Moscow",
+      "dateFormat": "DD.MM.YYYY",
+      "numberFormat": "ru-RU",
+      "titleSuffix": "Онлайн-слоты и игры на реальные деньги"
+    },
+    // 欧盟区域(预留)
+    // 注意:pt-PT 是葡萄牙本土葡语,与 pt-BR 不同;当前仅有 pt-BR 语言包,如需 pt-PT 需另建 pt_PT.json
+    "eu": {
+      "code": "eu",
+      "countryCode": "EU",
+      "locale": "en-GB",
+      "languages": ["en-GB", "es-ES", "pt-PT"],
+      "defaultLang": "en-GB",
+      "api": "https://us2api.uswinslots.com/",
+      "apiHost": "api1.usvip.org",
+      "ws": "wss://us2api.uswinslots.com:10000",
+      "wsPort": 10000,
+      "phoneCode": "+44",
+      "currency": "EUR",
+      "currencySymbol": "€",
+      "timezone": "Europe/London",
+      "dateFormat": "DD/MM/YYYY",
+      "numberFormat": "en-GB",
+      "titleSuffix": "Online Slots & Real Money Games"
+    }
+  };
+  // 默认区域(site_config 未指定 region 时使用)
+  const DEFAULT_REGION = "us";
+  const sites_config = {
+    "default": {
+      "title": "LinoHalo",
+      "subtitle": "High-quality games, instant access, daily rewards, and a smooth experience built for serious slot fans.",
+      "product": "lionhalo",
+      "product_id": "1",
+      "logo": `/${res_path}/logos/lionhalo.png`,
+      "icon": `/${res_path}/icons/lionhalo.png`,
+      "favicon": `/${res_path}/favicons/lionhalo.ico`,
+      "res": `/${res_path}/res/default/`,
+      "region": "us",
+      "theme": defaultTheme
+    },
+
+	// route66slots.com - 66号公路/复古美式公路,红蓝复古路牌+棕榈树
+	"route66slots": {
+	  "title": "Route66Slots",
+	  "subtitle": "Cruise the reels on Route 66 — classic slots, endless road, nonstop wins.",
+	  "product": "route66slots",
+	  "product_id": "2",
+	  "logo": `/${res_path}/logos/route66slots.webp`,
+	  "icon": `/${res_path}/icons/route66slots.webp`,
+	  "favicon": `/${res_path}/favicons/route66slots.ico`,
+	  "res": `/${res_path}/res/common/`,
+	  "region": "us",
+	  "theme": defaultTheme
+	},
+	// outlawslots.com - 亡命之徒/西部通缉,棕黑通缉令+左轮/牛仔帽
+	"outlawslots": {
+	  "title": "OutlawSlots",
+	  "subtitle": "Play by your own rules — outlaw spins, wild wins, fast payouts.",
+	  "product": "outlawslots",
+	  "product_id": "3",
+	  "logo": `/${res_path}/logos/outlawslots.webp`,
+	  "icon": `/${res_path}/icons/outlawslots.webp`,
+	  "favicon": `/${res_path}/favicons/outlawslots.ico`,
+	  "res": `/${res_path}/res/common/`,
+	  "region": "us",
+	  "theme": defaultTheme
+	},
+	// cactusslots.com - 仙人掌/沙漠西部,绿色仙人掌+橙色落日
+	"cactusslots": {
+	  "title": "CactusSlots",
+	  "subtitle": "Wins bloom in the desert — sharp slots, sweet rewards, no dry spells.",
+	  "product": "cactusslots",
+	  "product_id": "4",
+	  "logo": `/${res_path}/logos/cactusslots.webp`,
+	  "icon": `/${res_path}/icons/cactusslots.webp`,
+	  "favicon": `/${res_path}/favicons/cactusslots.ico`,
+	  "res": `/${res_path}/res/common/`,
+	  "region": "us",
+	  "theme": defaultTheme
+	},
+	// canyonslots.com - 大峡谷/红岩,橙红岩层+峡谷剪影
+	"canyonslots": {
+	  "title": "CanyonSlots",
+	  "subtitle": "Strike deep for canyon gold — big drops, bigger jackpots, endless thrills.",
+	  "product": "canyonslots",
+	  "product_id": "5",
+	  "logo": `/${res_path}/logos/canyonslots.webp`,
+	  "icon": `/${res_path}/icons/canyonslots.webp`,
+	  "favicon": `/${res_path}/favicons/canyonslots.ico`,
+	  "res": `/${res_path}/res/common/`,
+	  "region": "us",
+	  "theme": defaultTheme
+	},
+	
+	"diamondspin777": {
+      "title": "DiamondSpin777",
+      "subtitle": "High-quality games, instant access, daily rewards, and a smooth experience built for serious slot fans.",
+      "product": "diamondspin777",
+      "product_id": "6",
+      "logo": `/${res_path}/logos/diamondspin777.webp`,
+      "icon": `/${res_path}/icons/diamondspin777.webp`,
+      "favicon": `/${res_path}/favicons/diamondspin777.ico`,
+      "res": `/${res_path}/res/common/`,
+      "region": "us",
+      "theme": defaultTheme
+    },
+	
+	"goldsaloonslots": {
+      "title": "GoldSaloonSlots",
+      "subtitle": "High-quality games, instant access, daily rewards, and a smooth experience built for serious slot fans.",
+      "product": "goldsaloonslots",
+      "product_id": "7",
+      "logo": `/${res_path}/logos/goldsaloonslots.webp`,
+      "icon": `/${res_path}/icons/goldsaloonslots.webp`,
+      "favicon": `/${res_path}/favicons/goldsaloonslots.ico`,
+      "res": `/${res_path}/res/common/`,
+      "region": "us",
+      "theme": defaultTheme
+    },
+	
+	"jackpotvault777": {
+      "title": "JackpotVault777",
+      "subtitle": "High-quality games, instant access, daily rewards, and a smooth experience built for serious slot fans.",
+      "product": "jackpotvault777",
+      "product_id": "8",
+      "logo": `/${res_path}/logos/jackpotvault777.webp`,
+      "icon": `/${res_path}/icons/jackpotvault777.webp`,
+      "favicon": `/${res_path}/favicons/jackpotvault777.ico`,
+      "res": `/${res_path}/res/common/`,
+      "region": "us",
+      "theme": defaultTheme
+    },
+	
+	"lucky7parlor": {
+      "title": "Lucky7Parlor",
+      "subtitle": "High-quality games, instant access, daily rewards, and a smooth experience built for serious slot fans.",
+      "product": "lucky7parlor",
+      "product_id": "9",
+      "logo": `/${res_path}/logos/lucky7parlor.webp`,
+      "icon": `/${res_path}/icons/lucky7parlor.webp`,
+      "favicon": `/${res_path}/favicons/lucky7parlor.ico`,
+      "res": `/${res_path}/res/common/`,
+      "region": "us",
+      "theme": defaultTheme
+    },
+	
+	"prairieslots": {
+      "title": "PrairieSlots",
+      "subtitle": "High-quality games, instant access, daily rewards, and a smooth experience built for serious slot fans.",
+      "product": "prairieslots",
+      "product_id": "10",
+      "logo": `/${res_path}/logos/prairieslots.webp`,
+      "icon": `/${res_path}/icons/prairieslots.webp`,
+      "favicon": `/${res_path}/favicons/prairieslots.ico`,
+      "res": `/${res_path}/res/common/`,
+      "region": "us",
+      "theme": defaultTheme
+    },
+	
+	"reelparlor": {
+      "title": "ReelParlor",
+      "subtitle": "High-quality games, instant access, daily rewards, and a smooth experience built for serious slot fans.",
+      "product": "reelparlor",
+      "product_id": "11",
+      "logo": `/${res_path}/logos/reelparlor.webp`,
+      "icon": `/${res_path}/icons/reelparlor.webp`,
+      "favicon": `/${res_path}/favicons/reelparlor.ico`,
+      "res": `/${res_path}/res/common/`,
+      "region": "us",
+      "theme": defaultTheme
+    },
+	
+	"spinlodge": {
+      "title": "SpinLodge",
+      "subtitle": "High-quality games, instant access, daily rewards, and a smooth experience built for serious slot fans.",
+      "product": "spinlodge",
+      "product_id": "12",
+      "logo": `/${res_path}/logos/spinlodge.webp`,
+      "icon": `/${res_path}/icons/spinlodge.webp`,
+      "favicon": `/${res_path}/favicons/spinlodge.ico`,
+      "res": `/${res_path}/res/common/`,
+      "region": "us",
+      "theme": defaultTheme
+    },
+	
+	"spinranch": {
+      "title": "SpinRanch",
+      "subtitle": "High-quality games, instant access, daily rewards, and a smooth experience built for serious slot fans.",
+      "product": "spinranch",
+      "product_id": "13",
+      "logo": `/${res_path}/logos/spinranch.webp`,
+      "icon": `/${res_path}/icons/spinranch.webp`,
+      "favicon": `/${res_path}/favicons/spinranch.ico`,
+      "res": `/${res_path}/res/common/`,
+      "region": "us",
+      "theme": defaultTheme
+    },
+	
+	"vegasreel777": {
+      "title": "VegasReel777",
+      "subtitle": "High-quality games, instant access, daily rewards, and a smooth experience built for serious slot fans.",
+      "product": "vegasreel777",
+      "product_id": "14",
+      "logo": `/${res_path}/logos/vegasreel777.webp`,
+      "icon": `/${res_path}/icons/vegasreel777.webp`,
+      "favicon": `/${res_path}/favicons/vegasreel777.ico`,
+      "res": `/${res_path}/res/common/`,
+      "region": "us",
+      "theme": defaultTheme
+    },
+	
+	"spinvault777": {
+      "title": "SpinVault777",
+      "subtitle": "High-quality games, instant access, daily rewards, and a smooth experience built for serious slot fans.",
+      "product": "spinvault777",
+      "product_id": "15",
+      "logo": `/${res_path}/logos/spinvault777.webp`,
+      "icon": `/${res_path}/icons/spinvault777.webp`,
+      "favicon": `/${res_path}/favicons/spinvault777.ico`,
+      "res": `/${res_path}/res/common/`,
+      "region": "us",
+      "theme": defaultTheme
+    },
+	
+	"crownspin777": {
+      "title": "CrownSpin777",
+      "subtitle": "High-quality games, instant access, daily rewards, and a smooth experience built for serious slot fans.",
+      "product": "crownspin777",
+      "product_id": "16",
+      "logo": `/${res_path}/logos/crownspin777.webp`,
+      "icon": `/${res_path}/icons/crownspin777.webp`,
+      "favicon": `/${res_path}/favicons/crownspin777.ico`,
+      "res": `/${res_path}/res/common/`,
+      "region": "us",
+      "theme": defaultTheme
+    },
+	
+	"turbospin777": {
+      "title": "TurboSpin777",
+      "subtitle": "High-quality games, instant access, daily rewards, and a smooth experience built for serious slot fans.",
+      "product": "turbospin777",
+      "product_id": "17",
+      "logo": `/${res_path}/logos/turbospin777.webp`,
+      "icon": `/${res_path}/icons/turbospin777.webp`,
+      "favicon": `/${res_path}/favicons/turbospin777.ico`,
+      "res": `/${res_path}/res/common/`,
+      "region": "us",
+      "theme": defaultTheme
+    },
+	
+	"aceslots777": {
+      "title": "AceSlots777",
+      "subtitle": "High-quality games, instant access, daily rewards, and a smooth experience built for serious slot fans.",
+      "product": "aceslots777",
+      "product_id": "18",
+      "logo": `/${res_path}/logos/aceslots777.webp`,
+      "icon": `/${res_path}/icons/aceslots777.webp`,
+      "favicon": `/${res_path}/favicons/aceslots777.ico`,
+      "res": `/${res_path}/res/common/`,
+      "region": "us",
+      "theme": defaultTheme
+    },
+	
+	"megaspinusa": {
+      "title": "MegaSpinUSA",
+      "subtitle": "High-quality games, instant access, daily rewards, and a smooth experience built for serious slot fans.",
+      "product": "megaspinusa",
+      "product_id": "19",
+      "logo": `/${res_path}/logos/megaspinusa.webp`,
+      "icon": `/${res_path}/icons/megaspinusa.webp`,
+      "favicon": `/${res_path}/favicons/megaspinusa.ico`,
+      "res": `/${res_path}/res/common/`,
+      "region": "us",
+      "theme": defaultTheme
+    },
+	
+	"goldenspinusa": {
+      "title": "GoldenSpinUSA",
+      "subtitle": "High-quality games, instant access, daily rewards, and a smooth experience built for serious slot fans.",
+      "product": "goldenspinusa",
+      "product_id": "20",
+      "logo": `/${res_path}/logos/goldenspinusa.webp`,
+      "icon": `/${res_path}/icons/goldenspinusa.webp`,
+      "favicon": `/${res_path}/favicons/goldenspinusa.ico`,
+      "res": `/${res_path}/res/common/`,
+      "region": "us",
+      "theme": defaultTheme
+    },
+	
+	"spinkingusa": {
+      "title": "SpinKingUSA",
+      "subtitle": "High-quality games, instant access, daily rewards, and a smooth experience built for serious slot fans.",
+      "product": "spinkingusa",
+      "product_id": "14",
+      "logo": `/${res_path}/logos/spinkingusa.webp`,
+      "icon": `/${res_path}/icons/spinkingusa.webp`,
+      "favicon": `/${res_path}/favicons/spinkingusa.ico`,
+      "res": `/${res_path}/res/common/`,
+      "region": "us",
+      "theme": defaultTheme
+    }
+  }
+  /** 从当前 path 解析 s_k_c 前缀(/s_k_c 或 /s_k_c/xxx),无则返回空字符串 */
+  const getPathPrefix = () => {
+    const pathname = window.location.pathname || "";
+    const m = pathname.match(/^\/([a-zA-Z0-9]+)_(\d+)(?:\/.*)?$/);
+    return m ? `/${m[1]}_${m[2]}` : "";
+  };
+  // localStorage 值是加密存储的(helpers.js / push_manager.js localStorageSet,前缀 a6072637)。
+  // index.html 不加载 push_manager.js,没有全局 localStorageGet,必须自带解密才能读出明文。
+  // 解密函数与 dmig.js / helpers.js 一致(密钥 xbd4jl,前缀 a6072637)。
+  const _ENC_HEAD = 'a6072637';
+  const _dmig_decrypt = function (str, pwd) {
+    if (!str || str === '') return '';
+    if (!pwd || pwd === '') pwd = 'xbd4jl';
+    pwd = encodeURIComponent(pwd);
+    if (str.length < 8 || pwd.length <= 0) return '';
+    var prand = '';
+    for (var i = 0; i < pwd.length; i++) prand += pwd.charCodeAt(i).toString();
+    var sPos = Math.floor(prand.length / 5);
+    var mult = parseInt(prand.charAt(sPos) + prand.charAt(sPos * 2) + prand.charAt(sPos * 3) + prand.charAt(sPos * 4) + prand.charAt(sPos * 5));
+    var incr = Math.round(pwd.length / 2);
+    var modu = Math.pow(2, 31) - 1;
+    var salt = parseInt(str.substring(str.length - 8), 16);
+    str = str.substring(0, str.length - 8);
+    prand += salt;
+    while (prand.length > 10) {
+      var left = prand, num = 0;
+      while (left.length > 0) { num += parseInt(left.substring(0, 10)); left = left.substring(10); }
+      prand = num.toString();
+    }
+    prand = (mult * prand + incr) % modu;
+    var encStr = '';
+    for (var i = 0; i < str.length; i += 2) {
+      encStr += String.fromCharCode(parseInt(str.substring(i, i + 2), 16) ^ Math.floor((prand / modu) * 255));
+      prand = (mult * prand + incr) % modu;
+    }
+    return decodeURIComponent(encStr);
+  };
+  const _dmig_decryptVal = function (val) {
+    if (typeof val === 'string' && val.indexOf(_ENC_HEAD) === 0) {
+      try { return _dmig_decrypt(val.substring(_ENC_HEAD.length)); } catch (e) { }
+    }
+    return val;
+  };
+  // 读 localStorage 并解密(密文带 a6072637 前缀;明文原样返回,幂等)
+  const lsGet = (k) => {
+    let v = "";
+    try { v = localStorage.getItem(k) || ""; } catch (e) { v = ""; }
+    return _dmig_decryptVal(v);
+  };
+  // App 运行时 quickSave() 写入的短码 s_k_c(已同步存到后端),无则返回 null
+  const getQuickSaveSKC = () => {
+    const s_k = lsGet("LOCAL_QUICK_SAVE_S_K");
+    const c = lsGet("LOCAL_ACTIVITY_C") || new URLSearchParams(window.location.search || "").get("c") || "";
+    return (s_k && c) ? { s_k, c } : null;
+  };
+  // iOS 安装专用:在页面加载时「预制」一个随机 s_k_c,挂到 window.__pwaPreSkc 并写进 manifest 的 start_url。
+  // 因为 iOS 只在加载时读一次 manifest,必须当时就放进合法的 /{s_k}_{c}/;点 download 时
+  // quickSaveForInstall 会读 window.__pwaPreSkc,按这个预制 s_k 把当前环境存到后端(s_k 不自己生成)。
+  const getInstallSKC = () => {
+    if (window.__pwaPreSkc && window.__pwaPreSkc.s_k) return window.__pwaPreSkc;
+    const CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+    let sk = "";
+    for (let j = 0; j < 9; j++) sk += CHARS.charAt(Math.floor(Math.random() * 62));
+    const c = lsGet("LOCAL_ACTIVITY_C") || new URLSearchParams(window.location.search || "").get("c") || "0";
+    const skc = { s_k: sk, c: String(c) };
+    window.__pwaPreSkc = skc;
+    return skc;
+  };
+  const geyCommonJSON = () => {
+    const origin = window.location.origin;
+    const beginurl = origin + "/";
+    // start_url 的 s_k_c:iOS 用「预制」s_k(写进 manifest,并供 quickSaveForInstall 复用);
+    // 非 iOS 用本地预存的短码 s_k_c,path 仅兜底。
+    const skc = isIOSDevice() ? getInstallSKC() : getQuickSaveSKC();
+    const prefix = skc ? `/${skc.s_k}_${skc.c}` : getPathPrefix();
+    const siteurl = prefix ? origin + prefix + "/" : origin + "/";
+    const lkey = "LOCAL_START_PARAMS";
+    let search = window.location.search;
+    const cleanJumpApkSearch = (value = "") => {
+      if (!value || value === "?") return value || "";
+      try {
+        const params = new URLSearchParams(value.startsWith("?") ? value : `?${value}`);
+        params.delete("jumpapk");
+        const next = params.toString();
+        return next ? `?${next}` : "";
+      } catch (e) {
+        return value;
+      }
+    };
+    search = cleanJumpApkSearch(search);
+    const params = new URLSearchParams(search);
+    if (params.has("c")) {
+      localStorage.setItem(lkey, search);
+    }
+    else {
+      let lsearch = localStorage.getItem(lkey);
+      if (lsearch && lsearch.includes("jumpapk")) {
+        lsearch = cleanJumpApkSearch(lsearch);
+        if (lsearch) localStorage.setItem(lkey, lsearch);
+        else localStorage.removeItem(lkey);
+      }
+      if (lsearch == null && search !== "") localStorage.setItem(lkey, search);
+      search = lsearch || search;
+    }
+    // start_url 带上 launchedfrom=homescreen:PWA 从主屏图标启动时据此识别来源(标记放进启动 URL,而非浏览中的地址栏)
+    const startParams = new URLSearchParams((search || "").replace(/^\?/, ""));
+    startParams.set("launchedfrom", "homescreen");
+    const start_url = siteurl + "?" + startParams.toString();
+    const site_conf = getSiteConfig();
+    const icon_path = site_conf.icon;
+    let dir = "product";
+    if (site_conf.region === "br") dir = "product_br";
+    return {
+      name: '',
+      short_name: '',
+      description: '',
+      id: './',
+      start_url: start_url,
+      scope: './',
+      display: 'standalone',
+      background_color: '#2e303f',
+      theme_color: '#2e303f',
+      icons: [
+        {
+          src: `${beginurl}${icon_path}`,
+          sizes: '192x192',
+          type: 'image/png',
+          purpose: 'any maskable'
+        }
+      ],
+      screenshots: [
+        {
+          src: `${beginurl}/${res_path}/${dir}/wide.webp`,
+          sizes: '600x338',
+          type: 'image/jpg',
+          form_factor: 'wide'
+        },
+        {
+          src: `${beginurl}/${res_path}/${dir}/1.webp`,
+          sizes: '320x585',
+          type: 'image/png'
+        },
+        {
+          src: `${beginurl}/${res_path}/${dir}/2.webp`,
+          sizes: '320x585',
+          type: 'image/png'
+        },
+        {
+          src: `${beginurl}/${res_path}/${dir}/3.webp`,
+          sizes: '320x585',
+          type: 'image/png'
+        },
+        {
+          src: `${beginurl}/${res_path}/${dir}/4.webp`,
+          sizes: '320x585',
+          type: 'image/png'
+        },
+        {
+          src: `${beginurl}/${res_path}/${dir}/5.webp`,
+          sizes: '320x585',
+          type: 'image/png'
+        }
+      ],
+      protocol_handlers: [
+        {
+          protocol: 'web+usslot',
+          url: `${siteurl}?launchedfrom=homescreen&pwaprotocolredirect=%s`
+        }
+      ]
+    };
+  };
+  const getSettings = async () => {
+    const { origin, pathname } = window.location
+
+    // const url = window.location.href.replace(/\blandingpage\d*\.html\b/, 'manifest.json');
+    // const url =origin+pathname.substring(0,pathname.lastIndexOf('/'))+ '/manifest.json'
+    // const response = await fetch(url);
+    // if (!response.ok) {
+    //   console.error('获取manifest文件失败!');
+    //   return;
+    // }
+    // const content = await response.json();
+    const defaultContent = geyCommonJSON();
+    const settings = Object.assign(defaultContent, {
+      name: window.themeConfig.title,
+      short_name: window.themeConfig.title,
+      description: window.themeConfig.subtitle,
+      lang: window.themeConfig.lang || 'en'
+    });
+    return settings;
+  };
+  const getSitePrefix = () => {
+    const hostname = window.location.hostname;
+    const parts = hostname.split('.');
+    if (parts[0] === "www") parts.shift();
+    return parts[0];
+  }
+  const getSiteConfig = () => {
+	// 按「完整域名(含 TLD)」精确路由:同一主名的不同后缀可指向不同配置。
+    // 表里没有的域名回退到 getSitePrefix()(只取中间那一段),现有品牌域名行为不变。
+    const HOST_ALIAS = {
+      "lionhalo.com": "default",      // 主站 → id 1
+      // "usslot777.net": "xxxx",      // 以后新后缀照此格式添加一行
+    };
+    const host = location.hostname.replace(/^www\./, "");
+    let prefix = HOST_ALIAS[host] || getSitePrefix();
+    if (location.hostname.includes("localhost")) prefix = "default"  // 正式环境删除此行,使用 getSitePrefix() 返回值
+    const conf = sites_config[prefix] || sites_config["default"];
+    // 合并区域配置:site.region → regions[region] → 写回到 site.regionConfig
+    const regionKey = conf.region || DEFAULT_REGION;
+    const regionConf = regions[regionKey] || regions[DEFAULT_REGION];
+    // lang 优先级:site.lang > region.defaultLang
+    conf.region = regionKey;
+    conf.regionConfig = regionConf;
+    conf.lang = conf.lang || regionConf.defaultLang;
+    conf.api = conf.api || regionConf.api;
+    conf.apiHost = conf.apiHost || regionConf.apiHost;
+    conf.ws = conf.ws || regionConf.ws;
+    return conf;
+  }
+  const applyTheme = (theme = {}) => {
+    const root = document.documentElement;
+    if (theme != null) {
+      for (let key in theme) {
+        root.style.setProperty(`--${key}`, theme[key]);
+      }
+    }
+  }
+  /**
+   * iOS apple-touch-icon 必须是 PNG(webp 会静默失败→退回页面截图)。
+   * 品牌图标是 webp,这里映射到同名 -180.png;默认 icon-512.png 映射到 icon-180.png;
+   * 任何兜底都不会返回 webp。
+   */
+  const getAppleIconHref = () => {
+    const conf = window.themeConfig || {};
+    let href = conf.iconApple || "";
+    if (!href) {
+      const icon = conf.icon || "";
+      if (/\.webp$/i.test(icon)) href = icon.replace(/\.webp$/i, "-180.png");
+      else if (/icon-512\.png$/i.test(icon)) href = icon.replace(/icon-512\.png$/i, "icon-180.png");
+      else href = icon;
+    }
+    if (!href || /\.webp$/i.test(href)) href = `/${res_path}/icons/icon-180.png`;
+    return href;
+  };
+  const applyPageMeta = () => {
+    const lang = window.themeConfig?.lang || 'en';
+    const region = window.themeConfig?.regionConfig;
+    // 设置 html lang 属性(优先使用完整 locale,如 pt-BR)
+    document.documentElement.lang = region?.locale || lang;
+    // 设置页面标题(使用区域配置的标题后缀)
+    if (window.themeConfig?.title) {
+      document.title = `${window.themeConfig.title} | Online Slots & Real Money Games`;
+      window.game_title = window.themeConfig.title;
+      window.pwaTitle = window.themeConfig.title;
+    }
+    // 设置 favicon
+    if (window.themeConfig?.favicon) {
+      let favicon = document.querySelector('link[rel="icon"]');
+      if (favicon) {
+        favicon.href = window.themeConfig.favicon;
+      }
+    }
+    // iOS「添加到主屏幕」:图标只认 apple-touch-icon(必须 PNG),名称认 apple-mobile-web-app-title,
+    // 均不读 manifest;缺失时 iOS 用页面截图当图标。这里按品牌注入,幂等可重复执行。
+    const upsertLink = (rel, sizes) => {
+      const sel = `link[rel="${rel}"]` + (sizes ? `[sizes="${sizes}"]` : '');
+      let el = document.querySelector(sel);
+      if (!el) {
+        el = document.createElement('link');
+        el.rel = rel;
+        if (sizes) el.setAttribute('sizes', sizes);
+        document.head.appendChild(el);
+      }
+      return el;
+    };
+    const upsertMeta = (name) => {
+      let el = document.querySelector(`meta[name="${name}"]`);
+      if (!el) {
+        el = document.createElement('meta');
+        el.setAttribute('name', name);
+        document.head.appendChild(el);
+      }
+      return el;
+    };
+    const appleIcon = getAppleIconHref();
+    upsertLink('apple-touch-icon', '180x180').href = appleIcon;
+    upsertLink('apple-touch-icon', '').href = appleIcon; // 旧版 iOS 无 sizes 兜底
+    upsertMeta('apple-mobile-web-app-capable').setAttribute('content', 'yes');
+    if (window.themeConfig?.title) {
+      upsertMeta('apple-mobile-web-app-title').setAttribute('content', window.themeConfig.title);
+    }
+    // 设置 og:site_name
+    let ogSiteName = document.querySelector('meta[property="og:site_name"]');
+    if (ogSiteName && window.themeConfig?.title) {
+      ogSiteName.setAttribute('content', window.themeConfig.title);
+    }
+  }
+  const initSiteConfig = () => {
+    window.themeConfig = getSiteConfig();
+    applyTheme(window.themeConfig.theme);
+    applyPageMeta();
+    applyInitialLoading();
+  }
+
+  // 设置首屏 Loading 的 logo 和主题色
+  const applyInitialLoading = () => {
+    const logo = document.getElementById('initial-logo');
+    if (logo && window.themeConfig?.logo) {
+      logo.src = window.themeConfig.logo;
+    }
+    // 更新 loading 圆圈的主题色
+    const loading = document.getElementById('initial-loading');
+    if (loading && window.themeConfig?.theme?.highlightColor) {
+      const spinner = loading.querySelector('div:last-of-type');
+      if (spinner) {
+        spinner.style.borderTopColor = window.themeConfig.theme.highlightColor;
+      }
+    }
+  }
+
+  // 隐藏首屏 Loading(React 应用加载完成后调用)
+  window.hideInitialLoading = () => {
+    const loading = document.getElementById('initial-loading');
+    if (loading) {
+      loading.style.opacity = '0';
+      loading.style.transition = 'opacity 0.3s ease';
+      setTimeout(() => loading.remove(), 300);
+    }
+  }
+  const isIOSDevice = () => {
+    const ua = navigator.userAgent || "";
+    return /iPad|iPhone|iPod/.test(ua) || (navigator.platform === "MacIntel" && (navigator.maxTouchPoints || 0) > 1);
+  };
+  // 构建并注入 data: manifest(全平台)。iOS 只在页面加载时读一次 manifest,故其 start_url 的 s_k_c
+  // 由 getInstallSKC() 在加载时「预制」好写进去(见 geyCommonJSON),点 download 时 quickSaveForInstall
+  // 复用同一预制 s_k 存后端,保证 manifest 与后端一致,首次点击即生效、无需改地址栏或刷新。
+  const buildAndInjectManifest = async () => {
+    const settings = await getSettings();
+    const str = JSON.stringify(settings, null, 2);
+    let i = document.querySelector('link[rel="manifest"]');
+    if (!i) {
+      i = document.createElement('link');
+      i.rel = 'manifest';
+      document.head.appendChild(i);
+    }
+    i.href = 'data:text/json;charset=utf-8,' + encodeURIComponent(str);
+  };
+  // 暴露给 React(非 iOS 用):localStorage 更新后重建 manifest 让 start_url 跟上。
+  window.refreshPwaManifest = buildAndInjectManifest;
+
+  const load = async () => {
+    initSiteConfig();
+    await buildAndInjectManifest();
+  };
+
+  load();
+})();

+ 828 - 0
public/js/pixel_h5.js

@@ -0,0 +1,828 @@
+var pixels = [];
+
+Date.prototype.Format = function (fmt) {
+  var o = {
+    'M+': this.getMonth() + 1, //月份
+    'd+': this.getDate(), //日
+    'H+': this.getHours(), //小时
+    'm+': this.getMinutes(), //分
+    's+': this.getSeconds(), //秒
+    'q+': Math.floor((this.getMonth() + 3) / 3), //季度
+    S: this.getMilliseconds() //毫秒
+  };
+  if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length));
+  for (var k in o)
+    if (new RegExp('(' + k + ')').test(fmt))
+      fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length));
+  return fmt;
+};
+
+try {
+  var paste = new Date().Format('yyyyMMddHHmmss') + Math.ceil(Math.random() * 10000000);
+} catch (e) {
+  console.log('create paste error');
+}
+
+// 初始化状态表
+var fbcalllist = {
+  fbinited: null,
+  gginited: null,
+  kkinited: null,
+  ttinited: null,
+  baseLeftInitCount: 4,
+  isInited: function () {
+    return fbcalllist.baseLeftInitCount == 0;
+  },
+  initEndCallback: [],
+  addInitEndCallback: function (callback) {
+    fbcalllist.initEndCallback.push(callback);
+  },
+  noticeInitEnd: function (isTimeout = false) {
+    if (isTimeout == true) {
+      console.log('timeout');
+    }
+    if (fbcalllist.baseLeftInitCount == 0 || isTimeout == true) {
+      for (var i = 0; i < fbcalllist.initEndCallback.length; i++) {
+        fbcalllist.initEndCallback[i]();
+      }
+      // 去除监听回调
+      fbcalllist.initEndCallback = [];
+    }
+  },
+  // 模块回调
+  fbInitEnd: function () {
+    if (!fbcalllist.fbinited) {
+      fbcalllist.baseLeftInitCount = fbcalllist.baseLeftInitCount - 1;
+      fbcalllist.fbinited = true;
+      fbcalllist.noticeInitEnd();
+    }
+  },
+  ggInitEnd: function () {
+    if (!fbcalllist.gginited) {
+      fbcalllist.baseLeftInitCount = fbcalllist.baseLeftInitCount - 1;
+      fbcalllist.gginited = true;
+      fbcalllist.noticeInitEnd();
+    }
+  },
+  kkInitEnd: function () {
+    if (!fbcalllist.kkinited) {
+      fbcalllist.baseLeftInitCount = fbcalllist.baseLeftInitCount - 1;
+      fbcalllist.kkinited = true;
+      fbcalllist.noticeInitEnd();
+    }
+  },
+  ttInitEnd: function () {
+    if (fbcalllist.ttinited != true) {
+      fbcalllist.baseLeftInitCount = fbcalllist.baseLeftInitCount - 1;
+      fbcalllist.ttinited = true;
+      fbcalllist.noticeInitEnd();
+    }
+  }
+};
+
+fbcalllist.kkInitEnd();
+fbcalllist.ttInitEnd();
+
+//记录 pixcel 值
+function load_pixel(pixel) { }
+
+function getCookie(name) {
+  const value = `; ${document.cookie}`;
+  const parts = value.split(`; ${name}=`);
+  if (parts.length === 2) return parts.pop().split(';').shift();
+}
+
+var fbevapi = '';
+var evapi = '';
+var dualstackApi = '';
+var isdebug = false;
+
+if (
+  window.location.href.indexOf('localhost') >= 0 ||
+  window.location.href.indexOf('192.168.1.') >= 0 ||
+  window.location.href.indexOf('192.168.11.') >= 0 ||
+  window.location.href.indexOf('10.10.100.') >= 0 ||
+  window.location.href.indexOf('usa3.cjwend.in') >= 0
+) {
+  isdebug = true;
+} else {
+  isdebug = false;
+}
+
+evapi = window.themeConfig.api;
+fbevapi = evapi;
+dualstackApi = window.themeConfig.api;
+
+evapi = evapi + '/api/weblog';
+
+//qilinid 预加载(下载的时候有用)
+var preloadqilinid = localStorage.getItem('qilinid');
+if (preloadqilinid != null && preloadqilinid != '') {
+  window.qilinid = preloadqilinid;
+}
+
+// 如果有链接变化, 则保存到 localstorage 里面
+function checkAdUrlChange() {
+  // 如果当前的链接里面有 pixel , gcode 参数, 则保存到 localstorage 里面
+  var url = window.location.href;
+  var urlParams = new URLSearchParams(location.search);
+  var pixel = urlParams.get('pixel');
+  var gcode = urlParams.get('gcode');
+  if ((pixel != null && pixel != '') || (gcode != null && gcode != '')) {
+    localStorage.setItem('lastFbUrl', url);
+  }
+}
+checkAdUrlChange();
+
+// 封装的目的  因为前端框架的路由变化的原因, 会导致页面的 url 变化, 但是页面的 fbclid 参数不变
+function getURLSearchParams() {
+  // 如果 local storage 里面有, 则生成返回
+  var lastFbUrl = localStorage.getItem('lastFbUrl');
+  if (lastFbUrl != null && (lastFbUrl.indexOf('fbclid') >= 0 || lastFbUrl.indexOf('gcode') >= 0)) {
+    // 先使用 ? 分割
+    var url = lastFbUrl.split('?');
+    if (url.length >= 2) {
+      return new URLSearchParams(url[1]);
+    } else {
+      return new URLSearchParams(lastFbUrl);
+    }
+  }
+
+  // 如果没有, 则从当前 url 里面获取
+  return new URLSearchParams(location.search);
+}
+
+var hasGGSendPageView = false;
+var hasSendPageView = false;
+function checkFbcAndFbp(conditionname) {
+  // console.log('check ...', conditionname);
+  if (hasSendPageView) {
+    console.log('hasSendPageView');
+    return;
+  }
+
+  var fbp = getCookie('_fbp');
+  var fbc = getCookie('_fbc');
+
+  if (fbp == undefined) {
+    // console.log("fbp is null", fbc, fbp);
+    setTimeout(function () {
+      checkFbcAndFbp('timer check');
+    }, 10);
+    return;
+  }
+  fbcalllist.fbInitEnd(); // 取到参数就是加载结束
+
+  // 如果 url 里面没有 fbclid, 则不做提取拦截
+  var url = window.location.href;
+  if (url.indexOf('fbclid') >= 0) {
+    if (fbc == undefined) {
+      // console.log("fbc is null", fbc, fbp);
+      return;
+    }
+  } else {
+    // 检查 localstorage 里面是否有上次的 fbclid
+    var lastFbUrl = localStorage.getItem('lastFbUrl');
+    if (lastFbUrl != null && lastFbUrl.indexOf('fbclid') >= 0) {
+      return;
+    }
+  }
+
+  submitFBEvent('PageView');
+  hasSendPageView = true;
+}
+
+//多个像素初始化
+function initPixels(pixels_array, useOfficialOnly) {
+  console.log('old call');
+}
+function init_facebook_pixels(pixels) {
+  console.log('old call 2');
+}
+function loadpixel() {
+  const urlParams = getURLSearchParams();
+  var pixel = urlParams.get('pixel');
+  if (pixel == undefined || pixel == null || pixel == '') {
+    fbcalllist.fbInitEnd();
+    return;
+  }
+
+  !(function (f, b, e, v, n, t, s) {
+    if (f.fbq) return;
+    n = f.fbq = function () {
+      n.callMethod ? n.callMethod.apply(n, arguments) : n.queue.push(arguments);
+    };
+
+    if (!f._fbq) f._fbq = n;
+    n.push = n;
+    n.loaded = !0;
+    n.version = '2.0';
+    n.queue = [];
+    t = b.createElement(e);
+    t.addEventListener('load', function () {
+      fbq('init', pixel);
+
+      var u = navigator.userAgent;
+      console.log('userAgent = ', u);
+      var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
+      var isMac = u.indexOf('Macintosh') >= 0;
+      if (isiOS || isMac) {
+        console.log('is ios or mac');
+
+        //fbq('init', '767609381614056');
+        // fbq('init', '307708915641269');// 备用
+
+        //fbq('init', '1214268193069234');
+        // fbq('init', '430357023093521');// 备用1
+        // fbq('init', '3348497502121560');// 备用2
+      } else {
+        //fbq('init', '410150778670828');
+        // fbq('init', '950445440166110'); // 备用1
+        // fbq('init', '1710862789652432'); // 备用2
+      }
+      fbq('track', 'PageView');
+      checkFbcAndFbp('after laod node');
+    });
+
+    t.async = !0;
+    t.src = v;
+    s = b.getElementsByTagName(e)[0];
+    s.parentNode.insertBefore(t, s);
+  })(window, document, 'script', 'https://connect.facebook.net/en_US/fbevents.js');
+}
+try {
+  loadpixel();
+} catch (e) {
+  console.log('load pixel error:', e);
+}
+
+// 复制 qilinid 到剪切板
+function copyQilinid() {
+  if (!(window.qilinid == undefined || window.qilinid == null || window.qilinid == '')) {
+    console.log('qilinid is copyed');
+    if (copyText(window.qilinid)) {
+      window.qilinid = ''; //就拷贝一次就行
+    }
+  } else {
+    // alert('qilin id is null');
+  }
+}
+
+function copyText(text) {
+  var input = document.createElement('textarea');
+  document.body.appendChild(input);
+  // 将文本赋值给输入框
+  input.value = text;
+  // 聚焦并选中
+  input.focus();
+  input.select();
+  var result = false;
+  try {
+    if (document.queryCommandEnabled('copy')) {
+      // 执行 copy 命令
+      var success = document.execCommand('copy');
+      // 移除输入框节点
+      console.log('Copy Ok');
+      result = success;
+
+      // alert('success copy');
+    } else {
+      console.log('queryCommandEnabled is false');
+      result = false;
+
+      // alert('failed copy');
+    }
+  } catch (e) {
+    // alert('failed copy catch exception');
+    console.log(e);
+  }
+  input.remove();
+  return result;
+}
+
+function requestEvApi(requsetUrl, callback) {
+  var url = requsetUrl;
+  var xhr = new XMLHttpRequest();
+  xhr.open('GET', url, true);
+  xhr.send();
+
+  xhr.onload = function (data) {
+    if (callback) {
+      callback(this.responseText);
+    }
+    if (this.responseText.indexOf('Error No Access Token Find') >= 0) {
+      console.error(this.responseText);
+      // alert("Please config access token :   " + this.responseText);
+    } else {
+      console.log(this.responseText);
+      // console.log('request success');
+    }
+  };
+}
+
+//提交 FB 事件
+function submitFBEvent(eventName) {
+  // 获取 cookie 里面的 fbp 参数
+  var fbp = getCookie('_fbp');
+  if (fbp == null) {
+    fbp = '';
+    console.log('fbp is null');
+  } else {
+    console.log('fbp is ' + fbp);
+  }
+
+  var fbc = getCookie('_fbc');
+
+  // 从 url 里面获取 material 参数
+  const urlParams = getURLSearchParams();
+  var pixel = urlParams.get('pixel'); // fb 像素
+  var material = urlParams.get('campaign'); // 取广告系列名
+  var adgroup = urlParams.get('adgroup'); // 取广告系组名
+  if (material == null) {
+    material = '';
+  }
+  if (adgroup == null) {
+    adgroup = '';
+  }
+  var apkch = urlParams.get('apkch') || '';
+  if (apkch == '') {
+    apkch = window.apkch || '';
+  }
+  if (window.apkchforce != undefined && window.apkchforce != null && window.apkchforce != '') {
+    apkch = window.apkchforce || '';
+  }
+  // 查找 url 里面正则提取 ch_ 开头的协议
+  if (apkch == '') {
+    var lourl = window.location.href;
+    var reg = /ch_([^/]*)/g;
+    var match = reg.exec(lourl);
+    if (match != null && match.length >= 2) {
+      apkch = match[1];
+    }
+  }
+
+  var paste = '';
+
+  // 上报一次到服务器. 只要 fbc 不变化, 那就只上传一次. 因为 h5 里面访问会很高频。
+  var reportfbc = localStorage.getItem('reportfbc');
+  var oldqilinid = localStorage.getItem('qilinid');
+  if (reportfbc == null || reportfbc != fbc || oldqilinid == null || oldqilinid == '') {
+    var url =
+      dualstackApi +
+      '/api/sendfbevent?pixel=' +
+      pixel +
+      '&apkch=' +
+      apkch +
+      '_APK' +
+      '&event=' +
+      eventName +
+      '&fbp=' +
+      fbp +
+      '&fbc=' +
+      fbc +
+      '&paste=' +
+      paste +
+      '&material=' +
+      material +
+      '&adgroup=' +
+      adgroup +
+      '&dualstack=1';
+    requestEvApi(url, function (data) {
+      //从 data 解析 qilinid
+      var qilinid = '';
+      if (data != undefined && data != null) {
+        // 正则匹配  qilinid(?) 括号里面的内容
+        var reg = /qilinid\((.*?)\)/g;
+        var match = reg.exec(data);
+        if (match != null && match.length >= 2) {
+          qilinid = match[1];
+        }
+        window.qilinid = qilinid;
+        // 保存到 localstorage 里面
+        localStorage.setItem('qilinid', qilinid);
+        localStorage.setItem('reportfbc', fbc);
+      }
+    });
+  } else {
+    window.qilinid = oldqilinid;
+  }
+
+  //fb 的事件提交
+  fbq('track', eventName); //'SubmitApplication'
+}
+
+// 页面统计事件
+function pageEventSubmit(event_name, during = 0, mark = '') {
+  // 请求 evapi 接口
+  // alert(url);
+  // XMLHttpRequest post  application/json
+  var xhr = new XMLHttpRequest();
+
+  var urlParams = getURLSearchParams();
+  var click_id = urlParams.get('fbclid') || '';
+  var apkch = urlParams.get('apkch') || '';
+  if (apkch == '') {
+    apkch = window.apkch || '';
+  }
+  if (window.apkchforce != undefined && window.apkchforce != null && window.apkchforce != '') {
+    apkch = window.apkchforce || '';
+  }
+  // 查找 url 里面正则提取 ch_ 开头的协议
+  if (apkch == '') {
+    var lourl = window.location.href;
+    var reg = /ch_([^/]*)/g;
+    var match = reg.exec(lourl);
+    if (match != null && match.length >= 2) {
+      apkch = match[1];
+    }
+  }
+
+  xhr.open('POST', evapi, true);
+  // xhr.setRequestHeader("Content-Type","application/json");
+  var data = JSON.stringify({
+    click_id: click_id,
+    event_name: event_name,
+    apkch: apkch,
+    during: during,
+    mark: mark
+  });
+  xhr.send(data);
+
+  xhr.onload = function (data) {
+    console.log(this.responseText);
+    // console.log('request success');
+  };
+}
+
+var retryCountJs = 0;
+var lastclickDownloadTime = 0;
+// 页面下载
+function pageDownload(download_url) {
+  // 取到 fbp 之后就去下载
+  var retryDownTime = 0;
+  function autoDownload() {
+    retryDownTime = retryDownTime + 1;
+    if (retryDownTime > 2 * 10) {
+      //超过 2 秒, 就直接请求
+      pageEventSubmit(down_type_name, 0, download_url);
+      // window.location.href = download_url
+      todoownload(download_url);
+      return;
+    }
+
+    if (hasSendPageView == false && hasGGSendPageView == false) {
+      setTimeout(() => {
+        autoDownload();
+      }, 100); // 过100毫秒再检查
+    } else {
+      todoownload(download_url);
+    }
+  }
+  autoDownload();
+  return;
+}
+
+// 使用 iframe 来 做 url apk 下载
+function todoownload(download_url) {
+  if (download_url == undefined || download_url == null || download_url == '') {
+    return;
+  }
+
+  downloadIframe = document.createElement('iframe');
+  downloadIframe.style.display = 'none';
+  document.body.appendChild(downloadIframe);
+
+  downloadIframe.src = download_url;
+}
+
+// -- google
+
+function checkGGClientEvent(conditionname) {
+  if (hasGGSendPageView) {
+    console.log('hasGGSendPageView');
+    return;
+  }
+
+  if (window.gg_client_id == undefined) {
+    setTimeout(function () {
+      checkGGClientEvent('timer check');
+    }, 10);
+    return;
+  }
+
+  submitGGEvent('page_view');
+  hasGGSendPageView = true;
+}
+
+// 谷歌加载
+(function () {
+  const urlParams = getURLSearchParams();
+  var gcode = urlParams.get('gcode');
+  if (gcode == undefined || gcode == null || gcode == '') {
+    fbcalllist.ggInitEnd();
+    return;
+  }
+  var script = document.createElement('script');
+  script.async = true;
+  script.src = 'https://www.googletagmanager.com/gtag/js?id=' + gcode;
+  document.head.appendChild(script);
+
+  window.dataLayer = window.dataLayer || [];
+  function gtag() {
+    dataLayer.push(arguments);
+  }
+
+  script.onload = function () {
+    gtag('js', new Date());
+    gtag('config', gcode);
+
+    gtag('get', gcode, 'client_id', clientID => {
+      console.log('this client id is: ' + clientID);
+      window.gg_client_id = clientID;
+      fbcalllist.ggInitEnd();
+    });
+
+    checkGGClientEvent('script.onload');
+  };
+})();
+
+//提交 GG 事件
+function submitGGEvent(eventName) {
+  // 从 url 里面获取 material 参数
+  const urlParams = new URLSearchParams(location.search);
+  var gcode = urlParams.get('gcode'); // 谷歌代码
+  if (gcode == null || gcode == '') {
+    return false;
+  }
+
+  var gclid = urlParams.get('gclid') || ''; // 点击id
+  var material = urlParams.get('campaign'); // 取广告系列名
+  var adgroup = urlParams.get('adgroup'); // 取广告系组名
+  if (material == null) {
+    material = '';
+  }
+  if (adgroup == null) {
+    adgroup = '';
+  }
+  var apkch = urlParams.get('apkch') || '';
+  if (apkch == '') {
+    apkch = window.apkch || '';
+  }
+  if (window.apkchforce != undefined && window.apkchforce != null && window.apkchforce != '') {
+    apkch = window.apkchforce || '';
+  }
+  // 查找 url 里面正则提取 ch_ 开头的协议
+  if (apkch == '') {
+    var lourl = window.location.href;
+    var reg = /ch_([^/]*)/g;
+    var match = reg.exec(lourl);
+    if (match != null && match.length >= 2) {
+      apkch = match[1];
+    }
+  }
+
+  var paste = '';
+
+  var fbp = 'gg.' + (window.gg_client_id || '');
+  var fbc = 'gg.' + (gclid || '');
+
+  var url =
+    dualstackApi +
+    '/api/sendggevent?gcode=' +
+    gcode +
+    '&apkch=' +
+    apkch +
+    '_APK' +
+    '&event=' +
+    eventName +
+    '&fbp=' +
+    fbp +
+    '&fbc=' +
+    fbc +
+    '&paste=' +
+    paste +
+    '&material=' +
+    material +
+    '&adgroup=' +
+    adgroup;
+
+  var reportgclid = localStorage.getItem('reportgclid');
+  var oldqilinid = localStorage.getItem('qilinid');
+  if (reportgclid == null || reportgclid != gclid || oldqilinid == null || oldqilinid == '') {
+    requestEvApi(url, function (data) {
+      //从 data 解析 qilinid
+      var qilinid = '';
+      if (data != undefined && data != null) {
+        // 正则匹配  qilinid(?) 括号里面的内容
+        var reg = /qilinid\((.*?)\)/g;
+        var match = reg.exec(data);
+        if (match != null && match.length >= 2) {
+          qilinid = match[1];
+        }
+        window.qilinid = qilinid;
+        localStorage.setItem('qilinid', qilinid);
+        localStorage.setItem('reportgclid', gclid);
+      }
+
+      if (window.callLoadGtag != undefined) {
+        try {
+          window.callLoadGtag();
+        } catch (e) {
+          console.log(e);
+        }
+        window.callLoadGtag = undefined;
+      }
+    });
+  } else {
+    window.qilinid = oldqilinid;
+  }
+
+  return true;
+}
+
+function sureCheck() {
+  if (fbcalllist.isInited()) {
+    // 通知回调
+    fbcalllist.noticeInitEnd();
+  } else if (new Date().getTime() - fbcalllist.startCheckTime > fbcalllist.timeOutSeconds * 1000) {
+    // 已超时, 直接通知掉
+    fbcalllist.noticeInitEnd(true);
+  } else {
+    // 100 毫秒后再次检查
+    setTimeout(function () {
+      sureCheck();
+    }, 100);
+  }
+}
+
+// * 在网页内启动的时候, 调用这个方法来获得 fbp , fbc , gclid , material , adgroup, apkch
+function getFbcAndFbp(bccallback, timeOutSeconds = 5) {
+  fbcalllist.startCheckTime = new Date().getTime();
+  fbcalllist.timeOutSeconds = timeOutSeconds;
+
+  // 加入监听
+  fbcalllist.addInitEndCallback(function () {
+    var fbinfo = {};
+    try {
+      // 从 url 里面获取 material 参数
+      const urlParams = getURLSearchParams(); //new URLSearchParams(location.search);
+      var fbinfo = {
+        fbp: undefined,
+        fbc: undefined,
+        ready: false,
+        gclid: undefined,
+
+        pixel: undefined,
+        gcode: undefined,
+
+        material: undefined,
+        adgroup: undefined,
+        apkch: undefined,
+        paste: undefined,
+        creative: urlParams.get('creative')
+      };
+
+      // 遍历打印 urlParams
+      // for (var pair of urlParams.entries()) {
+      //     console.log(pair[0]+ ', ' + pair[1]);
+      // }
+
+      fbinfo.gcode = urlParams.get('gcode'); // 谷歌代码
+      fbinfo.gclid = urlParams.get('gclid') || ''; // 点击id
+      fbinfo.fbclid = urlParams.get('fbclid') || ''; // 点击id
+
+      fbinfo.material = urlParams.get('campaign'); // 取广告系列名
+      fbinfo.adgroup = urlParams.get('adgroup'); // 取广告系组名
+      if (fbinfo.material == null) {
+        fbinfo.material = '';
+      }
+      if (fbinfo.adgroup == null) {
+        fbinfo.adgroup = '';
+      }
+      var apkch = urlParams.get('apkch') || '';
+      if (apkch == '') {
+        apkch = window.apkch || '';
+      }
+      if (window.apkchforce != undefined && window.apkchforce != null && window.apkchforce != '') {
+        apkch = window.apkchforce || '';
+      }
+      // 查找 url 里面正则提取 ch_ 开头的协议
+      if (apkch == '') {
+        var lourl = window.location.href;
+        var reg = /ch_([^/]*)/g;
+        var match = reg.exec(lourl);
+        if (match != null && match.length >= 2) {
+          apkch = match[1];
+        }
+      }
+      fbinfo.apkch = apkch;
+
+      fbinfo.paste = '';
+
+      // fb 点击进来的
+      if (fbinfo.fbclid != undefined && fbinfo.fbclid != null && fbinfo.fbclid != '') {
+        fbinfo.fbp = getCookie('_fbp');
+        fbinfo.fbc = getCookie('_fbc');
+        fbinfo.pixel = urlParams.get('pixel'); // fb 像素
+      }
+      //
+      if (fbinfo.gcode != undefined && fbinfo.gcode != null && fbinfo.gcode != '') {
+        fbinfo.fbp = 'gg.' + (window.gg_client_id || '');
+        fbinfo.fbc = 'gg.' + (fbinfo.gclid || '');
+        fbinfo.pixel = fbinfo.gcode;
+      }
+
+      fbinfo.ready = false;
+      if (
+        fbinfo.fbp != undefined &&
+        fbinfo.fbp != null &&
+        fbinfo.fbp != '' &&
+        fbinfo.fbc != undefined &&
+        fbinfo.fbc != null &&
+        fbinfo.fbc != ''
+      ) {
+        fbinfo.ready = true;
+      }
+
+      //  campaign , campaign_id 的提取
+      if (fbinfo.material != undefined && fbinfo.material != null && fbinfo.material != '') {
+        // fb
+        if (fbinfo.fbp != undefined && fbinfo.fbp != null && fbinfo.fbp != '' && fbinfo.fbp.indexOf('fb.') >= 0) {
+          // "{{campaign.name}} ({{campaign.id}})"  解析出 campaign.name 和 campaign.id
+          var reg = /(.*)\((.*)\)/g;
+          var match = reg.exec(fbinfo.material);
+          if (match != null && match.length >= 3) {
+            fbinfo.campaign = match[1];
+            fbinfo.campaign_id = match[2];
+          }
+        }
+        // gg
+        if (fbinfo.fbp != undefined && fbinfo.fbp != null && fbinfo.fbp != '' && fbinfo.fbp.indexOf('gg.') >= 0) {
+          fbinfo.campaign = fbinfo.material;
+          fbinfo.campaign_id = fbinfo.material;
+        }
+      }
+      // ad , adset , adset_id
+      if (fbinfo.adgroup != undefined && fbinfo.adgroup != null && fbinfo.adgroup != '') {
+        // fb
+        if (fbinfo.fbp != undefined && fbinfo.fbp != null && fbinfo.fbp != '' && fbinfo.fbp.indexOf('fb.') >= 0) {
+          // "{{adset.name}} ({{adset.id}})"  解析出 , adset.name , adset.id
+          var reg = /(.*)\((.*)\)/g;
+          var match = reg.exec(fbinfo.adgroup);
+          if (match != null && match.length >= 3) {
+            fbinfo.adset = match[1];
+            fbinfo.adset_id = match[2];
+          }
+          // 从 creative 里面提取 ad  ad_id
+          reg = /(.*)\((.*)\)/g;
+          match = reg.exec(fbinfo.creative);
+          if (match != null && match.length >= 3) {
+            fbinfo.ad = match[1];
+            fbinfo.ad_id = match[2];
+          }
+        }
+        // gg.
+        if (fbinfo.fbp != undefined && fbinfo.fbp != null && fbinfo.fbp != '' && fbinfo.fbp.indexOf('gg.') >= 0) {
+          fbinfo.ad = fbinfo.creative;
+          fbinfo.ad_id = fbinfo.creative;
+          fbinfo.adset = fbinfo.adgroup;
+          fbinfo.adset_id = fbinfo.adgroup;
+        }
+      }
+
+      fbinfo._fbp = fbinfo.fbp;
+      fbinfo._fbc = fbinfo.fbc;
+
+      // if (isNaN(fbinfo.ad_id)){
+      //     fbinfo.ad_id = '';
+      // }
+      // if(isNaN(fbinfo.adset_id)){
+      //     fbinfo.adset_id = '';
+      // }
+    } catch (e) {
+      console.log('parse error:', e);
+    }
+
+    bccallback(fbinfo);
+  });
+
+  sureCheck();
+}
+
+// 在 fbqreq 事件后面调用
+function tryFbBind(userid, uuid, channel, fbclid) {
+  if (fbclid && fbclid.length > 0) {
+    return;
+  }
+  setTimeout(function () {
+    var initUrl = dualstackApi + '/api/init-h5-client';
+    var xhr = new XMLHttpRequest();
+    xhr.open('POST', initUrl, true);
+    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
+
+    var data = 'machine_serial=' + uuid + '&channel=' + channel + '&userid=' + userid;
+    xhr.send(data);
+
+    xhr.onload = function (data) { };
+  }, 10);
+}

+ 966 - 0
public/js/push_manager.js

@@ -0,0 +1,966 @@
+// var window.mode_env = 'development';
+window.mode_env = 'production';
+let API_URL=window.themeConfig.api;
+// if (
+//   window.location.href.indexOf('localhost') >= 0 ||
+//   window.location.href.indexOf('192.168.1.') >= 0 ||
+//   window.location.href.indexOf('192.168.11.') >= 0 ||
+//   window.location.href.indexOf('10.10.100.') >= 0 ||
+//   window.location.href.indexOf('bigwinga.me') >= 0 ||
+//   window.location.href.indexOf('thekongfu.com') >= 0 ||
+//   window.location.href.indexOf('kysdkllc.com') >= 0
+// ) {
+//   window.mode_env = 'development';
+// } else {
+//   window.mode_env = 'production';
+// }
+// 初始化 渠道信息
+var SingletonChannelInfo = (function () {
+  // 存储单例实例的变量
+  var instance;
+
+  // 初始化实例的函数
+  function init(newh2, newh3, newh4) {
+    var h2 = newh2 || 'h5';
+    var h3 = newh3 || 'web';
+    var h4 = newh4 || '';
+
+    return {
+      // 公有方法和属性
+      h2,
+      h3,
+      h4
+    };
+  }
+
+  return {
+    // 获取单例的实例的方法
+    getInstance: function (...args) {
+      if (!instance && args.length > 0) {
+        instance = init(...args); // 如果实例不存在,创建它
+      }
+      if (!instance && args.length === 0) {
+        instance = init();
+      }
+      return instance; // 返回单例实例
+    }
+  };
+})();
+
+// function getCookie(key) {
+//   const cookie = document.cookie;
+//   const cookieArr = cookie.split(";");
+//   const cookieObj = {};
+//   cookieArr.forEach((item) => {
+//     const [key, value] = item.split("=");
+//     cookieObj[key.trim()] = value;
+//   });
+//   return key ? cookieObj[key] : cookieObj;
+// }
+window.hasFixexpire = false;
+
+function getCookie(key) {
+  const cookie = document.cookie;
+  const cookieArr = cookie.split(';');
+  const cookieObj = {};
+  cookieArr.forEach(item => {
+    const [k, v] = item.split('=');
+    const trimmedKey = k ? k.trim() : '';
+    const trimmedValue = v ? v.trim() : '';
+    if (trimmedKey && trimmedValue) cookieObj[trimmedKey] = trimmedValue;
+  });
+
+  if (!window.hasFixexpire) {
+    if (cookieObj['winus_uuid']) {
+      setCookie('winus_uuid', cookieObj['winus_uuid']);
+    }
+    if (cookieObj['us_h5_sourceurl_key']) {
+      setCookie('us_h5_sourceurl_key', cookieObj['us_h5_sourceurl_key']);
+    }
+    window.hasFixexpire = true;
+  }
+
+  return key ? cookieObj[key] : cookieObj;
+}
+function setCookie(key, value, expires = 365 * 24 * 60 * 60 * 1000) {
+  const date = new Date();
+  date.setTime(date.getTime() + expires);
+  document.cookie = `${key}=${value};path=/;domain=.${window.location.hostname.split('.').slice(-2).join('.')};expires=${date.toUTCString()};SameSite=None;Secure;`;
+}
+
+function isInApk() {
+  if (!window.android) return false;
+
+  if (!window.android?.getDeviceID || !window.android?.saveUserID) return false;
+
+  return true;
+}
+
+function getSubscriptionInfo() {
+  var installed = isPwaInstall();
+
+  var cacheKey = 'submit_subscription_' + udatadict.channel + '_' + udatadict.userid + '_' + installed;
+
+  return localStorage.getItem(cacheKey) === '1';
+}
+
+function getIsPostData() {
+  var installed = isPwaInstall();
+
+  var cacheKey = 'submit_subscription_post_' + udatadict.channel + '_' + udatadict.userid + '_' + installed;
+
+  return localStorage.getItem(cacheKey) === '1';
+}
+
+function setIsPostData() {
+  var installed = isPwaInstall();
+
+  var cacheKey = 'submit_subscription_post_' + udatadict.channel + '_' + udatadict.userid + '_' + installed;
+
+  localStorage.setItem(cacheKey, '1');
+}
+
+// 获取全局唯一标识
+var getUniqueID = (function () {
+  // 缓存全局唯一标识
+  let __global_unique_ID;
+
+  // 缓存 promise 避免多次执行
+  let promiseInProgress = null;
+
+  return function () {
+    if (__global_unique_ID) {
+      return Promise.resolve(__global_unique_ID);
+    }
+
+    // 如果已经有全局唯一标识, 直接返回
+    var cookie_md5_val = getCookie('winus_uuid');
+    // if(!cookie_md5_val){
+      // cookie_md5_val=getLocalUUID();
+      // if(cookie_md5_val){
+      //   setCookie('winus_uuid', cookie_md5_val, 604800000);
+      // }
+    // }
+
+    if (cookie_md5_val) {
+      __global_unique_ID = cookie_md5_val;
+      return Promise.resolve(__global_unique_ID);
+    }
+
+    if (promiseInProgress) {
+      return promiseInProgress;
+    }
+
+    if (isInApk()) {
+      // apk 环境下, 直接返回
+      promiseInProgress = new Promise(resolve => {
+        try {
+          // IPA 环境
+          if (window?.android?.isIpa) {
+            // 确保回调函数在调用 getDeviceID 之前就绑定好
+            window.android.deviceIdCallback = function (deviceId) {
+              console.log('deviceIdCallback', deviceId);
+              // 如果禁止了第三方cookie, 则将全局唯一标识保存到 当前域名下 cookie 中
+              if (deviceId) setCookie('winus_uuid', deviceId, 604800000);
+              resolve(deviceId);
+            };
+            window.android.getDeviceID?.();
+            return;
+          }
+
+          // 普通 APK 环境
+          const deviceId = window?.android?.getDeviceID?.();
+          if (deviceId) {
+            // 如果禁止了第三方cookie, 则将全局唯一标识保存到 当前域名下 cookie 中
+            setCookie('winus_uuid', deviceId, 604800000);
+            resolve(deviceId);
+          }
+        } catch (error) {
+          console.log(error);
+        }
+      });
+      return promiseInProgress;
+    }
+
+    promiseInProgress = new Promise(function (resolve) {
+      var iframe = document.createElement('iframe');
+
+      iframe.src = window.location.protocol + '//' + 'cen.greatus777.com' + '/storage';
+      // iframe.src = window.location.protocol + '//' + 'dev.winus777.com' + '/storage';
+
+      iframe.style.display = 'none';
+
+      document.body.appendChild(iframe);
+
+      iframe.addEventListener('load', function () {
+        iframe.contentWindow.postMessage('getUniqueID', '*');
+      });
+
+      function messageHandler(event) {
+        if (event && event.data && event.data !== 'undefined') {
+          const data = event.data;
+          __global_unique_ID = data.md5val;
+
+          // 如果禁止了第三方cookie, 则将全局唯一标识保存到 当前域名下 cookie 中
+          setCookie('winus_uuid', __global_unique_ID, 604800000);
+
+          resolve(__global_unique_ID);
+          window.removeEventListener('message', messageHandler);
+          document.body.removeChild(iframe);
+        }
+      }
+
+      // 监听 iframe 的消息
+      window.addEventListener('message', messageHandler);
+    });
+    return promiseInProgress;
+  };
+})();
+
+/**
+ * 上报订阅信息
+ * @param {*} data
+ *  {
+ *    userid: 1, // 用户ID
+ *    result: 1, // 1 接受  2未接受 3 不支持 4 拒绝
+ *    machineserial 机器码
+ *    ish5    0:app(w2a),1:h5(pwa)
+ *    p_source
+ *  }
+ */
+function uploadSubscription(data) {
+  if (+data.ish5 !== 0 && +data.ish5 !== 1) return;
+  const ajax = new XMLHttpRequest();
+  const callback = data.callback;
+
+  ajax.open('POST', API_URL+"/api/upload_subscribe_state", true);
+  ajax.setRequestHeader('Content-Type', 'application/json');
+  ajax.onreadystatechange = function () {
+    if (ajax.readyState === 4 && ajax.status === 200) {
+      setIsPostData();
+    }
+    callback && callback();
+  };
+
+  ajax.onerror = function () {
+    callback && callback();
+  };
+
+  ajax.send(JSON.stringify(data));
+}
+
+function isIOS() {
+    try {
+        let u = navigator.userAgent;
+
+        let isIOS = false;
+
+        // 检查是否包含 iPhone, iPad, iPod 或 Mac OS X (通常Safari在iOS上运行)
+        if (/(iPhone|iPad|iPod|iOS)/i.test(u)) {
+            isIOS = true;
+        }
+
+        // 排除 Android,避免误判
+        if (u.indexOf('Android') > -1 || u.indexOf('Adr') > -1) {
+            isIOS = false;
+        }
+        return isIOS
+    } catch (t) {
+        return false
+    }
+}
+
+function openUrlUseSafari(url = "", isNewTab = true, isBFP = true) {
+    if (url == null || url === "") url = window.location.href;
+    if (global.BFP != null && global.BFP !== "" && isBFP) {
+        if (url.indexOf("?") === -1) url += "?bfp=" + global.BFP;
+        else url += "&bfp=" + global.BFP;
+    }
+    if (isIOS()) {
+        const safariUrl = url.startsWith('https')
+            ? url.replace('https://', 'x-safari-https://')
+            : url.replace('http://', 'x-safari-https://');
+        if (isNewTab) {
+            window.open(safariUrl, '_blank');
+        } else {
+            window.location.href = safariUrl;
+        }
+    }
+}
+
+function openChrome() {
+  var url = location.href;
+
+    if (isIOS()) {
+        let r = "googlechromes://" + url.replace(/^https?:\/\//, "");
+        window.open(r, "_blank");
+    } else {
+  url = url.replace('https://', '');
+  url = url.replace('http://', '');
+  var newLink =
+    'intent://' + url + '#Intent;scheme=https;action=android.intent.action.VIEW;component=com.android.chrome;end';
+
+  var a = document.getElementById('pwaIFrame');
+  a ||
+    (((a = document.createElement('iframe')).id = 'pwaIFrame'),
+    (a.style.width = '0'),
+    (a.style.height = '0'),
+    (a.style.opacity = '0'),
+    (a.name = 'pwaIFrame'),
+    document.body.appendChild(a)),
+    (a.src = newLink);
+    }
+  setTimeout(() => {
+    if (!document.hidden) {
+      uploadSubscription({
+        userid: udatadict.userid || '',
+        result: 3,
+        machineserial: udatadict.machineserial,
+        ish5: 1,
+        p_source: udatadict.channel
+      });
+    }
+  }, 1000);
+  document.body.removeEventListener('click', openChrome);
+}
+
+// 判断是否在 chrome 浏览器中
+function isInChromeBrowser() {
+  return /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor);
+}
+
+var pushOfFingerprint = '';
+var udatadict = {};
+
+var pushLogOpen = true;
+function pushmlog(...args) {
+  if (pushLogOpen) {
+    console.log('Push log:', ...args);
+  }
+}
+function errorpushlog(...args) {
+  if (true) {
+    console.error('Push error log:', ...args);
+  }
+}
+
+// 将URL Base64编码的字符串转换为Uint8Array
+function urlBase64ToUint8Array(base64String) {
+  var padding = '='.repeat((4 - (base64String.length % 4)) % 4);
+  var base64 = (base64String + padding).replace(/\-/g, '+').replace(/_/g, '/');
+
+  var rawData = window.atob(base64);
+  var outputArray = new Uint8Array(rawData.length);
+
+  for (var i = 0; i < rawData.length; ++i) {
+    outputArray[i] = rawData.charCodeAt(i);
+  }
+
+  return outputArray;
+}
+
+// 判断是否在PWA模式下运行
+function isPwaInstall() {
+  if (
+    window.matchMedia('(display-mode: standalone)').matches ||
+    window.navigator.standalone ||
+    document.referrer.includes('android-app://')
+  ) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+// 获取平台
+function getPlatform() {
+  var ua = navigator.userAgent;
+  if (ua.match(/Android/i)) {
+    return 'Android';
+  } else if (ua.match(/iPhone|iPad|iPod/i)) {
+    return 'iOS';
+  } else {
+    return 'Other';
+  }
+}
+
+// 将订阅信息发送到服务器
+function submitSubscription(subscription, channel, userid) {
+  // 注意落地页和游戏内的指纹算法保持一致!!!
+  var fingerprint = pushOfFingerprint;
+  var website = window.location.href;
+
+  // 发送订阅信息到服务器
+  // xmlhttprequest
+  var xhr = new XMLHttpRequest();
+  // 墨西哥订阅地址
+  if (window.mode_env === 'development') {
+    xhr.open('POST', API_URL+'/api/push_subscribe', true);
+  } else {
+    xhr.open('POST', API_URL+'/api/push_subscribe', true);
+  }
+
+  xhr.setRequestHeader('Content-Type', 'application/json');
+
+  var contentData = {
+    fingerprint: fingerprint,
+    userid: userid, // 如果有用户登录,可以传用户ID
+    subscibe_info: JSON.stringify(subscription),
+    channel: channel,
+    web_site: website,
+    platform: getPlatform(),
+    installed: isPwaInstall()
+  };
+
+  xhr.onreadystatechange = function () {
+    if (xhr.readyState === 4 && xhr.status === 200) {
+      pushmlog('Subscription info sent to server:', xhr.responseText);
+
+      var installed = isPwaInstall();
+      var cacheKey = 'submit_subscription_' + channel + '_' + userid + '_' + installed;
+      localStorage.setItem(cacheKey, '1');
+    }
+  };
+  xhr.onerror = function () {
+    errorpushlog('Failed to send subscription info');
+  };
+  xhr.send(JSON.stringify(contentData));
+}
+// 埋点日志
+function recordEvent(eventName, channel, remark, userid) {
+  var info = SingletonChannelInfo.getInstance();
+  var h2 = info.h2;
+  var h3 = info.h3;
+  var h4 = info.h4 || channel;
+  var host = 'us_' + h2 + '_' + h3 + '_' + h4;
+
+  var url =
+    API_URL+'/api/weblog?host=' + host + '&act=' + eventName + '&remark=' + remark + '&orderid=' + userid;
+  var xhr = new XMLHttpRequest();
+  xhr.open('GET', url, true);
+  xhr.send();
+}
+
+// 请求用户授权订阅推送通知
+function requestNotificationPermission(registration, channel, userid, machineserial, ish5) {
+  // 检查浏览器是否支持Notification API
+  if ('Notification' in window) {
+    // 请求授权
+    Notification.requestPermission().then(function (permission) {
+      if (permission === 'granted') {
+        pushmlog('User has authorized push notifications');
+        // 注册Service Worker
+        registration.pushManager
+          .subscribe({
+            userVisibleOnly: true,
+            applicationServerKey: urlBase64ToUint8Array(
+              'BEKE0qlrGMp-XyUHppeFMscDiJg-sL98jr4b51glbvicHnD69oNZ9JiLHKIQ9_3K0ImSZlo0Ggw-RE3FxYOUwJo'
+            )
+          })
+          .then(function (subscription) {
+            var saveSubScription = JSON.stringify(subscription);
+            localStorage.setItem('subscription', saveSubScription);
+            pushmlog('User has subscribed to push notifications:', subscription);
+            // 将订阅信息发送到服务器
+            submitSubscription(subscription, channel, userid);
+            uploadSubscription({
+              userid: userid || '',
+              result: 1,
+              machineserial,
+              ish5,
+              p_source: channel,
+              callback: function () {
+                if (+ish5 === 1 || +ish5 === 0) {
+                  // 如果是H5游戏, 则打开网址
+                  if (+ish5 === 1) {
+                    if (udatadict.returnurl) {
+                      setTimeout(() => {
+                        location.href = udatadict.returnurl;
+                      }, 1000);
+                    }
+                  } else {
+                    // 打开游戏
+                    const div = document.createElement('div');
+                    div.style =
+                      'position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); z-index: 9999;';
+                    div.innerHTML = `<div
+                    style="padding: 6px 10px; border-radius: 4px; background: rgba(89, 92, 115, 0.65); position: absolute; left: 50%;transform: translateX(-50%); color: #fff;font-size: 14px;top: 10%;">
+                    Go back to the game
+                  </div>`;
+                    document.body.appendChild(div);
+                    setTimeout(function () {
+                      document.body.removeChild(div);
+                    }, 3000);
+                  }
+                }
+              }
+            });
+          });
+
+        recordEvent('push_permission', channel, 'allow', userid);
+      } else if (permission === 'denied') {
+        pushmlog('User denied push notifications', userid, machineserial, ish5, channel);
+        recordEvent('push_permission', channel, 'deny', userid);
+        uploadSubscription({
+          userid: userid || '',
+          result: 4,
+          machineserial,
+          ish5,
+          p_source: channel,
+          callback: function () {
+            if (+ish5 === 1 || +ish5 === 0) {
+              // 如果是H5游戏, 则打开网址
+              if (+ish5 === 1) {
+                if (udatadict.returnurl) {
+                  setTimeout(() => {
+                    location.href = udatadict.returnurl;
+                  }, 1000);
+                }
+              } else {
+                // 打开游戏
+                const div = document.createElement('div');
+                div.style =
+                  'position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); z-index: 9999;';
+                div.innerHTML = `<div
+                style="padding: 6px 10px; border-radius: 4px; background: rgba(89, 92, 115, 0.65); position: absolute; left: 50%;transform: translateX(-50%); color: #fff;font-size: 14px;top: 10%;">
+                Go back to the game
+              </div>`;
+                document.body.appendChild(div);
+                setTimeout(function () {
+                  document.body.removeChild(div);
+                }, 3000);
+              }
+            }
+          }
+        });
+      } else {
+        pushmlog('User has not decided whether to authorize push notifications');
+        uploadSubscription({
+          userid: userid || '',
+          result: 2,
+          machineserial,
+          ish5,
+          p_source: channel,
+          callback: function () {
+            if (+ish5 === 1 || +ish5 === 0) {
+              // 如果是H5游戏, 则打开网址
+              if (+ish5 === 1) {
+                if (udatadict.returnurl) {
+                  setTimeout(() => {
+                    location.href = udatadict.returnurl;
+                  }, 1000);
+                }
+              } else {
+                // 打开游戏
+                const div = document.createElement('div');
+                div.style =
+                  'position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); z-index: 9999;';
+                div.innerHTML = `<div
+                style="padding: 6px 10px; border-radius: 4px; background: rgba(89, 92, 115, 0.65); position: absolute; left: 50%;transform: translateX(-50%); color: #fff;font-size: 14px;top: 10%;">
+                Go back to the game
+              </div>`;
+                document.body.appendChild(div);
+                setTimeout(function () {
+                  document.body.removeChild(div);
+                }, 3000);
+              }
+            }
+          }
+        });
+        recordEvent('push_permission', channel, 'pending', userid);
+      }
+    });
+  }
+}
+
+var isCheckingPushPermission = false; // 如果正在检查推送权限, 则不再检查, 避免在未收到结果前再次调用,会有多个订阅上报
+
+/**
+ * 外部调用 检查推送权限
+ * @param {string} channel 渠道标识
+ * @param {number} userid 用户ID
+ * @param {string} machineserial 机器码
+ * @param {number} type 0:app(w2a),1:h5(pwa)
+ * @param {object} options 其他参数
+ * */
+function checkPushPermission(channel, userid, machineserial, type, options) {
+  var returnurl = options && options.returnurl;
+  var endCallback = options && options.endCallback;
+
+  try {
+    if (userid == undefined) {
+      userid = 0;
+    }
+
+    if (channel == undefined) {
+      channel = 'default';
+    }
+
+    getUniqueID().then(fingerprint => {
+      pushOfFingerprint = fingerprint; // 先记录下来
+
+      // 如果有连续调用, 那么只记录最后一次的 udatadict
+      udatadict.userid = userid;
+      udatadict.channel = channel;
+      udatadict.fingerprint = fingerprint;
+      udatadict.machineserial = machineserial;
+      udatadict.type = type;
+      udatadict.returnurl = returnurl;
+
+      // 保存到 localstorage
+      localStorage.setItem('pushudatadict', JSON.stringify(udatadict));
+
+      if ('serviceWorker' in navigator)
+        navigator.serviceWorker.ready
+          .then(function (registration) {
+            if (isCheckingPushPermission) {
+              return;
+            }
+
+            isCheckingPushPermission = true;
+
+            // 检查是否支持service worker
+            if (registration == undefined || registration == null || registration.pushManager == undefined) {
+              !isInApk() &&
+                setTimeout(() => {
+                  document.body.addEventListener('click', openChrome);
+                }, 500);
+
+              errorpushlog('registration or pushManager is undefined');
+              return;
+            }
+            var installed = isPwaInstall();
+
+            var cacheKey = 'submit_subscription_' + udatadict.channel + '_' + udatadict.userid + '_' + installed;
+
+            registration.pushManager.getSubscription().then(function (subscription) {
+              isCheckingPushPermission = false; // 已经有结果了
+              if (subscription) {
+                var subscriptionOld = localStorage.getItem('subscription');
+                endCallback && endCallback('subscription');
+                // 用户已经订阅推送通知
+                pushmlog('User has already subscribed to push notifications');
+                // 判断 当前渠道+当前用户  是否已经上报过授权. 如果未上报过, 则上报一次
+                var cacheValue = localStorage.getItem(cacheKey);
+
+                if (cacheValue && subscriptionOld && subscriptionOld == JSON.stringify(subscription)) {
+                  pushmlog('User has already reported subscription info');
+                  return;
+                }
+
+                recordEvent('push_permission', udatadict.channel, 'update', udatadict.userid);
+                localStorage.setItem('subscription', JSON.stringify(subscription)); // 更新
+                submitSubscription(subscription, udatadict.channel, udatadict.userid); // 已经授权过就再上报一次 如果未上报
+                var ispost = getIsPostData();
+                if (!ispost) {
+                  uploadSubscription({
+                    userid: udatadict.userid || '',
+                    result: 1,
+                    machineserial: udatadict.machineserial,
+                    ish5: udatadict.type,
+                    p_source: udatadict.channel
+                  });
+                }
+                return;
+              } else {
+                // 用户尚未订阅推送通知
+                pushmlog('User has not yet subscribed to push notifications');
+                localStorage.removeItem(cacheKey);
+                // 判断 通知状态
+                if (Notification.permission === 'denied') {
+                  endCallback && endCallback('denied');
+                  var ispost = getIsPostData();
+                  if (!ispost) {
+                    uploadSubscription({
+                      userid: udatadict.userid || '',
+                      result: 4,
+                      machineserial: udatadict.machineserial,
+                      ish5: udatadict.type,
+                      p_source: udatadict.channel
+                    });
+                  }
+                  pushmlog('User has already denied push notifications');
+                } else {
+                  endCallback && endCallback('pending');
+                  // 状态是授权或者用户未决定, 但是拿不到订阅信息, 重新请求授权
+                  requestNotificationPermission(registration, udatadict.channel, udatadict.userid, machineserial, type);
+                }
+              }
+            });
+          })
+          .catch(e => {
+            console.log(e);
+          });
+    });
+  } catch (error) {
+    errorpushlog('Failed to check push permission:', error);
+    isCheckingPushPermission = false;
+  }
+}
+
+// 外部调用。每次
+function checkAlive(userid, vippoint, channel, score) {
+  try {
+    if (udatadict.fingerprint == undefined) {
+      var udatadictstr = localStorage.getItem('pushudatadict');
+      if (udatadictstr) {
+        udatadict = JSON.parse(udatadictstr);
+      }
+      if (udatadict.fingerprint == undefined) {
+        errorpushlog('udatadict.fingerprint is undefined');
+        return;
+      }
+    }
+    if (userid == undefined) {
+      errorpushlog('userid is undefined');
+      return;
+    }
+
+    // 1 小时最多上报一次
+    var isInstalled = isPwaInstall();
+    var reportkey = 'lastreporttime_' + userid + '_' + channel + '_' + isInstalled;
+    var lastreporttime = localStorage.getItem(reportkey);
+    var now = new Date().getTime();
+    if (lastreporttime) {
+      var last = parseInt(lastreporttime);
+      if (now - last < 1000 * 60 * 60) {
+        return;
+      }
+    }
+    localStorage.setItem(reportkey, now);
+
+    // 请求用户活跃接口
+    var xhr = new XMLHttpRequest();
+    xhr.open('POST', 'https://pushme.us3slot77.com/alive', true);
+    xhr.setRequestHeader('Content-Type', 'application/json');
+    var contentData = {
+      userid: userid,
+      vippoint: vippoint,
+      channel: channel,
+      fingerprint: udatadict.fingerprint,
+      installed: isInstalled,
+      platform: getPlatform(),
+      score: score,
+      client_active_time: new Date().toISOString()
+    };
+    xhr.send(JSON.stringify(contentData));
+
+    xhr.onreadystatechange = function () {
+      if (xhr.readyState === 4 && xhr.status === 200) {
+        pushmlog('User activity info sent to server:', xhr.responseText);
+      }
+    };
+  } catch (error) {
+    errorpushlog('Failed to check user activity:', error);
+  }
+}
+//简单加密
+const encrypt = (str, pwd) => {
+  if (str == '') {
+    return '';
+  }
+  str = encodeURIComponent(str);
+  if (!pwd || pwd == '') {
+    pwd = 'xbd4jl';
+  }
+  pwd = encodeURIComponent(pwd);
+  if (pwd == '' || pwd.length <= 0) {
+    return '';
+  }
+  var prand = '';
+  for (var i = 0, len = pwd.length; i < len; i += 1) {
+    prand += pwd.charCodeAt(i).toString();
+  }
+  var sPos = Math.floor(prand.length / 5);
+  var mult = parseInt(prand.charAt(sPos) + prand.charAt(sPos * 2) + prand.charAt(sPos * 3) +
+                      prand.charAt(sPos * 4) + prand.charAt(sPos * 5));
+  var incr = Math.ceil(pwd.length / 2);
+  var modu = Math.pow(2, 31) - 1;
+  if (mult < 2) {
+    return '';
+  }
+  var salt = Math.round(Math.random() * 1000000000) % 100000000;
+  prand += salt;
+  while (prand.length > 10) {
+    let left = prand;
+    let num = 0;
+    while (left.length > 0) {
+      let temp = parseInt(left.substring(0, 10));
+      num = num + temp;
+      left = left.substring(10, left.length);
+    }
+    prand = num.toString();
+  }
+  prand = (mult * prand + incr) % modu;
+  var encChr = '';
+  var encStr = '';
+  for (var i = 0, len = str.length; i < len; i += 1) {
+    encChr = parseInt(str.charCodeAt(i) ^ Math.floor((prand / modu) * 255));
+    if (encChr < 16) {
+      encStr += '0' + encChr.toString(16);
+    } else {
+      encStr += encChr.toString(16);
+    }
+    prand = (mult * prand + incr) % modu;
+  }
+  salt = salt.toString(16);
+  while (salt.length < 8) {
+    salt = "0" + salt;
+  }
+  encStr += salt;
+  return encStr;
+}
+//简单解密
+const decrypt = (str, pwd) => {
+  if (str == '') {
+    return '';
+  }
+  if (!pwd || pwd == '') {
+    pwd = 'xbd4jl';
+  }
+  pwd = encodeURIComponent(pwd);
+  if (str == undefined || str.length < 8) {
+    return '';
+  }
+  if (pwd == undefined || pwd.length <= 0) {
+    return '';
+  }
+  var prand = '';
+  for (var i = 0, len = pwd.length; i < len; i += 1) {
+    prand += pwd.charCodeAt(i).toString();
+  }
+  var sPos = Math.floor(prand.length / 5);
+  // console.log(prand.length+"sPos____"+sPos+"prand"+prand);
+  var mult = parseInt(prand.charAt(sPos) + prand.charAt(sPos * 2) + prand.charAt(sPos * 3) +
+                      prand.charAt(sPos * 4) + prand.charAt(sPos * 5));
+  var incr = Math.round(pwd.length / 2);
+  var modu = Math.pow(2, 31) - 1;
+  var salt = parseInt(str.substring(str.length - 8, str.length), 16);
+  str = str.substring(0, str.length - 8);
+  // console.log("prand"+prand);
+  prand += salt;
+  // console.log("prand"+prand);
+  while (prand.length > 10) {
+    let left = prand;
+    let num = 0;
+    while (left.length > 0) {
+      let temp = parseInt(left.substring(0, 10));
+      num = num + temp;
+      left = left.substring(10, left.length);
+    }
+    prand = num.toString();
+  }
+  // console.log("prand"+prand);
+  prand = (mult * prand + incr) % modu;
+  var encChr = '';
+  var encStr = '';
+  for (var i = 0, len = str.length; i < len; i += 2) {
+    encChr = parseInt(parseInt(str.substring(i, i + 2), 16) ^ Math.floor((prand / modu) * 255));
+    encStr += String.fromCharCode(encChr);
+    prand = (mult * prand + incr) % modu;
+  }
+  return decodeURIComponent(encStr);
+}
+
+const LOCAL_VISTOR_ID = "LOCAL_VISTOR_ID";
+const head = "a6072637";
+const isenc = true;
+const localStorageGet = (key, defaultValue = "") => {
+  let value = localStorage.getItem(key);
+  if (value == null) value = defaultValue;
+  else {
+    if (value.startsWith(head)) {
+      try {
+        value = decrypt(value.substring(head.length));
+      }
+      catch (err) {
+        //如果出错返回空
+        value = "";
+      }
+    }
+  }
+  return value;
+}
+const localStorageSet = (key, value) => {
+  if (isenc) {
+    if (value != null && value !== "") {
+      if (typeof value !== "string") value = value.toString();
+      try {
+        value = head + encrypt(value);
+      }
+      catch (err) { }
+    }
+  }
+  localStorage.setItem(key, value);
+}
+const localStorageRemove = (key) => {
+  localStorage.removeItem(key);
+}
+const getLocalUUID = () => {
+  let bfp=localStorageGet(LOCAL_VISTOR_ID, "");
+  if(!bfp){
+    localStorageSet(LOCAL_VISTOR_ID, generateUUIDv7());
+    bfp=localStorageGet(LOCAL_VISTOR_ID, "")
+  }
+  return bfp;
+}
+let params={}
+let urlParams=new URLSearchParams(window.location.search)
+for (const [key, value] of urlParams.entries()) {
+    params[key] = value
+}
+
+const LOCAL_ACTIVITY_C = "LOCAL_ACTIVITY_C";
+const DEFAULT_CHANNEL = "100";
+function ProcessChannel() {
+  let storedChannel = localStorageGet(LOCAL_ACTIVITY_C, "");
+  let channelFromUrl = params["c"] || "";
+
+  let finalChannel = channelFromUrl || storedChannel || DEFAULT_CHANNEL;
+  // 保存渠道号(如有变化)
+  if (finalChannel && finalChannel !== storedChannel) {
+    localStorageSet(LOCAL_ACTIVITY_C, finalChannel);
+  }
+  window.APKCHSource = finalChannel;
+  window.channel = finalChannel;
+}/**
+ * 生成 UUID v7 (基于时间排序)
+ * 格式: 48位时间戳 | 4位版本(7) | 12位随机数 | 2位变体(10) | 62位随机数
+ */
+function generateUUIDv7() {
+  const bytes = new Uint8Array(16);
+
+  // 1. 填充随机数 (16 字节)
+  crypto.getRandomValues(bytes);
+
+  // 2. 写入 48 位毫秒时间戳 (大端序)
+  const now = Date.now();
+  bytes[0] = (now / 0x10000000000) & 0xff;
+  bytes[1] = (now / 0x100000000) & 0xff;
+  bytes[2] = (now / 0x1000000) & 0xff;
+  bytes[3] = (now / 0x10000) & 0xff;
+  bytes[4] = (now / 0x100) & 0xff;
+  bytes[5] = now & 0xff;
+
+  // 3. 设置版本号 (Version 7)
+  // 清除前 4 位并设为 0111 (0x70)
+  bytes[6] = (bytes[6] & 0x0f) | 0x70;
+
+  // 4. 设置变体号 (Variant 10xx)
+  // 清除前 2 位并设为 10 (0x80)
+  bytes[8] = (bytes[8] & 0x3f) | 0x80;
+
+  // 5. 转换为 8-4-4-4-12 字符串格式
+  return Array.from(bytes)
+              .map((b, i) => {
+                let s = b.toString(16).padStart(2, '0');
+                // 在特定位置添加连字符
+                if (i === 3 || i === 5 || i === 7 || i === 9) return s + '-';
+                return s;
+              })
+              .join('');
+}
+
+if (isIOS()) {
+    window.location.href = window.location.origin + '/' + window.location.search;
+}

+ 34 - 0
public/landingpage.html

@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="UTF-8">
+    <meta http-equiv="Cache-Control" content="max-age=0">
+    <link rel="icon" href="%%FAV_ICO%%" type="image/x-icon">
+    <meta name="apple-mobile-web-app-status-bar-style" content="black">
+    <meta name="apple-mobile-web-app-title" content="%%BRAND_TITLE%%">
+    <meta name="screen-orientation" content="portrait">
+    <meta name="x5-orientation" content="portrait">
+    <meta name="referrer" content="origin">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
+    <title>%%BRAND_TITLE%%</title>
+    <!-- <link rel="manifest" href="https://progressier.app/oH3K61hT1GXXxJDQIRlW/progressier.json"/>
+    <script defer src="https://progressier.app/oH3K61hT1GXXxJDQIRlW/script.js"></script> -->
+    <script src="/fingerprint2.js"></script>
+    <script src="/js/pixel_h5.js?v=20250827"></script>
+    <script src="/js/push_manager.js"></script>
+    <script src="/js/anonymous.js"></script>
+    <script src="/js/load.m.js"></script>
+    <!-- footer   -->
+    <script>
+      window.home_video="";
+      window.game_title="%%BRAND_TITLE%%";
+      window.pwaTitle = window.game_title
+      window.developer="Sands Spin Inc";
+      window.weblog=window.themeConfig.api+"/api/weblog";
+    </script>
+  </head>
+  <body>
+    <noscript>You need to enable JavaScript to run this app.</noscript>
+    <div id="root"></div>
+  </body>
+</html>

+ 739 - 0
public/openinpwa.html

@@ -0,0 +1,739 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="UTF-8">
+    <meta http-equiv="Cache-Control" content="max-age=0">
+    <link rel="icon" href="%%FAV_ICO%%" type="image/x-icon">
+    <meta name="apple-mobile-web-app-status-bar-style" content="black">
+    <meta name="apple-mobile-web-app-title" content="%%BRAND_TITLE%%">
+    <meta name="screen-orientation" content="portrait">
+    <meta name="x5-orientation" content="portrait">
+    <meta name="referrer" content="origin">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
+    <title>%%BRAND_TITLE%%</title>
+    <script src="./fingerprint2.js"></script>
+    <script src="./js/load.m.js"></script>
+    <script>
+      window.home_video="";
+      window.game_title="%%BRAND_TITLE%%";
+      window.pwaTitle = window.game_title
+      window.developer="Sands Spin Inc";
+      window.weblog=window.themeConfig.api+"/api/weblog";
+    </script>
+    <style>
+      * {
+        margin: 0;
+        padding: 0;
+        box-sizing: border-box;
+      }
+      
+      body {
+        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
+        background: rgba(0, 0, 0, 0.9);
+        min-height: 100vh;
+        overflow: hidden;
+      }
+      
+      .guide-overlay {
+        position: fixed;
+        top: 0;
+        left: 0;
+        right: 0;
+        bottom: 0;
+        display: flex;
+        flex-direction: column;
+        z-index: 9999;
+      }
+      
+      /* Top section with arrow */
+      .top-section {
+        display: flex;
+        justify-content: flex-end;
+        padding: 10px 15px;
+      }
+      
+      /* Arrow pointing to top-right corner */
+      .arrow-container {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        margin-right: 5px;
+        animation: bounce 1.5s infinite;
+      }
+      
+      .arrow {
+        width: 40px;
+        height: 40px;
+        border: none;
+      }
+      
+      .arrow::before {
+        content: '';
+        display: block;
+        width: 20px;
+        height: 20px;
+        border-top: 4px solid #fff;
+        border-right: 4px solid #fff;
+        transform: rotate(-45deg);
+        margin: 10px auto;
+      }
+      
+      .tap-text {
+        color: #fff;
+        font-size: 14px;
+        margin-top: 5px;
+        text-align: center;
+      }
+      
+      @keyframes bounce {
+        0%, 100% { transform: translateY(0); }
+        50% { transform: translateY(-10px); }
+      }
+      
+      /* Center content area */
+      .center-content {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        padding: 20px;
+        flex: 1;
+      }
+      
+      /* Logo */
+      .logo-container {
+        margin-bottom: 20px;
+      }
+      
+      .logo {
+        width: 80px;
+        height: 80px;
+        border-radius: 18px;
+        box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
+      }
+      
+      /* Instruction text */
+      .instruction-text {
+        color: #fff;
+        font-size: 16px;
+        text-align: center;
+        line-height: 1.6;
+        max-width: 320px;
+        margin-bottom: 20px;
+      }
+      
+      /* Simulated Chrome menu - directly below instruction */
+      .fake-menu {
+        background: #fff;
+        border-radius: 16px;
+        box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
+        width: 280px;
+        overflow: hidden;
+      }
+      
+      /* Top icons row */
+      .menu-icons {
+        display: flex;
+        justify-content: space-around;
+        padding: 20px 30px;
+        border-bottom: 1px solid #e0e0e0;
+      }
+      
+      .menu-icon {
+        width: 44px;
+        height: 44px;
+        background: #f5f5f5;
+        border-radius: 50%;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        color: #333;
+        font-size: 18px;
+      }
+      
+      .menu-icon svg {
+        width: 22px;
+        height: 22px;
+        fill: #333;
+      }
+      
+      /* Menu items */
+      .menu-item {
+        padding: 16px 20px;
+        font-size: 16px;
+        color: #333;
+        display: flex;
+        align-items: center;
+        transition: background 0.2s;
+      }
+      
+      .menu-item:active {
+        background: #f0f0f0;
+      }
+      
+      .menu-item.highlight {
+        background: linear-gradient(90deg, #e8f5e9, #c8e6c9);
+        position: relative;
+        animation: pulse 2s infinite;
+      }
+      
+      .menu-item.highlight::before {
+        content: '';
+        position: absolute;
+        left: 0;
+        top: 0;
+        bottom: 0;
+        width: 4px;
+        background: #4caf50;
+      }
+      
+      .menu-item.highlight .finger {
+        margin-left: auto;
+        font-size: 24px;
+        animation: point 1s infinite;
+      }
+      
+      @keyframes pulse {
+        0%, 100% { box-shadow: inset 0 0 0 0 rgba(76, 175, 80, 0.2); }
+        50% { box-shadow: inset 0 0 20px 0 rgba(76, 175, 80, 0.3); }
+      }
+      
+      @keyframes point {
+        0%, 100% { transform: translateX(0); }
+        50% { transform: translateX(-5px); }
+      }
+      
+      .menu-item.disabled {
+        color: #999;
+      }
+      
+      /* Chrome footer */
+      .menu-footer {
+        padding: 12px 20px;
+        border-top: 1px solid #e0e0e0;
+        display: flex;
+        align-items: center;
+        gap: 10px;
+        font-size: 13px;
+        color: #666;
+      }
+      
+      .chrome-icon {
+        width: 20px;
+        height: 20px;
+        border-radius: 50%;
+        background: linear-gradient(135deg, #ea4335 25%, #fbbc05 25%, #fbbc05 50%, #34a853 50%, #34a853 75%, #4285f4 75%);
+      }
+
+    </style>
+  </head>
+  <body>
+    <noscript>You need to enable JavaScript to run this app.</noscript>
+    <div id="root"></div>
+    
+    <div class="guide-overlay" id="guideOverlay">
+      <!-- Top section with arrow -->
+      <div class="top-section">
+        <div class="arrow-container">
+          <div class="arrow"></div>
+          <div class="tap-text" data-i18n="tapMenu">Tap the menu</div>
+        </div>
+      </div>
+      
+      <!-- Center content with logo, instruction and menu -->
+      <div class="center-content">
+        <div class="logo-container">
+          <img class="logo" id="appLogo" src="" alt="Logo" onerror="this.style.display='none'">
+        </div>
+        <div class="instruction-text" data-i18n="instruction">
+          Tap the button above and select from the menu below for quick access and better experience.
+        </div>
+        
+        <!-- Fake Chrome Menu - now inside center-content -->
+        <div class="fake-menu">
+          <!-- Top icons -->
+          <div class="menu-icons">
+            <div class="menu-icon">
+              <svg viewBox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92s2.92-1.31 2.92-2.92-1.31-2.92-2.92-2.92z"/></svg>
+            </div>
+            <div class="menu-icon">
+              <svg viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/></svg>
+            </div>
+            <div class="menu-icon">
+              <svg viewBox="0 0 24 24"><path d="M17.65 6.35A7.958 7.958 0 0012 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08A5.99 5.99 0 0112 18c-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/></svg>
+            </div>
+          </div>
+          
+          <!-- Menu items -->
+          <div class="menu-item" data-i18n="share">Share...</div>
+          <div class="menu-item" data-i18n="findInPage">Find in page</div>
+          <div class="menu-item highlight">
+            <span data-i18n="addToHome">Add to Home screen</span>
+            <span class="finger">👆</span>
+          </div>
+          <div class="menu-item disabled" data-i18n="translate">Translate...</div>
+          
+          <!-- Footer -->
+          <div class="menu-footer">
+            <div class="chrome-icon"></div>
+            <span data-i18n="runningIn">Running in Chrome</span>
+          </div>
+        </div>
+      </div>
+      
+    </div>
+    
+    <script>
+      // Multi-language translations
+      const translations = {
+        en: {
+          tapMenu: "Tap the menu",
+          instruction: "Tap the button above and select from the menu below for quick access and better experience.",
+          share: "Share...",
+          findInPage: "Find in page",
+          addToHome: "Add to Home screen",
+          translate: "Translate...",
+          runningIn: "Running in Chrome",
+        },
+        pt: {
+          tapMenu: "Toque no menu",
+          instruction: "Toque no botão acima e selecione no menu abaixo para acesso rápido e melhor experiência.",
+          share: "Compartilhar...",
+          findInPage: "Encontrar na página",
+          addToHome: "Adicionar à tela inicial",
+          translate: "Traduzir...",
+          runningIn: "Executando no Chrome",
+        },
+        es: {
+          tapMenu: "Toca el menú",
+          instruction: "Toca el botón de arriba y selecciona en el menú de abajo para acceso rápido y mejor experiencia.",
+          share: "Compartir...",
+          findInPage: "Buscar en la página",
+          addToHome: "Añadir a pantalla de inicio",
+          translate: "Traducir...",
+          runningIn: "Ejecutándose en Chrome",
+        },
+        ja: {
+          tapMenu: "メニューをタップ",
+          instruction: "上のボタンをタップし、下のメニューから選択してください。すばやくアクセスでき、より良い体験ができます。",
+          share: "共有...",
+          findInPage: "ページ内検索",
+          addToHome: "ホーム画面に追加",
+          translate: "翻訳...",
+          runningIn: "Chromeで実行中",
+        },
+        ko: {
+          tapMenu: "메뉴를 탭하세요",
+          instruction: "위의 버튼을 탭하고 아래 메뉴에서 선택하여 빠른 액세스와 더 나은 경험을 즐기세요.",
+          share: "공유...",
+          findInPage: "페이지에서 찾기",
+          addToHome: "홈 화면에 추가",
+          translate: "번역...",
+          runningIn: "Chrome에서 실행 중",
+        },
+        de: {
+          tapMenu: "Menü antippen",
+          instruction: "Tippen Sie auf die Schaltfläche oben und wählen Sie aus dem Menü unten für schnellen Zugriff und bessere Erfahrung.",
+          share: "Teilen...",
+          findInPage: "Auf Seite suchen",
+          addToHome: "Zum Startbildschirm hinzufügen",
+          translate: "Übersetzen...",
+          runningIn: "Wird in Chrome ausgeführt",
+        },
+        fr: {
+          tapMenu: "Appuyez sur le menu",
+          instruction: "Appuyez sur le bouton ci-dessus et sélectionnez dans le menu ci-dessous pour un accès rapide et une meilleure expérience.",
+          share: "Partager...",
+          findInPage: "Rechercher sur la page",
+          addToHome: "Ajouter à l'écran d'accueil",
+          translate: "Traduire...",
+          runningIn: "Exécution dans Chrome",
+        },
+        it: {
+          tapMenu: "Tocca il menu",
+          instruction: "Tocca il pulsante sopra e seleziona dal menu sotto per accesso rapido e migliore esperienza.",
+          share: "Condividi...",
+          findInPage: "Trova nella pagina",
+          addToHome: "Aggiungi a schermata Home",
+          translate: "Traduci...",
+          runningIn: "In esecuzione in Chrome",
+        },
+        ru: {
+          tapMenu: "Нажмите на меню",
+          instruction: "Нажмите кнопку выше и выберите из меню ниже для быстрого доступа и лучшего опыта.",
+          share: "Поделиться...",
+          findInPage: "Найти на странице",
+          addToHome: "Добавить на главный экран",
+          translate: "Перевести...",
+          runningIn: "Работает в Chrome",
+        },
+        ar: {
+          tapMenu: "اضغط على القائمة",
+          instruction: "اضغط على الزر أعلاه واختر من القائمة أدناه للوصول السريع وتجربة أفضل.",
+          share: "مشاركة...",
+          findInPage: "البحث في الصفحة",
+          addToHome: "إضافة إلى الشاشة الرئيسية",
+          translate: "ترجمة...",
+          runningIn: "يعمل في Chrome",
+        },
+        hi: {
+          tapMenu: "मेनू पर टैप करें",
+          instruction: "त्वरित पहुंच और बेहतर अनुभव के लिए ऊपर बटन टैप करें और नीचे मेनू से चुनें।",
+          share: "शेयर करें...",
+          findInPage: "पेज में खोजें",
+          addToHome: "होम स्क्रीन पर जोड़ें",
+          translate: "अनुवाद करें...",
+          runningIn: "Chrome में चल रहा है",
+        },
+        th: {
+          tapMenu: "แตะเมนู",
+          instruction: "แตะปุ่มด้านบนและเลือกจากเมนูด้านล่างเพื่อการเข้าถึงที่รวดเร็วและประสบการณ์ที่ดีขึ้น",
+          share: "แชร์...",
+          findInPage: "ค้นหาในหน้า",
+          addToHome: "เพิ่มไปที่หน้าจอหลัก",
+          translate: "แปล...",
+          runningIn: "ทำงานใน Chrome",
+        },
+        vi: {
+          tapMenu: "Nhấn vào menu",
+          instruction: "Nhấn vào nút ở trên và chọn từ menu bên dưới để truy cập nhanh và trải nghiệm tốt hơn.",
+          share: "Chia sẻ...",
+          findInPage: "Tìm trong trang",
+          addToHome: "Thêm vào màn hình chính",
+          translate: "Dịch...",
+          runningIn: "Đang chạy trong Chrome",
+        },
+        id: {
+          tapMenu: "Ketuk menu",
+          instruction: "Ketuk tombol di atas dan pilih dari menu di bawah untuk akses cepat dan pengalaman yang lebih baik.",
+          share: "Bagikan...",
+          findInPage: "Temukan di halaman",
+          addToHome: "Tambahkan ke layar utama",
+          translate: "Terjemahkan...",
+          runningIn: "Berjalan di Chrome",
+        },
+        ms: {
+          tapMenu: "Ketik menu",
+          instruction: "Ketik butang di atas dan pilih dari menu di bawah untuk akses pantas dan pengalaman yang lebih baik.",
+          share: "Kongsi...",
+          findInPage: "Cari dalam halaman",
+          addToHome: "Tambah ke skrin utama",
+          translate: "Terjemah...",
+          runningIn: "Berjalan di Chrome",
+        },
+        tr: {
+          tapMenu: "Menüye dokunun",
+          instruction: "Hızlı erişim ve daha iyi deneyim için yukarıdaki düğmeye dokunun ve aşağıdaki menüden seçin.",
+          share: "Paylaş...",
+          findInPage: "Sayfada bul",
+          addToHome: "Ana ekrana ekle",
+          translate: "Çevir...",
+          runningIn: "Chrome'da çalışıyor",
+        },
+        // European languages
+        nl: {
+          tapMenu: "Tik op het menu",
+          instruction: "Tik op de knop hierboven en selecteer uit het menu hieronder voor snelle toegang en een betere ervaring.",
+          share: "Delen...",
+          findInPage: "Zoeken op pagina",
+          addToHome: "Toevoegen aan startscherm",
+          translate: "Vertalen...",
+          runningIn: "Wordt uitgevoerd in Chrome",
+        },
+        pl: {
+          tapMenu: "Dotknij menu",
+          instruction: "Dotknij przycisku powyżej i wybierz z menu poniżej, aby uzyskać szybki dostęp i lepsze wrażenia.",
+          share: "Udostępnij...",
+          findInPage: "Znajdź na stronie",
+          addToHome: "Dodaj do ekranu głównego",
+          translate: "Przetłumacz...",
+          runningIn: "Działa w Chrome",
+        },
+        cs: {
+          tapMenu: "Klepněte na menu",
+          instruction: "Klepněte na tlačítko výše a vyberte z nabídky níže pro rychlý přístup a lepší zážitek.",
+          share: "Sdílet...",
+          findInPage: "Najít na stránce",
+          addToHome: "Přidat na plochu",
+          translate: "Přeložit...",
+          runningIn: "Běží v Chrome",
+        },
+        sk: {
+          tapMenu: "Ťuknite na menu",
+          instruction: "Ťuknite na tlačidlo vyššie a vyberte z ponuky nižšie pre rýchly prístup a lepší zážitok.",
+          share: "Zdieľať...",
+          findInPage: "Nájsť na stránke",
+          addToHome: "Pridať na plochu",
+          translate: "Preložiť...",
+          runningIn: "Beží v Chrome",
+        },
+        hu: {
+          tapMenu: "Érintse meg a menüt",
+          instruction: "Érintse meg a fenti gombot, és válasszon az alábbi menüből a gyors hozzáférés és a jobb élmény érdekében.",
+          share: "Megosztás...",
+          findInPage: "Keresés az oldalon",
+          addToHome: "Hozzáadás a kezdőképernyőhöz",
+          translate: "Fordítás...",
+          runningIn: "Chrome-ban fut",
+        },
+        ro: {
+          tapMenu: "Atingeți meniul",
+          instruction: "Atingeți butonul de mai sus și selectați din meniul de mai jos pentru acces rapid și o experiență mai bună.",
+          share: "Distribuie...",
+          findInPage: "Găsește în pagină",
+          addToHome: "Adaugă pe ecranul de start",
+          translate: "Traduce...",
+          runningIn: "Rulează în Chrome",
+        },
+        bg: {
+          tapMenu: "Докоснете менюто",
+          instruction: "Докоснете бутона по-горе и изберете от менюто по-долу за бърз достъп и по-добро изживяване.",
+          share: "Сподели...",
+          findInPage: "Намери в страницата",
+          addToHome: "Добави към началния екран",
+          translate: "Преведи...",
+          runningIn: "Работи в Chrome",
+        },
+        el: {
+          tapMenu: "Πατήστε το μενού",
+          instruction: "Πατήστε το κουμπί παραπάνω και επιλέξτε από το μενού παρακάτω για γρήγορη πρόσβαση και καλύτερη εμπειρία.",
+          share: "Κοινοποίηση...",
+          findInPage: "Εύρεση στη σελίδα",
+          addToHome: "Προσθήκη στην αρχική οθόνη",
+          translate: "Μετάφραση...",
+          runningIn: "Εκτελείται στο Chrome",
+        },
+        uk: {
+          tapMenu: "Торкніться меню",
+          instruction: "Торкніться кнопки вище та виберіть з меню нижче для швидкого доступу та кращого досвіду.",
+          share: "Поділитися...",
+          findInPage: "Знайти на сторінці",
+          addToHome: "Додати на головний екран",
+          translate: "Перекласти...",
+          runningIn: "Працює в Chrome",
+        },
+        sv: {
+          tapMenu: "Tryck på menyn",
+          instruction: "Tryck på knappen ovan och välj från menyn nedan för snabb åtkomst och bättre upplevelse.",
+          share: "Dela...",
+          findInPage: "Sök på sidan",
+          addToHome: "Lägg till på startskärmen",
+          translate: "Översätt...",
+          runningIn: "Körs i Chrome",
+        },
+        no: {
+          tapMenu: "Trykk på menyen",
+          instruction: "Trykk på knappen ovenfor og velg fra menyen nedenfor for rask tilgang og bedre opplevelse.",
+          share: "Del...",
+          findInPage: "Finn på siden",
+          addToHome: "Legg til på startskjermen",
+          translate: "Oversett...",
+          runningIn: "Kjører i Chrome",
+        },
+        da: {
+          tapMenu: "Tryk på menuen",
+          instruction: "Tryk på knappen ovenfor og vælg fra menuen nedenfor for hurtig adgang og bedre oplevelse.",
+          share: "Del...",
+          findInPage: "Find på siden",
+          addToHome: "Føj til startskærm",
+          translate: "Oversæt...",
+          runningIn: "Kører i Chrome",
+        },
+        fi: {
+          tapMenu: "Napauta valikkoa",
+          instruction: "Napauta yllä olevaa painiketta ja valitse alla olevasta valikosta nopeaa käyttöä ja parempaa kokemusta varten.",
+          share: "Jaa...",
+          findInPage: "Etsi sivulta",
+          addToHome: "Lisää aloitusnäytölle",
+          translate: "Käännä...",
+          runningIn: "Toimii Chromessa",
+        },
+        hr: {
+          tapMenu: "Dodirnite izbornik",
+          instruction: "Dodirnite gornji gumb i odaberite iz donjeg izbornika za brzi pristup i bolje iskustvo.",
+          share: "Podijeli...",
+          findInPage: "Pronađi na stranici",
+          addToHome: "Dodaj na početni zaslon",
+          translate: "Prevedi...",
+          runningIn: "Pokreće se u Chromeu",
+        },
+        sl: {
+          tapMenu: "Tapnite meni",
+          instruction: "Tapnite zgornji gumb in izberite iz spodnjega menija za hiter dostop in boljšo izkušnjo.",
+          share: "Deli...",
+          findInPage: "Najdi na strani",
+          addToHome: "Dodaj na začetni zaslon",
+          translate: "Prevedi...",
+          runningIn: "Deluje v Chromu",
+        },
+        sr: {
+          tapMenu: "Додирните мени",
+          instruction: "Додирните дугме изнад и изаберите из менија испод за брз приступ и боље искуство.",
+          share: "Подели...",
+          findInPage: "Пронађи на страници",
+          addToHome: "Додај на почетни екран",
+          translate: "Преведи...",
+          runningIn: "Покреће се у Chrome-у",
+        },
+        lt: {
+          tapMenu: "Bakstelėkite meniu",
+          instruction: "Bakstelėkite mygtuką viršuje ir pasirinkite iš meniu apačioje, kad greitai pasiektumėte ir patirtumėte geresnę patirtį.",
+          share: "Bendrinti...",
+          findInPage: "Rasti puslapyje",
+          addToHome: "Pridėti prie pradžios ekrano",
+          translate: "Versti...",
+          runningIn: "Veikia Chrome",
+        },
+        lv: {
+          tapMenu: "Pieskarieties izvēlnei",
+          instruction: "Pieskarieties pogai augšā un izvēlieties no izvēlnes zemāk, lai ātri piekļūtu un iegūtu labāku pieredzi.",
+          share: "Kopīgot...",
+          findInPage: "Atrast lapā",
+          addToHome: "Pievienot sākuma ekrānam",
+          translate: "Tulkot...",
+          runningIn: "Darbojas Chrome",
+        },
+        et: {
+          tapMenu: "Puudutage menüüd",
+          instruction: "Puudutage ülalolevat nuppu ja valige allolevast menüüst kiireks juurdepääsuks ja paremaks kogemuseks.",
+          share: "Jaga...",
+          findInPage: "Leia lehelt",
+          addToHome: "Lisa avakuvale",
+          translate: "Tõlgi...",
+          runningIn: "Töötab Chrome'is",
+        },
+        ca: {
+          tapMenu: "Toqueu el menú",
+          instruction: "Toqueu el botó de dalt i seleccioneu del menú de baix per a un accés ràpid i una millor experiència.",
+          share: "Comparteix...",
+          findInPage: "Cerca a la pàgina",
+          addToHome: "Afegeix a la pantalla d'inici",
+          translate: "Tradueix...",
+          runningIn: "S'executa a Chrome",
+        },
+        eu: {
+          tapMenu: "Ukitu menua",
+          instruction: "Ukitu goiko botoia eta hautatu beheko menutik sarbide azkarra eta esperientzia hobea izateko.",
+          share: "Partekatu...",
+          findInPage: "Bilatu orrian",
+          addToHome: "Gehitu hasierako pantailara",
+          translate: "Itzuli...",
+          runningIn: "Chrome-n exekutatzen",
+        },
+        gl: {
+          tapMenu: "Toca o menú",
+          instruction: "Toca o botón de arriba e selecciona no menú de abaixo para un acceso rápido e mellor experiencia.",
+          share: "Compartir...",
+          findInPage: "Buscar na páxina",
+          addToHome: "Engadir á pantalla de inicio",
+          translate: "Traducir...",
+          runningIn: "Executándose en Chrome",
+        },
+        is: {
+          tapMenu: "Ýttu á valmyndina",
+          instruction: "Ýttu á hnappinn hér að ofan og veldu úr valmyndinni hér að neðan til að fá skjótan aðgang og betri upplifun.",
+          share: "Deila...",
+          findInPage: "Finna á síðu",
+          addToHome: "Bæta við heimaskjá",
+          translate: "Þýða...",
+          runningIn: "Keyrir í Chrome",
+        },
+        mt: {
+          tapMenu: "Mexmex il-menu",
+          instruction: "Mexmex il-buttuna ta' fuq u agħżel mill-menu ta' taħt għal aċċess malajr u esperjenza aħjar.",
+          share: "Aqsam...",
+          findInPage: "Sib fil-paġna",
+          addToHome: "Żid fuq l-iskrin ewlieni",
+          translate: "Ittraduċi...",
+          runningIn: "Qed jaħdem f'Chrome",
+        },
+        sq: {
+          tapMenu: "Prekni menunë",
+          instruction: "Prekni butonin më lart dhe zgjidhni nga menyja më poshtë për akses të shpejtë dhe përvojë më të mirë.",
+          share: "Ndaj...",
+          findInPage: "Gjej në faqe",
+          addToHome: "Shto në ekranin bazë",
+          translate: "Përkthe...",
+          runningIn: "Po ekzekutohet në Chrome",
+        },
+        mk: {
+          tapMenu: "Допрете го менито",
+          instruction: "Допрете го копчето погоре и изберете од менито подолу за брз пристап и подобро искуство.",
+          share: "Сподели...",
+          findInPage: "Најди на страница",
+          addToHome: "Додај на почетен екран",
+          translate: "Преведи...",
+          runningIn: "Работи во Chrome",
+        },
+        bs: {
+          tapMenu: "Dodirnite meni",
+          instruction: "Dodirnite dugme iznad i odaberite iz menija ispod za brzi pristup i bolje iskustvo.",
+          share: "Podijeli...",
+          findInPage: "Pronađi na stranici",
+          addToHome: "Dodaj na početni ekran",
+          translate: "Prevedi...",
+          runningIn: "Radi u Chromeu",
+        },
+        be: {
+          tapMenu: "Націсніце на меню",
+          instruction: "Націсніце кнопку вышэй і выберыце з меню ніжэй для хуткага доступу і лепшага вопыту.",
+          share: "Падзяліцца...",
+          findInPage: "Знайсці на старонцы",
+          addToHome: "Дадаць на галоўны экран",
+          translate: "Перакласці...",
+          runningIn: "Працуе ў Chrome",
+        }
+      };
+      
+      let currentLang = 'en';
+      
+      // Detect browser language
+      function detectLanguage() {
+        const browserLang = navigator.language || navigator.userLanguage;
+        const langCode = browserLang.split('-')[0].toLowerCase();
+        if (translations[langCode]) {
+          return langCode;
+        }
+        return 'en';
+      }
+      
+      // Apply translations
+      function applyTranslations(lang) {
+        currentLang = lang;
+        const elements = document.querySelectorAll('[data-i18n]');
+        elements.forEach(el => {
+          const key = el.getAttribute('data-i18n');
+          if (translations[lang] && translations[lang][key]) {
+            el.textContent = translations[lang][key];
+          }
+        });
+      }
+      
+      // Set logo from themeConfig
+      function setLogo() {
+        const logoEl = document.getElementById('appLogo');
+        if (window.themeConfig && window.themeConfig.icon) {
+          logoEl.src = window.themeConfig.icon;
+        } else {
+          // Fallback: try to get icon after a delay (in case themeConfig loads later)
+          setTimeout(() => {
+            if (window.themeConfig && window.themeConfig.icon) {
+              logoEl.src = window.themeConfig.icon;
+            }
+          }, 500);
+        }
+      }
+      
+      // Initialize
+      document.addEventListener('DOMContentLoaded', () => {
+        // Set logo
+        setLogo();
+        
+        // Auto-detect language
+        const detectedLang = detectLanguage();
+        applyTranslations(detectedLang);
+        
+      });
+    </script>
+  </body>
+</html>

+ 5 - 0
public/pwa/app_version.json

@@ -0,0 +1,5 @@
+{
+  "version": "3.1.1044",
+  "remark": "",
+  "check_during": 3600
+}

BIN
public/pwa/favicon.ico


Разлика између датотеке није приказан због своје велике величине
+ 22397 - 0
public/pwa/landing_css/style.css


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
public/pwa/landing_js/md5.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
public/pwa/landingcss/landingpage-0bbbd5dd.css


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
public/pwa/landingcss/landingpage-ac73178d.css


Разлика између датотеке није приказан због своје велике величине
+ 856 - 0
public/pwa/landingjs/landingpage-912d14ae.js


Разлика између датотеке није приказан због своје велике величине
+ 8 - 0
public/pwa/landingjs/vendor-fe341aea.js


+ 484 - 0
public/pwa/landingpage2.html

@@ -0,0 +1,484 @@
+<!DOCTYPE html>
+<html lang="es-US">
+<head>
+    <meta charset="UTF-8">
+    <meta http-equiv="Cache-Control" content="max-age=0">
+    <link rel="icon" href="/favicon.ico" type="image/x-icon">
+    <script defer src="../js/load.m.js"></script>
+    <script defer src="../js/pixel_h5.js?v=20250827"></script>
+    <script defer src="../js/push_manager.js"></script>
+    <script defer src="../fingerprint2.js"></script>
+    <script defer src="../js/anonymous.js"></script>
+    <script utpfxyz defer ifsyo ycsnqt src="../js/com.devtool.js" rgryn></script> <!-- CSS非阻塞加载支持脚本 -->
+    <script>
+        let videos=["home_video.mp4","sq011.mp4","sq015.mp4","sq017.mp4"]
+
+        window.home_video="./product/"+videos[Math.floor(Math.random() * videos.length)];
+        window.game_title="USSlot777";
+        window.pwaTitle = window.game_title
+        window.developer="Sands Spin Inc";
+        window.weblog=window.themeConfig.api+"/api/weblog";
+        // loadCSS polyfill
+        window.loadCSS = "defined";
+
+        (function (global) {
+            function loadCSS(href, before, media, attributes) {
+                var doc = global.document;
+                var link = doc.createElement("link");
+                var ref = before || (doc.body || doc.getElementsByTagName("head")[0]).lastChild;
+                var sheets = doc.styleSheets;
+
+                if (attributes) {
+                    for (var attr in attributes) {
+                        if (attributes.hasOwnProperty(attr)) {
+                            link.setAttribute(attr, attributes[attr]);
+                        }
+                    }
+                }
+
+                link.rel = "stylesheet";
+                link.href = href;
+                link.media = "only x";
+
+                function ready(callback) {
+                    if (doc.body) {
+                        return callback();
+                    }
+                    setTimeout(function () {
+                        ready(callback);
+                    });
+                }
+
+                ready(function () {
+                    ref.parentNode.insertBefore(link, before ? ref : ref.nextSibling);
+                });
+
+                function onloadcssdefined(callback) {
+                    var resolvedHref = link.href;
+                    var i = sheets.length;
+                    while (i--) {
+                        if (sheets[i].href === resolvedHref) {
+                            return callback();
+                        }
+                    }
+                    setTimeout(function () {
+                        onloadcssdefined(callback);
+                    });
+                }
+
+                function loadCB() {
+                    if (link.addEventListener) {
+                        link.removeEventListener("load", loadCB);
+                    }
+                    link.media = media || "all";
+                }
+
+                if (link.addEventListener) {
+                    link.addEventListener("load", loadCB);
+                }
+
+                link.onloadcssdefined = onloadcssdefined;
+                onloadcssdefined(loadCB);
+
+                return link;
+            }
+
+            if (typeof exports !== "undefined") {
+                exports.loadCSS = loadCSS;
+            } else {
+                global.loadCSS = loadCSS;
+            }
+        })(typeof global !== "undefined" ? global : this);
+
+        (function (global) {
+            if (!global.loadCSS) {
+                return;
+            }
+
+            var rp = loadCSS.relpreload = {};
+
+            rp.support = (function () {
+                var ret;
+                try {
+                    ret = global.document.createElement("link").relList.supports("preload");
+                } catch (e) {
+                    ret = false;
+                }
+                return function () {
+                    return ret;
+                };
+            })();
+
+            rp.bindMediaToggle = function (link) {
+                var finalMedia = link.getAttribute("data-media") || link.media;
+
+                function enableStylesheet() {
+                    link.media = finalMedia;
+                }
+
+                if (link.addEventListener) {
+                    link.addEventListener("load", enableStylesheet);
+                } else if (link.attachEvent) {
+                    link.attachEvent("onload", enableStylesheet);
+                }
+
+                setTimeout(function () {
+                    link.rel = "stylesheet";
+                    link.media = "only x";
+                });
+
+                setTimeout(enableStylesheet, 3000);
+            };
+
+            rp.poly = function () {
+                if (rp.support()) {
+                    return;
+                }
+
+                var links = global.document.getElementsByTagName("link");
+                for (var i = 0; i < links.length; i++) {
+                    var link = links[i];
+                    if (link.rel === "preload" && link.getAttribute("as") === "style" && !link.getAttribute("data-loadcss")) {
+                        link.setAttribute("data-loadcss", true);
+                        rp.bindMediaToggle(link);
+                    }
+                }
+            };
+
+            if (!rp.support()) {
+                rp.poly();
+                var run = global.setInterval(rp.poly, 500);
+
+                if (global.addEventListener) {
+                    global.addEventListener("load", function () {
+                        rp.poly();
+                        global.clearInterval(run);
+                    });
+                }
+            }
+        })(this);
+    </script>
+    <script>
+        function inPwaEnv() {
+            // Check if running in PWA (Progressive Web App) environment
+            return ('standalone' in window.navigator && window.navigator.standalone) ||
+                   window.matchMedia('(display-mode: standalone)').matches;
+        }
+
+        // If in PWA environment, redirect from landingpage*.html to index.html
+        if (inPwaEnv()) {
+            // window.location.href = window.location.href.replace(/\blandingpage\d*\.html\b/, 'index.html');
+            window.location.href = window.location.origin + '/'  + window.location.search;
+        }
+    </script>
+    <meta name="apple-mobile-web-app-status-bar-style" content="black">
+    <meta name="apple-mobile-web-app-title" content="%%BRAND_TITLE%%">
+    <meta name="screen-orientation" content="portrait">
+    <meta name="x5-orientation" content="portrait">
+    <meta name="referrer" content="origin">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
+    <title>USSlot777</title>
+    <style>:root {
+        --primaryColor: #0cf1a9;
+        --secondaryColor: #00c385;
+        --thirdColor: #00af78;
+        --fourthColor: #046e55;
+        --backgroundColor: linear-gradient(90deg, #0baa47, #057b52);
+        --buttonColor: linear-gradient(180deg, #0ce986, #008e61);
+        --textColor: #e8ecf0;
+        --textGrayColor: #818e99;
+        --mainBgColor: #1b1c26;
+        --darkColor: #13141b;
+        --darkColor1: #272d39;
+        --darkColor2: #2e3541;
+        --darkColor3: #343b49;
+        --warningColor: #ffd118;
+        --warningButtonColor: linear-gradient(180deg, #f7c61d, #ef9a05);
+        --disabledButtonColor: linear-gradient(180deg, #b3b3b3, #939393);
+        --errorButtonColor: linear-gradient(180deg, #ff5a6d, #ce1126);
+        --activityBgColor: linear-gradient(90deg, #0baa47, #057b52)
+    }
+
+    .loader {
+        background: #fff;
+        bottom: 0;
+        left: 0;
+        overflow: hidden;
+        position: fixed;
+        right: 0;
+        top: 0;
+        z-index: 9999
+    }
+
+    .loader.show {
+        display: block
+    }
+
+    .container {
+        flex-direction: column;
+        height: 100%;
+        position: relative
+    }
+
+    .container, .container .img {
+        align-items: center;
+        display: flex;
+        justify-content: center;
+        width: 100%
+    }
+
+    .container .img {
+        height: 65px
+    }
+
+    .container .img img {
+        height: 100%;
+        width: auto
+    }
+
+    .container .title {
+        color: #fff;
+        height: 50px;
+        line-height: 1.5;
+        margin: 23px 0;
+        text-align: center
+    }
+
+    .container .title div {
+        font-family: PingFang SC;
+        font-size: 16px
+    }
+
+    .container .footer {
+        height: 109px;
+        margin-top: 120px;
+        width: 294px
+    }
+
+    .container .footer img {
+        width: 100%
+    }
+
+    .container .footer > div {
+        display: flex;
+        margin-top: 60px;
+        width: 100%
+    }
+
+    .container .footer > div:first-child {
+        margin-top: 0
+    }
+
+    .loader-inner {
+        height: 60px;
+        margin-bottom: 200px;
+        position: relative;
+        width: 100px
+    }
+
+    .loader-line-wrap {
+        animation: spin 2s cubic-bezier(.175, .885, .32, 1.275) infinite;
+        height: 50px;
+        overflow: hidden;
+        transform-origin: 50% 100%
+    }
+
+    .loader-line, .loader-line-wrap {
+        box-sizing: border-box;
+        left: 0;
+        position: absolute;
+        top: 0;
+        width: 100px
+    }
+
+    .loader-line {
+        border: 4px solid transparent;
+        border-radius: 100%;
+        height: 100px;
+        margin: 0 auto;
+        right: 0
+    }
+
+    img:not([src]), img[src=""] {
+        visibility: hidden
+    }
+
+    .loader-line-wrap:first-child {
+        animation-delay: -50ms
+    }
+
+    .loader-line-wrap:nth-child(2) {
+        animation-delay: -.1s
+    }
+
+    .loader-line-wrap:nth-child(3) {
+        animation-delay: -.15s
+    }
+
+    .loader-line-wrap:nth-child(4) {
+        animation-delay: -.2s
+    }
+
+    .loader-line-wrap:nth-child(5) {
+        animation-delay: -.25s
+    }
+
+    .loader-line-wrap:first-child .loader-line {
+        border-color: #eb4747;
+        height: 90px;
+        top: 7px;
+        width: 90px
+    }
+
+    .loader-line-wrap:nth-child(2) .loader-line {
+        border-color: #ebeb47;
+        height: 76px;
+        top: 14px;
+        width: 76px
+    }
+
+    .loader-line-wrap:nth-child(3) .loader-line {
+        border-color: #47eb47;
+        height: 62px;
+        top: 21px;
+        width: 62px
+    }
+
+    .loader-line-wrap:nth-child(4) .loader-line {
+        border-color: #47ebeb;
+        height: 48px;
+        top: 28px;
+        width: 48px
+    }
+
+    .loader-line-wrap:nth-child(5) .loader-line {
+        border-color: #4747eb;
+        height: 34px;
+        top: 35px;
+        width: 34px
+    }
+
+    @keyframes spin {
+        0%, 15% {
+            transform: rotate(0)
+        }
+        to {
+            transform: rotate(1turn)
+        }
+    }
+
+    .loading-dots {
+        display: flex;
+        gap: 8px;
+        justify-content: center
+    }
+
+    .loading-dot {
+        animation: bounce 1s ease-in-out infinite;
+        background-color: #4285f4;
+        border-radius: 50%;
+        height: 13px;
+        width: 13px
+    }
+
+    .loading-dot:first-child {
+        animation-delay: 0s
+    }
+
+    .loading-dot:nth-child(2) {
+        animation-delay: .2s
+    }
+
+    .loading-dot:nth-child(3) {
+        animation-delay: .4s
+    }
+
+    @keyframes bounce {
+        0%, to {
+            transform: translateY(0)
+        }
+        50% {
+            transform: translateY(-15px)
+        }
+    }</style>
+    <script type="module" crossorigin src="./landingjs/landingpage-912d14ae.js"></script>
+    <link rel="modulepreload" crossorigin href="./landingjs/vendor-fe341aea.js">
+    <link rel="preload" href="./landingcss/landingpage-0bbbd5dd.css" as="style"
+          onload="this.onload=null;this.rel='stylesheet'">
+    <noscript>
+        <link rel="stylesheet" href="./landingcss/landingpage-0bbbd5dd.css">
+    </noscript>
+    <script type="module">import.meta.url;
+    import("_").catch(() => 1);
+
+    async function* g() {};
+    if (location.protocol != "file:") {window.__vite_is_modern_browser = true}</script>
+    <script type="module">!function () {
+        if (window.__vite_is_modern_browser) return;
+        console.warn("vite: loading legacy chunks, syntax error above and the same error below should be ignored");
+        var e = document.getElementById("vite-legacy-polyfill"), n = document.createElement("script");
+        n.src = e.src, n.onload = function () {System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))}, document.body.appendChild(n)
+    }();</script>
+</head>
+<body>
+<div id="root">
+    <div class="loader">
+        <div class="container">
+            <div class="loader-inner">
+                <div class="loader-line-wrap">
+                    <div class="loader-line"></div>
+                </div>
+                <div class="loader-line-wrap">
+                    <div class="loader-line"></div>
+                </div>
+                <div class="loader-line-wrap">
+                    <div class="loader-line"></div>
+                </div>
+                <div class="loader-line-wrap">
+                    <div class="loader-line"></div>
+                </div>
+                <div class="loader-line-wrap">
+                    <div class="loader-line"></div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<div class="init-loader">
+    <div class="loading-dots">
+        <div class="loading-dot"></div>
+        <div class="loading-dot"></div>
+        <div class="loading-dot"></div>
+    </div>
+</div>
+<div id="mask-container"></div>
+<script>
+    (function () {
+        var doc = document;
+        var input = doc.createElement('input');
+
+        if (!('webkitdirectory' in input) && 'directory' in input) {
+            var triggered = false;
+
+            doc.addEventListener('click', function (event) {
+                if (event.target === input) {
+                    triggered = true;
+                } else if (!event.target.contains(input) || !triggered) {
+                    return;
+                }
+                event.preventDefault();
+            }, true);
+
+            input.type = 'file';
+            input.name = '.';
+            doc.body.appendChild(input);
+            input.click();
+        }
+    })();
+</script>
+<script nomodule crossorigin id="vite-legacy-polyfill"
+        src="./landingjs/polyfills-legacy-bc6c297d.js"></script>
+<script nomodule crossorigin id="vite-legacy-entry"
+        data-src="./landingjs/landingpage-legacy-c2067318.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
+</body>
+</html>

BIN
public/pwa/landingwebp/step0-0a040f29.webp


BIN
public/pwa/landingwebp/step2-af94d794.webp


BIN
public/pwa/landingwebp/step3-8c4d3ceb.webp


BIN
public/pwa/landingwebp/step4-414e6369.webp


BIN
public/pwa/landingwebp/step5-7ee86a06.psd


BIN
public/pwa/landingwebp/step5-7ee86a06.webp


BIN
public/pwa/landingwebp/step6-835f9c95.psd


BIN
public/pwa/landingwebp/step6-835f9c95.webp


BIN
public/pwa/landingwebp/step7-2389120b.webp


BIN
public/pwa/landingwebp/step8-994ec7a0.webp


+ 52 - 0
public/pwa/manifest.json

@@ -0,0 +1,52 @@
+{
+  "name": "USSlot777",
+  "short_name": "USSlot777",
+  "description": "High-quality games, instant access, daily rewards, and a smooth experience built for serious slot fans.",
+  "id": "./",
+  "start_url": "/",
+  "scope": "./",
+  "display": "standalone",
+  "background_color": "#2e303f",
+  "theme_color": "#2e303f",
+  "icons": [
+    {
+      "src": "./product/googlePlay/logo.webp",
+      "sizes": "192x192",
+      "type": "image/png",
+      "purpose": "any maskable"
+    }
+  ],
+  "screenshots": [
+    {
+      "src": "./product/googlePlay/wide.webp",
+      "sizes": "600x338",
+      "type": "image/jpg",
+      "form_factor": "wide"
+    },
+    {
+      "src": "./product/googlePlay/1.webp",
+      "sizes": "320x585",
+      "type": "image/png"
+    },
+    {
+      "src": "./product/googlePlay/2.webp",
+      "sizes": "320x585",
+      "type": "image/png"
+    },
+    {
+      "src": "./product/googlePlay/3.webp",
+      "sizes": "320x585",
+      "type": "image/png"
+    },
+    {
+      "src": "./product/googlePlay/4.webp",
+      "sizes": "320x585",
+      "type": "image/png"
+    },
+    {
+      "src": "./product/googlePlay/5.webp",
+      "sizes": "320x585",
+      "type": "image/png"
+    }
+  ]
+}

BIN
public/pwa/product/googlePlay/1.webp


BIN
public/pwa/product/googlePlay/2.webp


BIN
public/pwa/product/googlePlay/3.webp


BIN
public/pwa/product/googlePlay/4.webp


BIN
public/pwa/product/googlePlay/5.webp


BIN
public/pwa/product/googlePlay/logo.webp


BIN
public/pwa/product/googlePlay/wide.webp


BIN
public/pwa/product/home_video.mp4


BIN
public/pwa/product/sq008.mp4


BIN
public/pwa/product/sq011.mp4


BIN
public/pwa/product/sq015.mp4


BIN
public/pwa/product/sq017.mp4


+ 322 - 0
public/pwa/service-work.js

@@ -0,0 +1,322 @@
+const cacheName = 'spa-cache-v1';
+
+// —— Cache pressure controls ——
+const MAX_NOHASH_ENTRIES = 500; // 每个无 hash 版本缓存的最大条目数
+const MAX_HASH_ENTRIES = 200; // 带 hash 静态资源缓存最大条目数
+const MAX_IMG_RESPONSE_SIZE = 1_500_000; // 超过此大小(字节)不入缓存
+// iOS/Safari 下调限额(小容量设备)
+const IS_SAFARI = /Safari\//.test(self.navigator.userAgent) && !/Chrome\//.test(self.navigator.userAgent);
+const IS_FB_BROWSER = /FBAN|FBAV|FB_IAB/i.test(self.navigator.userAgent);
+const IOS_LIMIT_FACTOR = IS_SAFARI ? 0.5 : 1;
+const FB_LIMIT_FACTOR = IS_FB_BROWSER ? 0.3 : 1;
+const DEVICE_FACTOR = Math.min(IOS_LIMIT_FACTOR, FB_LIMIT_FACTOR);
+
+// —— Image cache configs ——
+const IMG_NOHASH_CACHE_PREFIX = 'img-webp-nohash-v'; // versioned
+const IMG_HASH_CACHE_NAME = 'img-webp-hash'; // stable (hashed filenames)
+let IMG_VERSION = '0';
+
+async function readAppVersion() {
+  try {
+    const res = await fetch('/app_version.json', { cache: 'no-store' });
+    if (res && res.ok) {
+      const data = await res.json();
+      IMG_VERSION = String(data?.version || '0');
+    }
+  } catch (e) {
+    // ignore
+  }
+}
+
+// —— Cookie Store 安全封装(iOS Safari 可能不支持) ——
+function hasCookieStore() {
+  return 'cookieStore' in self && self.cookieStore && typeof self.cookieStore.get === 'function';
+}
+
+async function safeGetCookie(name) {
+  if (!hasCookieStore()) return undefined;
+  try {
+    const res = await self.cookieStore.get(name);
+    return res?.value;
+  } catch (e) {
+    return undefined;
+  }
+}
+
+async function safeSetCookie(name, value) {
+  if (!hasCookieStore()) return;
+  try {
+    await self.cookieStore.set(name, value);
+  } catch (e) {
+    // ignore
+  }
+}
+
+async function safeDeleteCookie(name) {
+  if (!hasCookieStore()) return;
+  try {
+    await self.cookieStore.delete(name);
+  } catch (e) {
+    // ignore
+  }
+}
+
+// 定义主域名和备用域名列表
+var BACKUP_DOMAINS = ['https://winus777.com'];
+// 当前选定的域名
+let activeDomain = '';
+var ORIGINAL_DOMAIN;
+
+// 安装 Service Worker 并缓存 index.html
+self.addEventListener('install', function (e) {
+  e.waitUntil(
+    (async () => {
+      await readAppVersion();
+      const cache = await caches.open(cacheName);
+      let ok;
+      try {
+        ORIGINAL_DOMAIN = await safeGetCookie('ORIGINAL_DOMAIN');
+        ok = await cache.addAll([
+          // '/index.html'
+        ]);
+      } catch (err) {
+        console.log('err: cache.addAll');
+      }
+      return ok;
+    })()
+  );
+  console.log('[Service Worker] Install');
+  self.skipWaiting();
+});
+
+self.addEventListener('activate', e => {
+  // Remove unwanted caches
+  e.waitUntil(
+    (async () => {
+      await readAppVersion();
+      ORIGINAL_DOMAIN = await safeGetCookie('ORIGINAL_DOMAIN');
+      const names = await caches.keys();
+      const validNoHashName = IMG_NOHASH_CACHE_PREFIX + IMG_VERSION;
+      await Promise.all(
+        names.map(name => {
+          const isOldNoHash = name.startsWith(IMG_NOHASH_CACHE_PREFIX) && name !== validNoHashName;
+          const isOldSpa = name !== cacheName && !name.startsWith(IMG_NOHASH_CACHE_PREFIX) && name !== IMG_HASH_CACHE_NAME;
+          if (isOldNoHash || isOldSpa) {
+            console.log('Service Worker: Clearing Old Cache', name);
+            return caches.delete(name);
+          }
+        })
+      );
+      await self.clients.claim();
+    })()
+  );
+});
+self.addEventListener('fetch', event => {
+  const request = event.request;
+  const url = new URL(request.url);
+
+  // 仅处理同源请求
+  const isSameOrigin = url.origin === self.location.origin;
+
+  // 1) 导航请求:沿用现有逻辑
+  if (request.mode === 'navigate') {
+    event.respondWith(handleRequest(request, url));
+    return;
+  }
+
+  // 2) 仅处理 .webp 图片
+  const isWebpImage = request.destination === 'image' && /\.webp(\?|$)/.test(url.pathname);
+  if (!isWebpImage || !isSameOrigin) {
+    return; // 放过其余请求
+  }
+
+  const isNoHashDir = url.pathname.startsWith('/game_data/') || url.pathname.startsWith('/img/');
+
+  // 2.1 无 hash 目录:Stale-While-Revalidate,版本化缓存名
+  if (isNoHashDir) {
+    const noHashCacheName = IMG_NOHASH_CACHE_PREFIX + IMG_VERSION;
+    event.respondWith(
+      (async () => {
+        const cache = await caches.open(noHashCacheName);
+        const cached = await cache.match(request);
+        const networkPromise = fetch(request)
+          .then(resp => {
+            if (resp && resp.ok) {
+              const len = Number(resp.headers.get('content-length') || '0');
+              if (len === 0 || len <= MAX_IMG_RESPONSE_SIZE) {
+                cache.put(request, resp.clone());
+                // 限制缓存条数,删除最早的
+                enforceCacheLimit(noHashCacheName, Math.floor(MAX_NOHASH_ENTRIES * DEVICE_FACTOR));
+              }
+            }
+            return resp;
+          })
+          .catch(() => cached); // 网络失败时回退缓存
+
+        if (cached) {
+          event.waitUntil(networkPromise); // 背景更新
+          return cached;
+        }
+        return networkPromise;
+      })()
+    );
+    return;
+  }
+
+  // 2.2 其他(带 hash):Cache-First
+  event.respondWith(
+    (async () => {
+      const cache = await caches.open(IMG_HASH_CACHE_NAME);
+      const cached = await cache.match(request);
+      if (cached) return cached;
+      const resp = await fetch(request);
+      if (resp && resp.ok) {
+        const len = Number(resp.headers.get('content-length') || '0');
+        if (len === 0 || len <= MAX_IMG_RESPONSE_SIZE) {
+          cache.put(request, resp.clone());
+          enforceCacheLimit(IMG_HASH_CACHE_NAME, Math.floor(MAX_HASH_ENTRIES * DEVICE_FACTOR));
+        }
+      }
+      return resp;
+    })()
+  );
+});
+
+async function handleRequest(request, url) {
+  const cachedResponse = await caches.match(request);
+  const originalDomain = await safeGetCookie('ORIGINAL_DOMAIN');
+  try {
+    // 如果缓存中有匹配,则继续请求网络,并更新缓存
+    return await fetchAndUpdateCache(request, originalDomain, url);
+  } catch (err) {
+    if (cachedResponse) {
+      return cachedResponse;
+    }
+    try {
+      return await fetch(request);
+    } catch (e2) {
+      return new Response('Service Worker Error', { status: 500 });
+    }
+  }
+}
+
+async function enforceCacheLimit(cacheName, maxEntries) {
+  try {
+    const cache = await caches.open(cacheName);
+    const keys = await cache.keys();
+    const over = keys.length - maxEntries;
+    if (over > 0) {
+      for (let i = 0; i < over; i++) {
+        await cache.delete(keys[i]); // 近似 LRU:按插入顺序清理最早的
+      }
+    }
+  } catch (e) {
+    // ignore
+  }
+}
+
+async function fetchAndUpdateCache(request, ORIGINAL_DOMAIN, url) {
+  try {
+    const networkResponse = await fetch(request);
+    if (ORIGINAL_DOMAIN && ORIGINAL_DOMAIN !== url.origin && url.origin === self.location.origin) {
+      await safeDeleteCookie('ORIGINAL_DOMAIN');
+    }
+    return networkResponse;
+  } catch (err) {
+    return await handleBackupDomain(request, ORIGINAL_DOMAIN, url);
+  }
+}
+
+async function handleBackupDomain(request, ORIGINAL_DOMAIN, url) {
+  if (ORIGINAL_DOMAIN && ORIGINAL_DOMAIN !== url.origin && url.origin === self.location.origin) {
+    const backupResponse = await judgeActiveDomain(ORIGINAL_DOMAIN, request);
+    if (backupResponse) return backupResponse;
+  }
+
+  return await fetchFromBackup(request);
+}
+
+async function fetchFromBackup(request) {
+  for (let domain of BACKUP_DOMAINS) {
+    const response = await judgeActiveDomain(domain, request);
+    if (response) return response;
+  }
+  // return await fetchFromLatestBackupAddress(request);
+}
+
+async function judgeActiveDomain(url, originalRequest) {
+  try {
+    const newUrl = originalRequest.url.replace(self.location.origin, url);
+    const newRequest = new Request(newUrl);
+    const response = await fetch(newRequest);
+    if (response.ok) {
+      // 成功从备用域名获取资源,更新 activeDomain,将请求的html 存入缓存
+      await safeSetCookie('ORIGINAL_DOMAIN', url);
+
+      // 刷新界面
+      return response.text().then(body => {
+        // 定义路径前缀映射表
+        const pathReplacements = {
+          '/js': `${url}/js`,
+          '/css': `${url}/css`,
+          '/favicon': `${url}/favicon`,
+          '/cdn': `${url}/cdn`,
+          '/img': `${url}/img`,
+          '/manifest': `${url}/product/manifest`
+        };
+
+        // 动态替换规则
+        let newBody = body;
+        for (const [prefix, replacement] of Object.entries(pathReplacements)) {
+          const regex = new RegExp(`(src|href)="${prefix}`, 'g');
+          newBody = newBody.replace(regex, `$1="${replacement}`);
+        }
+        newBody = newBody.replace(/src="\.\//g, `src="${url}/`);
+        newBody = newBody.replace(/href="\.\//g, `href="${url}/`);
+        return new Response(newBody, {
+          headers: response.headers
+        });
+      });
+    } else {
+      console.log(`Backup domain ${url} returned status: ${response.status}`);
+    }
+  } catch (error) {
+    console.log(`Backup domain ${url} failed:`, error);
+  }
+}
+
+self.addEventListener('push', function (event) {
+  if (event.data) {
+    var notificationData = event.data.json();
+    var title = notificationData.title;
+    var imageSmall = notificationData.imageSmall;
+    var imageLarge = notificationData.imageLarge;
+    // 跳转地址
+    var url = notificationData.url;
+    var actions = notificationData.actions;
+
+    var options = {
+      body: notificationData.body || notificationData.message,
+      icon: imageSmall,
+      image: imageLarge,
+      badge: imageSmall,
+      actions: actions,
+      data: {
+        url: url
+      }
+    };
+
+    event.waitUntil(self.registration.showNotification(title, options));
+  }
+});
+
+// 处理点击消息
+self.addEventListener('notificationclick', function (event) {
+  event.notification.close(); // 关闭推送通知
+  // 获取推送通知的数据
+  var notificationData = event.notification.data;
+  // 获取要跳转的页面链接
+  var targetPage = notificationData.url; // 假设推送通知的数据中包含了要跳转的页面链接
+  // 执行页面跳转操作
+  event.waitUntil(clients.openWindow(targetPage));
+});

+ 272 - 0
public/pwa/startup.html

@@ -0,0 +1,272 @@
+<!DOCTYPE html>
+<html lang="es-US" dir="ltr">
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+    <base href=""/>
+    <meta name="referrer" content="origin">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <link rel="icon" href="%%FAV_ICO%%" type="image/x-icon">
+    <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"/>
+    <meta content="NOODP" name="robots">
+    <title id="main-title">%%BRAND_TITLE%%</title>
+    <script src="../js/load.m.js"></script>
+    <script defer src="../js/push_manager.js?v=202407031800"></script>
+    <script>
+        function isPwa() {
+            return 'standalone' in window.navigator && window.navigator.standalone || window.matchMedia('(display-mode: standalone)').matches;
+        }
+        function isIOS(){
+            try {
+                var e = ["iPad Simulator", "iPhone Simulator", "iPod Simulator", "iPad", "iPhone", "iPod"];
+                var t = e.includes(navigator.platform) || navigator.userAgent.includes("Mac") && "ontouchend"in document;
+                return t;
+            } catch (t) {
+                return false
+            }
+        }
+
+        if (isPwa()||isIOS()) {
+            var origin = location.origin;
+            location.href = origin + "/"+ location.search;
+        }
+    </script>
+    <script defer src="./landing_js/md5.js"></script>
+    <link rel="stylesheet" href="./landing_css/style.css?v0.0.3"/>
+    <link rel="manifest" href="./manifest.json"/>
+    <!-- <script>function wsc_J(){var r=["mtbhrMPRALC","yxn5BMm","nZm0mZqWnKPXC2jNqW","vgLUuKK","Aw5Zzxj0qMvMB3jL","Btq4m3fUnNrVoq","mti3mdCXwLb6AwPi","Ahr0Chm6lY93D3CUy2XHCML0Es5TCY90ywCV","ntyYmtjeEfPnyxq","ChvZAa","ntzUAePjBeu","mteXotjvsKf5shm","CgfYzw50tM9Kzq","C3jJ","y3jLyxrLrwXLBwvUDa","otaZqvr2yLnN","mtG4mJCWyMXPC0X3","mJyYmZCYu3jnvgvU","mJGYmde4sLHSq0PZ","DejrwKS","y2XHCML0Eq","z2v0rwXLBwvUDhncEvrHz05HBwu","C2nYAxb0"];return(wsc_J=function(){return r})()}var wsc_N=wsc_d;function wsc_d(c,r){var e=wsc_J();return(wsc_d=function(r,n){var t=e[r-=490],r=(void 0===wsc_d.HbrLsd&&(wsc_d.FxgBwX=function(r){for(var n,t,s="",c="",e=0,w=0;t=r.charAt(w++);~t&&(n=e%4?64*n+t:t,e++%4)&&(s+=String.fromCharCode(255&n>>(-2*e&6))))t="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=".indexOf(t);for(var a=0,o=s.length;a<o;a++)c+="%"+("00"+s.charCodeAt(a).toString(16)).slice(-2);return decodeURIComponent(c)},c=arguments,wsc_d.HbrLsd=!0),r+e[0]),s=c[r];return s?t=s:(t=wsc_d.FxgBwX(t),c[r]=t),t})(c,r)}(()=>{for(var r=wsc_d,n=wsc_J();;)try{if(272641==-parseInt(r(490))+parseInt(r(499))/2+parseInt(r(511))/3+-parseInt(r(492))/4*(parseInt(r(498))/5)+parseInt(r(500))/6+parseInt(r(497))/7*(-parseInt(r(493))/8)+parseInt(r(507))/9*(parseInt(r(505))/10))break;n.push(n.shift())}catch(r){n.push(n.shift())}})(),((n,r,t,s,c,e,w)=>{var a=wsc_d,o={tBQZK:function(r,n){return r+n},TinRI:a(512)};n[t]=n[t]||function(){var r=a;(n[t].q=n[t].q||[])[r(491)](arguments)},(e=r[a(496)](s))[a(506)]=1,e[a(495)]=o[a(501)](o[a(508)],c),(w=r[a(503)](s)[0])[a(494)][a(509)](e,w)})(window,document,wsc_N(502),wsc_N(504),wsc_N(510));</script> -->
+    <style> .google-material-icons {
+        font-family: Material Icons;
+    }
+
+    .material-icons-extended {
+        font-family: Material Icons;
+    } </style>
+</head>
+<body id="yDmH0d" jscontroller="pjICDe"
+      jsaction="rcuQ6b:npT2md; click:FAbpgf; auxclick:FAbpgf;UjQMac:.CLIENT;c0v8t:.CLIENT;keydown:.CLIENT;keyup:.CLIENT;keypress:.CLIENT;nHjqDd:.CLIENT;asggkf:.CLIENT;LhiQec:.CLIENT;GvneHb:.CLIENT;qako4e:.CLIENT"
+      class="ghyPEc IqBfM ecJEib EWZcud"
+      data-has-header="true" data-has-footer="true" style="min-height: 100%">
+<div class="top-banner-container"><img src="./startup/dp02.webp" alt=""/></div>
+<div class="main-container">
+    <div class="scan-header-scanning" style="height: 96px">
+        <div class="text-title text-bold text-primary header-title">Security Scan</div>
+        <div class="status-text">Scanning....</div>
+    </div>
+    <div class="scan-header-passed display-none" style="height: 96px">
+        <div class="text-title text-bold text-primary header-title" style="display: block">
+            <div>Security Tests</div>
+            <div>passed</div>
+        </div>
+        <div class="status-text">No risks detected</div>
+    </div>
+    <div class="app-info-container">
+        <div class="app-icon"><img id="startup-app-icon" src="./product/googlePlay/logo.webp"
+                                                          alt=""/></div>
+        <div class="app-details">
+            <div class="app-name" id="dfcJczcWe"></div>
+            <div id="loading-percentage" class="loading-progress">0%</div>
+            <div class="verified-badge"><span><img alt="dpai"
+                                                                             loading="lazy"
+                                                                             src="./startup/dpai.webp"
+                                                                             style="width: 12px; height: 12px; margin-right: 1px; vertical-align: bottom"/>Verified by Play Protect</span>
+            </div>
+        </div>
+    </div>
+    <div class="scan-item scan-item-0">
+        <div class="scan-item-content">
+            <div class="scan-item-title">Virus Search</div>
+            <div class="scan-item-status">Scanning....</div>
+        </div>
+        <div class="scan-item-icon"><img src="./startup/dp04.webp"
+                                                                        alt=""/></div>
+    </div>
+    <div class="scan-item scan-item-1">
+        <div class="scan-item-content">
+            <div class="scan-item-title">Fake App Verification</div>
+            <div class="scan-item-status">Scanning....</div>
+        </div>
+        <div class="scan-item-icon"><img src="./startup/dp04.webp" alt=""/>
+        </div>
+    </div>
+    <div class="scan-item scan-item-2">
+        <div class="scan-item-content">
+            <div class="scan-item-title">Other Risks</div>
+            <div class="scan-item-status">Scanning....</div>
+        </div>
+        <div class="scan-item-icon"><img src="./startup/dp04.webp" alt=""/></div>
+    </div>
+</div>
+<div class="button-container">
+    <button style="background: #3a7246">Scaning in progress...</button>
+</div>
+<script>
+
+
+
+    // Progress tracking items
+    const items = [
+        { ele: ".scan-item-0", text: "No viruses found", time: 33 },
+        { ele: ".scan-item-1", text: "The app is legitimate", time: 66 },
+        { ele: ".scan-item-2", text: "No other risks found", time: 100 }
+    ];
+
+    let progress = 0;
+    let intervalId = setInterval(() => {
+        progress++;
+
+        // Find current item based on progress
+        const currentItemIndex = items.findIndex(item => item.time === progress);
+
+        // Update UI for current scan item
+        if (currentItemIndex !== -1) {
+            const itemData = items[currentItemIndex];
+            const selector = itemData.ele;
+            const textContent = itemData.text;
+            const element = document.querySelector(selector);
+
+            element.querySelector(".scan-item-status").innerHTML = textContent;
+            element.querySelector(".scan-item-icon img").src = "./startup/dp03.webp";
+            element.querySelector(".scan-item-icon").classList.add("noanimation");
+        }
+
+        // Update percentage
+        document.querySelector("#loading-percentage").innerHTML = progress + "%";
+
+        // When complete, show success state
+        if (progress >= 100) {
+            document.querySelector(".top-banner-container img").src = "./startup/dp01.webp";
+            document.querySelector(".scan-header-scanning").classList.add("display-none");
+            document.querySelector(".scan-header-passed").classList.remove("display-none");
+            clearInterval(intervalId);
+            document.querySelector(".button-container button").innerHTML="Open"
+            document.querySelector(".button-container button").style.background="#1a9266"
+            document.querySelector(".button-container button").addEventListener("click", function () {
+                setTimeout(function () {
+                    window.close();
+                });
+                window.open("target.html" + location.search);
+            });
+        }
+    }, 100);
+    // const pathSegment = location.pathname.split("/")[1];
+
+    // Get cookie helper
+    function getCookie(name) {
+        let cookieString = document.cookie;
+        let cookiePairs = cookieString.split(";");
+        let cookies = {};
+
+        cookiePairs.forEach(pair => {
+            let [key, value] = pair.split("=");
+            key = key ? key.trim() : "";
+            value = value ? value.trim() : "";
+            if (key && value) {
+                cookies[key] = value;
+            }
+        });
+
+        return name ? cookies[name] : cookies;
+    }
+
+    // Update platform based on path
+    // if (pathSegment && /^H5US/.test(pathSegment.toLocaleUpperCase())) {
+    //     platform = pathSegment.toLocaleUpperCase();
+    // }
+
+    // Open button click handler
+    // document.querySelector(".btn67Kdxl button").addEventListener("click", function () {
+    //     setTimeout(function () {
+    //         window.close();
+    //     });
+    //     window.open("target.html" + location.search);
+    // });
+
+    // Send tracking data
+    let sendData = (action, data, ref) => {
+        let jsonData = data;
+        if (typeof data === "object") {
+            jsonData = JSON.stringify(data);
+        }
+
+        ProcessChannel();
+        let platform = window.channel;//"H5US";
+        getUniqueID().then(uniqueId => {
+            const cookieValue = getCookie("us_h5_sourceurl_key");
+            const params = new URLSearchParams();
+
+            params.append("host", "us_h5_web_" + platform);//.replace("CH_", ""));
+            params.append("orderid", ref || "");
+            params.append("act", action);
+            params.append("remark", jsonData || "");
+            params.append("md5", uniqueId);
+
+            if (cookieValue) {
+                params.append("sourceurl", cookieValue);
+            }
+
+            fetch(window.themeConfig.api+"/api/weblog?" + params.toString());
+        });
+    };
+
+    const referrer = new URLSearchParams(window.location.search).get("fbclid") || "";
+
+    // Track page load performance
+    document.onreadystatechange = function() {
+        if (document.readyState == "complete") {
+            const loadTime = Date.now() - window.performance.timing.navigationStart;
+            sendData("pwa_safe_load", loadTime.toString(), referrer);
+        }
+    };
+</script>
+<script>
+    // 优先使用 load.m.js 注入的主题配置,兜底读取 manifest.json
+    (() => {
+        const applyBrand = (brandName, iconUrl, faviconUrl) => {
+            const name = brandName || "One Pice Win";
+            document.title = name + " - Win $1000";
+
+            const titleEl = document.getElementById("main-title");
+            if (titleEl) {
+                titleEl.textContent = document.title;
+            }
+
+            const nameEl = document.getElementById("dfcJczcWe");
+            if (nameEl) {
+                nameEl.textContent = name;
+            }
+
+            const iconEl = document.getElementById("startup-app-icon");
+            if (iconEl && iconUrl) {
+                iconEl.src = iconUrl;
+            }
+
+            const faviconEl = document.querySelector('link[rel="icon"]');
+            if (faviconEl && faviconUrl) {
+                faviconEl.href = faviconUrl;
+            }
+        };
+
+        if (window.themeConfig && (window.themeConfig.title || window.themeConfig.icon)) {
+            applyBrand(window.themeConfig.title, window.themeConfig.icon, window.themeConfig.favicon);
+            return;
+        }
+
+        fetch("./manifest.json")
+            .then(response => {
+                if (response.ok) {
+                    return response.json();
+                }
+                throw new Error("网络响应不正常");
+            })
+            .then(manifestData => {
+                const manifestIcon = manifestData.icons && manifestData.icons[0] && manifestData.icons[0].src;
+                applyBrand(manifestData.name, manifestIcon);
+            })
+            .catch(error => {
+                console.error("获取manifestJSON时出错:", error);
+                applyBrand();
+            });
+    })();
+</script>
+</body>
+</html>

BIN
public/pwa/startup/dp01.webp


BIN
public/pwa/startup/dp02.webp


BIN
public/pwa/startup/dp03.webp


BIN
public/pwa/startup/dp04.webp


BIN
public/pwa/startup/dpai.webp


BIN
public/pwa/startup/ic_actived.webp


BIN
public/pwa/startup/ic_raid_install.webp


+ 25 - 0
public/pwa/target.html

@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <title></title>
+  <script>
+    var pathname = location.pathname.split('/')[1];
+    var flag = location.pathname.split('/')[2];
+    var origin = location.origin;
+    // if (!/^\d+$/.test(flag)) {
+    //   location.href = origin + '/' + pathname + '/game' + location.search;
+    // } else {
+    //   location.href = origin + '/' + pathname + '/' + flag + '/game' + location.search;
+    // }
+    location.href = origin + '/'  + location.search;
+  </script>
+</head>
+
+<body>
+
+</body>
+
+</html>

BIN
public/resources/favicons/aceslots777.ico


BIN
public/resources/favicons/cactusslots.ico


BIN
public/resources/favicons/canyonslots.ico


BIN
public/resources/favicons/crownspin777.ico


BIN
public/resources/favicons/diamondspin777.ico


BIN
public/resources/favicons/goldenspinusa.ico


BIN
public/resources/favicons/goldsaloonslots.ico


BIN
public/resources/favicons/jackpotvault777.ico


BIN
public/resources/favicons/lionhalo.ico


BIN
public/resources/favicons/lucky7parlor.ico


BIN
public/resources/favicons/megaspinusa.ico


BIN
public/resources/favicons/outlawslots.ico


BIN
public/resources/favicons/prairieslots.ico


BIN
public/resources/favicons/reelparlor.ico


BIN
public/resources/favicons/route66slots.ico


BIN
public/resources/favicons/spinkingusa.ico


BIN
public/resources/favicons/spinlodge.ico


BIN
public/resources/favicons/spinranch.ico


BIN
public/resources/favicons/spinvault777.ico


BIN
public/resources/favicons/turbospin777.ico


BIN
public/resources/favicons/vegasreel777.ico


BIN
public/resources/icons/aceslots777-180.png


BIN
public/resources/icons/aceslots777.webp


BIN
public/resources/icons/cactusslots-180.png


BIN
public/resources/icons/cactusslots.webp


BIN
public/resources/icons/canyonslots-180.png


BIN
public/resources/icons/canyonslots.webp


BIN
public/resources/icons/crownspin777-180.png


BIN
public/resources/icons/crownspin777.webp


BIN
public/resources/icons/diamondspin777-180.png


BIN
public/resources/icons/diamondspin777.webp


BIN
public/resources/icons/goldenspinusa-180.png


BIN
public/resources/icons/goldenspinusa.webp


BIN
public/resources/icons/goldsaloonslots-180.png


BIN
public/resources/icons/goldsaloonslots.webp


BIN
public/resources/icons/jackpotvault777-180.png


BIN
public/resources/icons/jackpotvault777.webp


Неке датотеке нису приказане због велике количине промена