soyak

babybot that can insert colorful square images into the file selector (vichan)

Jun 12th, 2026 (edited)
31
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. (function() {
  2.  
  3.     function insertColorfulSquares() {
  4.       const {
  5.         count = 3, // number of files to generate
  6.         width = 800,
  7.         height = 600,
  8.         itemsPerImage = 30, // shapes per image
  9.         shape = 'square', // 'square' | 'circle' | 'mixed'
  10.         squareSizeMin = 20,
  11.         squareSizeMax = 120,
  12.         filenamePrefix = 'vichan_gen', // base name; timestamp + index appended
  13.         addWatermark = false,
  14.         /*watermarkText = 'Anon',
  15.         watermarkFont = '20px sans-serif',
  16.         watermarkColor = 'rgba(0,0,0,0.4)',*/
  17.         autoSubmit = false, // if true, tries to submit enclosing form after inserting files
  18.         preferSelector = null, // CSS selector for specific input
  19.         waitMs = 1000,
  20.         createPreview = false
  21.       } = arguments[0] || {};
  22.  
  23.       function findFileInput() {
  24.         if (preferSelector) {
  25.           const el = document.querySelector(preferSelector);
  26.           if (el && el.type === 'file') return el;
  27.         }
  28.         const selectors = ['input[type="file"]', 'input#file', 'input[name="file"]', 'input[name^="file"]'];
  29.         for (const s of selectors) {
  30.           const el = document.querySelector(s);
  31.           if (el && el.type === 'file') return el;
  32.         }
  33.         return Array.from(document.querySelectorAll('input[type="file"]')).find(i => i.offsetParent !== null) || null;
  34.       }
  35.  
  36.       function makeCanvas(w, h) {
  37.         const c = document.createElement('canvas');
  38.         c.width = w;
  39.         c.height = h;
  40.         return c;
  41.       }
  42.  
  43.       function drawRandomArt(ctx, w, h, items, shapeOption) {
  44.         // white bg
  45.         ctx.fillStyle = '#ffffff';
  46.         ctx.fillRect(0, 0, w, h);
  47.         for (let i = 0; i < items; i++) {
  48.           const s = Math.floor(Math.random() * (squareSizeMax - squareSizeMin + 1)) + squareSizeMin;
  49.           const x = Math.floor(Math.random() * Math.max(1, w - s));
  50.           const y = Math.floor(Math.random() * Math.max(1, h - s));
  51.           const hue = Math.floor(Math.random() * 360);
  52.           const sat = Math.floor(60 + Math.random() * 40);
  53.           const light = Math.floor(45 + Math.random() * 30);
  54.           ctx.fillStyle = `hsl(${hue} ${sat}% ${light}%)`;
  55.           const pick = shapeOption === 'mixed' ? (Math.random() > 0.5 ? 'circle' : 'square') : shapeOption;
  56.           if (pick === 'circle') {
  57.             ctx.beginPath();
  58.             ctx.arc(x + s/2, y + s/2, s/2, 0, Math.PI * 2);
  59.             ctx.fill();
  60.           } else {
  61.             ctx.fillRect(x, y, s, s);
  62.           }
  63.         }
  64.       }
  65.  
  66.       function addWatermarkToCtx(ctx, w, h, text) {
  67.         ctx.save();
  68.         ctx.font = watermarkFont;
  69.         ctx.fillStyle = watermarkColor;
  70.         ctx.textAlign = 'right';
  71.         ctx.textBaseline = 'bottom';
  72.         ctx.fillText(text, w - 8, h - 8);
  73.         ctx.restore();
  74.       }
  75.  
  76.       async function canvasToFile(canvas, name) {
  77.         return new Promise((resolve, reject) => {
  78.           canvas.toBlob((blob) => {
  79.             if (!blob) return reject(new Error('Blob creation failed'));
  80.             const f = new File([blob], name, { type: 'image/png', lastModified: Date.now() });
  81.             resolve({ file: f, blob });
  82.           }, 'image/png');
  83.         });
  84.       }
  85.  
  86.       // Create multiple files
  87.       (async () => {
  88.         const generated = [];
  89.         for (let i = 0; i < count; i++) {
  90.           const c = makeCanvas(width, height);
  91.           const ctx = c.getContext('2d');
  92.           drawRandomArt(ctx, width, height, itemsPerImage, shape);
  93.           if (addWatermark) addWatermarkToCtx(ctx, width, height, `${watermarkText}`);
  94.           const name = `${filenamePrefix}_${Date.now()}_${i+1}.png`;
  95.           const { file, blob } = await canvasToFile(c, name);
  96.           generated.push({ file, blob, name });
  97.         }
  98.  
  99.         // Wait for input up to waitMs, else attempt drop targets
  100.         let input = findFileInput();
  101.         const start = Date.now();
  102.         if (!input) {
  103.           const obs = new MutationObserver(() => {
  104.             input = findFileInput();
  105.             if (input) {
  106.               obs.disconnect();
  107.               performInsert(input, generated);
  108.             } else if (Date.now() - start > waitMs) {
  109.               obs.disconnect();
  110.               fallbackDropOrError(generated);
  111.             }
  112.           });
  113.           obs.observe(document.documentElement || document.body, { childList: true, subtree: true });
  114.           // timeout safety
  115.           setTimeout(() => {
  116.             if (!input) {
  117.               input = findFileInput();
  118.               if (input) return performInsert(input, generated);
  119.               fallbackDropOrError(generated);
  120.             }
  121.           }, waitMs + 50);
  122.         } else {
  123.           performInsert(input, generated);
  124.         }
  125.       })();
  126.  
  127.       function performInsert(input, generated) {
  128.         try {
  129.           const dt = new DataTransfer();
  130.           for (const g of generated) dt.items.add(g.file);
  131.           input.files = dt.files;
  132.         } catch (e) {
  133.           // assign failed; try setting first file and then adding others via drop
  134.           try {
  135.             const dt = new DataTransfer();
  136.             dt.items.add(generated[0].file);
  137.             input.files = dt.files;
  138.           } catch (e2) { /* ignore */ }
  139.           console.warn('Direct assignment of multiple files failed, attempting drop fallback.', e);
  140.           attemptDrop(input.parentElement || input, generated);
  141.         }
  142.  
  143.         ['input', 'change'].forEach(n => input.dispatchEvent(new Event(n, { bubbles: true })));
  144.         if (window.jQuery) try { window.jQuery(input).trigger('change'); } catch (e) {}
  145.  
  146.         if (createPreview) attachMultiplePreview(input, generated);
  147.         console.log('Inserted', generated.length, 'generated file(s) into input:', input);
  148.  
  149.         if (autoSubmit) {
  150.           // try to find enclosing form and submit it
  151.           const form = input.closest && input.closest('form') || input.form;
  152.           if (form) {
  153.             try {
  154.               // If vichan uses AJAX, triggering submit may be intercepted; try both submit() and dispatching events
  155.               form.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
  156.               form.requestSubmit ? form.requestSubmit() : form.submit();
  157.               console.log('Form submitted.');
  158.             } catch (e) {
  159.               console.warn('Auto-submit failed:', e);
  160.             }
  161.           } else {
  162.             console.warn('Auto-submit requested but no enclosing form found.');
  163.           }
  164.         }
  165.       }
  166.  
  167.       // fallback: try drop on typical drop targets
  168.       function fallbackDropOrError(generated) {
  169.         const drops = ['.file-drop', '.dropzone', '.filearea', '.uploader', '.drag-drop', '.drag-and-drop', '#drop'];
  170.         let target = null;
  171.         for (const s of drops) {
  172.           const el = document.querySelector(s);
  173.           if (el) { target = el; break; }
  174.         }
  175.         if (!target) {
  176.           const anyInput = document.querySelector('input[type="file"]');
  177.           if (anyInput && anyInput.parentElement) target = anyInput.parentElement;
  178.         }
  179.         if (!target) {
  180.           console.error('No file input or drop target found; cannot insert files.');
  181.           return;
  182.         }
  183.         attemptDrop(target, generated);
  184.       }
  185.  
  186.       // attempt to drop multiple files
  187.       function attemptDrop(target, generated) {
  188.         const dt = new DataTransfer();
  189.         generated.forEach(g => dt.items.add(g.file));
  190.         ['dragenter', 'dragover', 'drop'].forEach(type => {
  191.           let ev;
  192.           try {
  193.             ev = new DragEvent(type, { dataTransfer: dt, bubbles: true, cancelable: true });
  194.           } catch (e) {
  195.             ev = new Event(type, { bubbles: true, cancelable: true });
  196.             ev.dataTransfer = dt;
  197.           }
  198.           target.dispatchEvent(ev);
  199.         });
  200.  
  201.         // if target contains an input, set it
  202.         const nested = target.querySelector && target.querySelector('input[type="file"]');
  203.         if (nested) {
  204.           try {
  205.             const dt2 = new DataTransfer();
  206.             generated.forEach(g => dt2.items.add(g.file));
  207.             nested.files = dt2.files;
  208.             ['input', 'change'].forEach(n => nested.dispatchEvent(new Event(n, { bubbles: true })));
  209.             if (window.jQuery) try { window.jQuery(nested).trigger('change'); } catch (e) {}
  210.             if (createPreview) attachMultiplePreview(nested, generated);
  211.             console.log('Inserted files into nested input:', nested);
  212.             return;
  213.           } catch (e) { /* ignore */ }
  214.         }
  215.  
  216.         if (createPreview) {
  217.           try {
  218.             const container = document.createElement('div');
  219.             container.style.display = 'flex';
  220.             container.style.gap = '6px';
  221.             generated.forEach(g => {
  222.               const img = new Image();
  223.               img.src = URL.createObjectURL(g.blob);
  224.               img.style.maxWidth = '100px';
  225.               img.style.maxHeight = '80px';
  226.               container.appendChild(img);
  227.             });
  228.             target.appendChild(container);
  229.           } catch (e) {}
  230.         }
  231.  
  232.         console.log('Attempted drop on target:', target);
  233.       }
  234.  
  235.       function attachMultiplePreview(input, generated) {
  236.         try {
  237.           const existing = input.nextElementSibling && input.nextElementSibling.getAttribute && input.nextElementSibling.getAttribute('data-generated-preview') === '1';
  238.           if (existing) return;
  239.           const wrapper = document.createElement('div');
  240.           wrapper.setAttribute('data-generated-preview', '1');
  241.           wrapper.style.display = 'flex';
  242.           wrapper.style.gap = '6px';
  243.           wrapper.style.marginLeft = '8px';
  244.           generated.forEach(g => {
  245.             const img = new Image();
  246.             img.alt = g.name;
  247.             img.src = URL.createObjectURL(g.blob);
  248.             img.style.maxWidth = '100px';
  249.             img.style.maxHeight = '80px';
  250.             wrapper.appendChild(img);
  251.           });
  252.           input.parentNode && input.parentNode.insertBefore(wrapper, input.nextSibling);
  253.         } catch (e) {}
  254.       }
  255.     }
  256.     insertColorfulSquares();
  257.    
  258.     // Generate a similar but randomized string to "baby"
  259.     function generateRandomSimilarString(baseString = "baby") {
  260.         const characters = 'abcdefghijklmnopqrstuvwxyz1234567890-=!@#$%^&*()_+';
  261.         const baseArray = baseString.split('');
  262.         const newArray = [...baseArray];
  263.         for (let i = 0; i < 2; i++) {
  264.             const randomChar = characters.charAt(Math.floor(Math.random() * characters.length));
  265.             newArray.splice(Math.floor(Math.random() * newArray.length), 0, randomChar);
  266.         }
  267.         for (let i = 0; i < 2; i++) {
  268.             newArray.splice(Math.floor(Math.random() * newArray.length), 1);
  269.         }
  270.         return newArray.join('');
  271.     }
  272.  
  273.     // Utility: click element safely
  274.     function safeClick(el) {
  275.         if (!el) return false;
  276.         try {
  277.             if (el.focus) el.focus();
  278.             el.click();
  279.             return true;
  280.         } catch (e) {
  281.             try {
  282.                 el.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));
  283.                 return true;
  284.             } catch (e2) {
  285.                 return false;
  286.             }
  287.         }
  288.     }
  289.  
  290.     // Populate the form fields automatically (body + embed or file)
  291.     function populateForm() {
  292.         // set vichan name fields to "goo goo gaa gaa" and email fields to "nonoko"
  293.         const nameText = "goo goo gaa gaa";
  294.         const emailText = "nonoko";
  295.  
  296.         // Name by id
  297.         const nameById = document.getElementById('post_name');
  298.         if (nameById) {
  299.             nameById.value = nameText;
  300.             nameById.dispatchEvent(new Event('input', { bubbles: true }));
  301.             nameById.dispatchEvent(new Event('change', { bubbles: true }));
  302.         }
  303.         // Name by name attribute
  304.         const nameFields = document.querySelectorAll('input[name="name"]');
  305.         nameFields.forEach(f => {
  306.             if (!f) return;
  307.             f.value = nameText;
  308.             f.dispatchEvent(new Event('input', { bubbles: true }));
  309.             f.dispatchEvent(new Event('change', { bubbles: true }));
  310.         });
  311.  
  312.         // Email by id (text input)
  313.         const emailById = document.getElementById('email');
  314.         if (emailById) {
  315.             emailById.value = emailText;
  316.             emailById.dispatchEvent(new Event('input', { bubbles: true }));
  317.             emailById.dispatchEvent(new Event('change', { bubbles: true }));
  318.         }
  319.  
  320.         // Email selectbox by id
  321.         const emailSelectBox = document.getElementById('email_selectbox');
  322.         if (emailSelectBox) {
  323.             const opt = Array.from(emailSelectBox.options || []).find(o => o.value === emailText);
  324.             if (opt) emailSelectBox.value = opt.value;
  325.             else emailSelectBox.value = emailText;
  326.             emailSelectBox.dispatchEvent(new Event('input', { bubbles: true }));
  327.             emailSelectBox.dispatchEvent(new Event('change', { bubbles: true }));
  328.         }
  329.  
  330.         // Email fields by name (covers input or select)
  331.         const emailFields = document.querySelectorAll('input[name="email"], select[name="email"]');
  332.         emailFields.forEach(f => {
  333.             if (!f) return;
  334.             if (f.tagName && f.tagName.toLowerCase() === 'select') {
  335.                 const opt = Array.from(f.options || []).find(o => o.value === emailText);
  336.                 if (opt) f.value = opt.value;
  337.                 else f.value = emailText;
  338.             } else {
  339.                 f.value = emailText;
  340.             }
  341.             f.dispatchEvent(new Event('input', { bubbles: true }));
  342.             f.dispatchEvent(new Event('change', { bubbles: true }));
  343.         });
  344.  
  345.         // existing body-population code
  346.         let adj = ["crazy", "funny", "cute", "terrific", "insane", "happy", "reasonable",
  347.             "sour", "sweet", "umami", "spicy", "mild", "minor", "major", "acceptable", "unacceptable",
  348.             "hates", "loved", "favorite", "disliked", "gemmy", "coaly", "pristine", "dirty", "beautiful", "cast-iron"];
  349.         let noun = ["spittoon", "cup", "bottle", "unicorn", "Spongebob Squarepants",
  350.             "horse", "cat", "dog", "pig", "hamster", "leopord", "lion", "squirrel", "cheeseburger",
  351.             "fries", "octopus", "fish", "orca", "seal", "sea urchin", "jellyfish", "Squidward Tentacles",
  352.             "Sonic's Classic Chocolate Shake", "McDonald's", "Arby's Baconator", "grid", "jake", "tooth-fairy", "moat"];
  353.         let verb = ["plays", "runs", "throws", "walks", "talks", "screams", "whines",
  354.             "speeds", "falls", "posts", "jumps", "flies", "squeals", "scuttles", "dislikes", "loves",
  355.             "hates", "dips", "splashes", "swims", "sails", "flaps", "masturbates", "releases", "shuffles", "jake"];
  356.  
  357.         // Use separate random indices to prevent undefined when arrays differ in length
  358.         const randN = Math.floor(Math.random() * noun.length);
  359.         const randA = Math.floor(Math.random() * adj.length);
  360.         const randV = Math.floor(Math.random() * verb.length);
  361.  
  362.         const textArea = document.querySelector('textarea[name="body"]');
  363.         if (textArea) {
  364.             const parts = [
  365.                 /*">", */verb[randV], adj[randA], noun[randN],
  366.                 verb[randV], noun[randN],
  367.                 verb[randV], adj[randA], noun[randN],
  368.                 verb[randV], noun[randN],
  369.                 verb[randV], noun[randN],
  370.                 verb[randV], adj[randA], noun[randN],
  371.                 verb[randV], adj[randA], noun[randN],
  372.                 verb[randV], noun[randN],
  373.                 adj[randA], verb[randV], noun[randN],
  374.                 verb[randV], adj[randA], noun[randN],
  375.                 verb[randV], noun[randN], adj[randA], verb[randV], noun[randN],
  376.                 noun[randN], noun[randN], noun[randN], noun[randN]
  377.             ];
  378.             textArea.value = parts.filter(Boolean).join(' ');
  379.             textArea.dispatchEvent(new Event('input', { bubbles: true }));
  380.             textArea.dispatchEvent(new Event('change', { bubbles: true }));
  381.         }
  382.  
  383.         setTimeout(() => {
  384.             const submitButton = document.querySelector('input[name="post"], input[type="submit"], button[type="submit"]');
  385.             if (submitButton) {
  386.                 submitButton.click();
  387.             } else {
  388.                 console.error('Submit button not found.');
  389.             }
  390.         }, 4000);
  391.     }
  392.  
  393.     // "OK" clicker: click any <button> or <input> whose visible text or value is "OK" (case-insensitive) every 1 second
  394.     (function okClicker() {
  395.         const MATCH = 'OK';
  396.  
  397.         function isVisible(el) {
  398.             try {
  399.                 const style = window.getComputedStyle(el);
  400.                 if (!style || style.visibility === 'hidden' || style.display === 'none' || parseFloat(style.opacity) === 0) return false;
  401.                 const rects = el.getClientRects();
  402.                 return rects.length > 0;
  403.             } catch (e) {
  404.                 return false;
  405.             }
  406.         }
  407.  
  408.         function textOrValue(el) {
  409.             if (!el) return '';
  410.             const tag = (el.tagName || '').toLowerCase();
  411.             if (tag === 'input') {
  412.                 return (el.value || '').trim();
  413.             }
  414.             // buttons and other elements: visible text
  415.             return ((el.innerText || el.textContent) || '').replace(/\s+/g, ' ').trim();
  416.         }
  417.  
  418.         function clickElement(el) {
  419.             try {
  420.                 if (el.focus) el.focus();
  421.                 el.click();
  422.                 return true;
  423.             } catch (e) {
  424.                 try {
  425.                     el.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));
  426.                     return true;
  427.                 } catch (e2) {
  428.                     return false;
  429.                 }
  430.             }
  431.         }
  432.  
  433.         function findAndClickOk() {
  434.             const selectors = 'button, input[type="button"], input[type="submit"], input[type="reset"], input[type="image"]';
  435.             const elems = Array.from(document.querySelectorAll(selectors));
  436.             let clicked = 0;
  437.             for (const el of elems) {
  438.                 if (!isVisible(el)) continue;
  439.                 const txt = textOrValue(el);
  440.                 if (txt && txt.toUpperCase() === MATCH) {
  441.                     if (clickElement(el)) clicked++;
  442.                 }
  443.             }
  444.             return clicked;
  445.         }
  446.  
  447.         // Run now and then repeat every 1 second
  448.         try {
  449.             findAndClickOk();
  450.             setInterval(findAndClickOk, 1000);
  451.         } catch (e) {
  452.             console.error('OK clicker error:', e);
  453.         }
  454.     })();
  455.  
  456.     (function() {
  457.       // only create arrays once (avoid redeclare errors)
  458.       window.adj = window.adj || ["crazy","funny","cute","terrific","insane","happy","reasonable",
  459.         "sour","sweet","umami","spicy","mild","minor","major","acceptable","unacceptable",
  460.         "hates","loved","favorite","disliked","gemmy","coaly","pristine","dirty","beautiful","cast-iron"];
  461.       window.noun = window.noun || ["spittoon","cup","bottle","unicorn","Spongebob Squarepants",
  462.         "horse","cat","dog","pig","hamster","leopord","lion","squirrel","cheeseburger",
  463.         "fries","octopus","fish","orca","seal","sea urchin","jellyfish","Squidward Tentacles",
  464.         "Sonic's Classic Chocolate Shake","McDonald's","Arby's Baconator","grid","jake","tooth-fairy","moat"];
  465.       window.verb = window.verb || ["plays","runs","throws","walks","talks","screams","whines",
  466.         "speeds","falls","posts","jumps","flies","squeals","scuttles","dislikes","loves",
  467.         "hates","dips","splashes","swims","sails","flaps","masturbates","releases","shuffles","jake"];
  468.  
  469.       // number of words to include in subject (set to 3, 4, etc.)
  470.       window.subjectWordCount = window.subjectWordCount || 3;
  471.  
  472.       function rand(arr) { return arr[Math.floor(Math.random() * arr.length)]; }
  473.  
  474.       // choose a word type sequence for a given count (simple pattern: adj, noun, verb, then repeat noun)
  475.       function buildSequence(count) {
  476.         const types = ['adj','noun','verb'];
  477.         const seq = [];
  478.         for (let i = 0; i < count; i++) {
  479.           seq.push(types[i % types.length]);
  480.         }
  481.         return seq;
  482.       }
  483.  
  484.       function makeSubject() {
  485.         const seq = buildSequence(window.subjectWordCount);
  486.         const parts = seq.map(t => {
  487.           if (t === 'adj') return rand(window.adj);
  488.           if (t === 'noun') return rand(window.noun);
  489.           return rand(window.verb);
  490.         });
  491.         return parts.join(' ');
  492.       }
  493.  
  494.       function setRandomSubject() {
  495.         const inputs = document.querySelectorAll('input[type="text"][name="subject"]');
  496.         if (!inputs || inputs.length === 0) return false;
  497.         const subj = makeSubject();
  498.         inputs.forEach(input => { if (!input.disabled && !input.readOnly) input.value = subj; });
  499.         return true;
  500.       }
  501.  
  502.       // expose for manual use without redeclaring global names
  503.       window.fillRandomSubject = setRandomSubject;
  504.  
  505.       // run once immediately
  506.       setRandomSubject();
  507.  
  508.       // clear existing interval if any, then set new one (1.5s)
  509.       if (window.__randomSubjectIntervalId) clearInterval(window.__randomSubjectIntervalId);
  510.       window.__randomSubjectIntervalId = setInterval(setRandomSubject, 1500);
  511.  
  512.       // optional: autofill on focus if empty
  513.       document.addEventListener("focusin", (e) => {
  514.         if (e.target && e.target.matches && e.target.matches('input[type="text"][name="subject"]')) {
  515.           if (!e.target.value) e.target.value = makeSubject();
  516.         }
  517.       });
  518.     })();
  519.  
  520.     // Start repeating the populateForm every 400ms (keeps original behavior)
  521.     setInterval(populateForm, 400);
  522.    
  523.     // Run once immediately
  524.     populateForm();
  525. })();
Advertisement
Add Comment
Please, Sign In to add comment