4ndr0666

Untitled

Dec 22nd, 2025
46
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 14.21 KB | None | 0 0
  1. // ==UserScript==
  2. // @name        4ndr0tools - HailuoSuperset
  3. // @namespace   https://github.com/4ndr0666/userscripts
  4. // @author      4ndr0666
  5. // @version     47.0
  6. // @description Superset: Asset extraction, HUD, status bypass, bracket obfuscation, drag-safe, bug-immune. Security research only.
  7. // @icon        https://raw.githubusercontent.com/4ndr0666/4ndr0site/refs/heads/main/static/cyanglassarch.png
  8. // @match       *://*.hailuoai.video/*
  9. // @match       *://*.hailuoai.com/*
  10. // @run-at      document-start
  11. // @grant       GM_setValue
  12. // @grant       GM_getValue
  13. // @grant       GM_registerMenuCommand
  14. // @grant       GM_notification
  15. // @license     MIT
  16. // ==/UserScript==
  17.  
  18. (() => {
  19.   'use strict';
  20.  
  21.   //────── ONTOLOGICAL MASKING & SINGLETON ──────//
  22.   const nomenclature = (() => {
  23.     const r = () => Math.random().toString(36).substring(2, 10);
  24.     const prefix = `Ψ_${r()}`;
  25.     return {
  26.       singleton: `_hkInit_${r()}`,
  27.       cssId: `${prefix}_css`,
  28.       hudBtnId: `${prefix}_hudBtn`,
  29.       hudRootId: `${prefix}_hudRoot`,
  30.       class: (name) => `${prefix}_${name}`,
  31.     };
  32.   })();
  33.  
  34.   if (window[nomenclature.singleton]) return;
  35.   Object.defineProperty(window, nomenclature.singleton, { value: true, writable: false, configurable: false });
  36.  
  37.   //────── CORE STATE & CONFIG ──────//
  38.   let CONFIG = {
  39.     debugMode: false,
  40.     promptObfuscation: 'bracket',
  41.   };
  42.   let ASSETS = [];
  43.   const originalFetch = window.fetch;
  44.   const originalJSONParse = JSON.parse;
  45.   const originalWebSocket = window.WebSocket;
  46.  
  47.   const BYPASS_KEYS = [ 'statusInfo', 'sensitiveInfo', 'postStatus', 'humanCheckStatus', 'projectStatus', 'status' ];
  48.  
  49.   //────── UTILITIES ──────//
  50.   function el(tag, props = {}, ...children) {
  51.     const element = document.createElement(tag);
  52.     for (const [key, value] of Object.entries(props || {})) {
  53.       if (key === 'class') element.className = value;
  54.       else if (key === 'style') Object.assign(element.style, value);
  55.       else if (key === 'on' && typeof value === 'object')
  56.         Object.entries(value).forEach(([ev, fn]) => element.addEventListener(ev, fn));
  57.       else if (key === 'dataset' && value && typeof value === 'object')
  58.         Object.entries(value).forEach(([dk, dv]) => element.dataset[dk] = dv);
  59.       else element[key] = value;
  60.     }
  61.     // Flatten children and append as Node or text
  62.     ([].concat(...children)).forEach(child => {
  63.       if (!child && child !== 0) return;
  64.       if (child instanceof Node) element.append(child);
  65.       else if (typeof child === 'string' || typeof child === 'number') element.append(document.createTextNode(child));
  66.       // Ignore false/null/undefined
  67.     });
  68.     return element;
  69.   }
  70.  
  71.   //────── PERSISTENT STORAGE ──────//
  72.   const storage = {
  73.     _key: 'hailuo_assets_v10',
  74.     async load() { return await GM_getValue(storage._key, []); },
  75.     async save(data) { await GM_setValue(storage._key, data); }
  76.   };
  77.  
  78.   //────── UI CONTROLLER ──────//
  79.   let ui;
  80.   const createUIController = () => {
  81.     let hud;
  82.     const psiGlyphSVG = `<svg viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg" class="${nomenclature.class('glyph')}" fill="none" stroke="currentColor" stroke-width="3"><path d="M64 30 L91.3 47 L91.3 81 L64 98 L36.7 81 L36.7 47 Z" /><text x="64" y="67" text-anchor="middle" dominant-baseline="middle" fill="currentColor" stroke="none" font-size="56" font-weight="700">Ψ</text></svg>`;
  83.  
  84.     const updateAssetList = () => {
  85.       const container = hud?.querySelector('#assets-list');
  86.       if (!container) return;
  87.       container.innerHTML = '';
  88.       if (!Array.isArray(ASSETS) || ASSETS.length === 0) {
  89.         container.innerHTML = `<p style="text-align:center; color:#888;">Awaiting assets...</p>`;
  90.         return;
  91.       }
  92.       ASSETS.slice().reverse().forEach(asset => {
  93.         container.append(
  94.           el('div', { class: nomenclature.class('asset-item') },
  95.             el('img', { class: nomenclature.class('asset-thumb'), src: asset.thumb, loading: 'lazy', on: { error: (e) => (e.target.style.display = 'none') } }),
  96.             el('div', { class: nomenclature.class('asset-url'), textContent: asset.url.split('/').pop(), title: asset.url }),
  97.             el('div', { class: nomenclature.class('asset-actions') },
  98.               el('button', { textContent: 'Open', on: { click: () => window.open(asset.url, '_blank') } }),
  99.               el('button', { textContent: 'Copy', on: { click: () => { navigator.clipboard.writeText(asset.url); showToast('Copied!'); } } }),
  100.               el('button', { textContent: 'DL', on: { click: () => downloadAsset(asset.url) } })
  101.             )
  102.           )
  103.         );
  104.       });
  105.     };
  106.  
  107.     const showToast = (msg, duration = 2000) => {
  108.       const toast = el('div', { class: nomenclature.class('toast'), textContent: msg });
  109.       document.body.append(toast);
  110.       setTimeout(() => toast.remove(), duration);
  111.     };
  112.  
  113.     const downloadAsset = async (url) => {
  114.       try {
  115.         const response = await originalFetch(url, { cache: 'no-cache' });
  116.         if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
  117.         const blob = await response.blob();
  118.         const a = el('a', { href: URL.createObjectURL(blob), download: url.split('/').pop() || 'download' });
  119.         document.body.append(a); a.click(); a.remove();
  120.         URL.revokeObjectURL(a.href);
  121.       } catch (e) { showToast('Download Failed!'); }
  122.     };
  123.  
  124.     // Optional: Dragging support for the HUD
  125.     let offsetX = 0, offsetY = 0, isDragging = false;
  126.     function enableDrag(elem) {
  127.       const header = elem.querySelector(`.${nomenclature.class('hud-header')}`);
  128.       if (!header) return;
  129.       header.onmousedown = function(e) {
  130.         isDragging = true;
  131.         offsetX = e.clientX - elem.offsetLeft;
  132.         offsetY = e.clientY - elem.offsetTop;
  133.         document.onmousemove = function(ev) {
  134.           if (!isDragging) return;
  135.           elem.style.left = (ev.clientX - offsetX) + 'px';
  136.           elem.style.top = (ev.clientY - offsetY) + 'px';
  137.           elem.style.right = 'auto'; // disable right anchor while dragging
  138.         };
  139.         document.onmouseup = function() {
  140.           isDragging = false;
  141.           document.onmousemove = null;
  142.           document.onmouseup = null;
  143.         };
  144.       };
  145.     }
  146.  
  147.     return {
  148.       toggle: (force = null) => {
  149.         if (!hud) {
  150.           hud = el('div', { id: nomenclature.hudRootId, class: nomenclature.class('hud-container'), hidden: true }, [
  151.             el('div', { class: nomenclature.class('hud-header') },
  152.               el('div', { innerHTML: psiGlyphSVG }),
  153.               el('div', { class: nomenclature.class('hud-title'), textContent: 'HailuoΨ Extractor' }),
  154.               el('button', { class: nomenclature.class('hud-close-btn'), textContent: '×', on: { click: () => ui.toggle(false) } })
  155.             ),
  156.             el('div', { class: nomenclature.class('hud-content') },
  157.               el('div', { class: nomenclature.class('panel-header') },
  158.                 el('h3', { textContent: 'Captured Assets' }),
  159.                 el('button', { textContent: 'Clear', on: { click: async () => { if (confirm('Clear all captured assets?')) { ASSETS = []; await storage.save(ASSETS); updateAssetList(); } } } })
  160.               ),
  161.               el('div', { id: 'assets-list', class: nomenclature.class('asset-list') })
  162.             )
  163.           ]);
  164.           document.body.append(hud);
  165.           enableDrag(hud);
  166.         }
  167.         hud.hidden = force !== null ? !force : !hud.hidden;
  168.         if (!hud.hidden) updateAssetList();
  169.       },
  170.       updateAssetList,
  171.       inject: () => {
  172.         if (document.getElementById(nomenclature.cssId)) return;
  173.         document.head.append(el('style', { id: nomenclature.cssId, textContent: `
  174.           :root { --accent: #00E5FF; --bg1: #101827; --bg2: rgba(16,24,39,0.8); --text1: #EAEAEA; --text2: #9E9E9E; }
  175.           .${nomenclature.class('hud-btn')} { position:fixed; bottom:20px; right:20px; width:50px; height:50px; background:var(--bg1); border:2px solid var(--accent); border-radius:50%; z-index:999998; cursor:pointer; display:flex; align-items:center; justify-content:center; color:var(--accent); box-shadow:0 0 15px var(--accent); }
  176.           .${nomenclature.class('glyph')} { width: 60%; height: 60%; }
  177.           .${nomenclature.class('hud-container')} { position:fixed; top:100px; right:20px; z-index:999999; background:var(--bg2); backdrop-filter:blur(8px); border:2px solid var(--accent); border-radius:12px; box-shadow:0 0 25px rgba(0,229,255,0.2); width:500px; color:var(--text1); font-family:sans-serif; }
  178.           .${nomenclature.class('hud-header')} { display:flex; align-items:center; padding:8px; background:var(--bg1); cursor:move; border-bottom:1px solid var(--accent); }
  179.           .${nomenclature.class('hud-header')} .${nomenclature.class('glyph')} { width:30px; height:30px; margin-right:10px; }
  180.           .${nomenclature.class('hud-title')} { font-weight:bold; flex-grow:1; }
  181.           .${nomenclature.class('hud-close-btn')} { background:0; border:0; color:var(--text2); font-size:20px; cursor:pointer; }
  182.           .${nomenclature.class('hud-content')} { padding:15px; max-height:60vh; overflow-y:auto; }
  183.           .${nomenclature.class('panel-header')} { display:flex; justify-content:space-between; align-items:center; margin-bottom:10px; }
  184.           .${nomenclature.class('panel-header')} h3 { margin:0; }
  185.           .${nomenclature.class('asset-list')} { display:flex; flex-direction:column; gap:10px; }
  186.           .${nomenclature.class('asset-item')} { display:grid; grid-template-columns:60px 1fr auto; gap:10px; align-items:center; background:rgba(255,255,255,0.05); padding:8px; border-radius:4px; }
  187.           .${nomenclature.class('asset-thumb')} { width:60px; height:40px; object-fit:cover; border-radius:3px; }
  188.           .${nomenclature.class('asset-url')} { word-break:break-all; font-size:0.9em; }
  189.           .${nomenclature.class('asset-actions')} { display:flex; gap:5px; }
  190.           .${nomenclature.class('asset-actions')} button, .${nomenclature.class('panel-header')} button { background:var(--accent); color:var(--bg1); border:0; padding:4px 8px; cursor:pointer; border-radius:3px; font-weight:bold; }
  191.           .${nomenclature.class('toast')} { position:fixed; bottom:20px; left:50%; transform:translateX(-50%); background:var(--accent); color:var(--bg1); padding:10px 20px; border-radius:5px; z-index:1000000; font-weight:bold; }
  192.         `}));
  193.         document.body.append(el('button', { id: nomenclature.hudBtnId, className: nomenclature.class('hud-btn'), innerHTML: psiGlyphSVG, on: { click: () => ui.toggle() } }));
  194.       },
  195.     };
  196.   };
  197.  
  198.   //────── NETWORK & DATA PROCESSING ──────//
  199.   const obfuscatePrompt = (p) => {
  200.     if (CONFIG.promptObfuscation === 'bracket' && p) {
  201.       return p.split('').map(c => `[${c}]`).join('');
  202.     }
  203.     return p;
  204.   };
  205.  
  206.   const processData = (data, depth = 0) => {
  207.     if (!data || typeof data !== 'object' || depth > 50) return;
  208.     if (Array.isArray(data)) {
  209.       data.forEach(child => processData(child, depth + 1));
  210.       return;
  211.     }
  212.     BYPASS_KEYS.forEach(key => {
  213.       if (data[key] && typeof data[key] === 'object' && data[key].level && data[key].level !== 0) {
  214.         data[key].level = 0;
  215.       }
  216.     });
  217.     const url = data.downloadURLWithoutWatermark || data.videoUrl || data.imageUrl;
  218.     if (url && typeof url === 'string' && url.startsWith('http')) {
  219.       const newAsset = { url, thumb: data.coverUrl || data.feedURL || url };
  220.       if (!ASSETS.some(a => a.url === newAsset.url)) {
  221.         ASSETS.push(newAsset);
  222.         storage.save(ASSETS);
  223.         ui?.updateAssetList();
  224.         GM_notification({ title: 'Asset Captured!', text: newAsset.url, timeout: 10000, onclick: () => window.open(newAsset.url, '_blank')});
  225.       }
  226.     }
  227.     Object.values(data).forEach(child => processData(child, depth + 1));
  228.   };
  229.  
  230.   const overrideNetwork = () => {
  231.     window.fetch = async function(...args) {
  232.       let [url, options] = args;
  233.       if (typeof url === 'string') {
  234.         if (url.includes('identitytoolkit.googleapis.com') || url.includes('/default_avatar.png')) {
  235.           return new Response(null, { status: 404, statusText: 'Blocked by HailuoΨ' });
  236.         }
  237.         if (url.includes('/api/multimodal/generate/') && options?.method === 'POST') {
  238.           try {
  239.             const body = originalJSONParse(options.body);
  240.             if (body.prompt) {
  241.               body.prompt = obfuscatePrompt(body.prompt);
  242.               options.body = JSON.stringify(body);
  243.             }
  244.           } catch (e) { }
  245.         }
  246.       }
  247.       const response = await originalFetch.apply(this, args);
  248.       if (response.ok && response.headers.get('Content-Type')?.includes('json')) {
  249.         const clone = response.clone();
  250.         try {
  251.           const data = await response.json();
  252.           processData(data);
  253.           return new Response(JSON.stringify(data), {
  254.             status: response.status, statusText: response.statusText, headers: response.headers,
  255.           });
  256.         } catch (e) { return clone; }
  257.       }
  258.       return response;
  259.     };
  260.     if (originalWebSocket) {
  261.       window.WebSocket = class extends originalWebSocket {
  262.         constructor(...args) {
  263.           super(...args);
  264.           this.addEventListener('message', (event) => {
  265.             if (typeof event.data === 'string') {
  266.               try {
  267.                 const data = originalJSONParse(event.data);
  268.                 processData(data);
  269.               } catch (err) { }
  270.             }
  271.           });
  272.         }
  273.       };
  274.     }
  275.   };
  276.  
  277.   //────── INITIALIZATION ──────//
  278.   async function initialize() {
  279.     ASSETS = await storage.load();
  280.     ui = createUIController();
  281.     overrideNetwork();
  282.     const observer = new MutationObserver((_, obs) => {
  283.       const targetNode = document.querySelector('#app, #root, main');
  284.       if (targetNode) { ui.inject(); obs.disconnect(); }
  285.     });
  286.     observer.observe(document.documentElement, { childList: true, subtree: true });
  287.     GM_registerMenuCommand('Open Asset HUD', () => ui.toggle(true));
  288.     GM_registerMenuCommand(`Toggle Obfuscation: [${CONFIG.promptObfuscation}]`, async () => {
  289.       CONFIG.promptObfuscation = CONFIG.promptObfuscation === 'bracket' ? 'none' : 'bracket';
  290.       await GM_setValue('hailuo_config_v1', CONFIG);
  291.     });
  292.   }
  293.   if (document.readyState === 'loading') window.addEventListener('DOMContentLoaded', initialize);
  294.   else initialize();
  295.  
  296. })();
Add Comment
Please, Sign In to add comment