Created
October 19, 2025 16:10
-
-
Save anthonyholmes/6b252f141e02c69c952df15815e19479 to your computer and use it in GitHub Desktop.
Jewel-Osco sucks. Automate clipping all their coupons.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (async function clickAllCoupons(delay = 600) { | |
| // Deep query that also searches open shadow roots | |
| function queryAllDeep(selector, root = document) { | |
| let found = [...root.querySelectorAll(selector)]; | |
| const all = root.querySelectorAll('*'); | |
| for (const el of all) { | |
| if (el.shadowRoot) { | |
| found = found.concat(queryAllDeep(selector, el.shadowRoot)); | |
| } | |
| } | |
| return found; | |
| } | |
| // Collect likely coupon buttons (id, class, aria-label, or visible text) | |
| let candidates = queryAllDeep( | |
| 'button.couponBtn-size, button[id^="couponAddBtn"], button[aria-label*="Clip Coupon" i]' | |
| ); | |
| // Include buttons that display "Clip Coupon" text even if they lack the above attrs | |
| candidates = candidates.concat( | |
| queryAllDeep('button').filter(b => /clip coupon/i.test(b.textContent || '')) | |
| ); | |
| // Dedupe | |
| const uniq = [...new Set(candidates)]; | |
| // Filter to clickable targets: enabled, visible, not already "Clipped" | |
| const targets = uniq.filter(btn => { | |
| const txt = (btn.textContent || btn.getAttribute('aria-label') || '').toLowerCase(); | |
| const notClipped = !/clipped|remove|added/.test(txt); | |
| const visible = !!(btn.offsetParent || btn.getClientRects().length); | |
| const enabled = !btn.disabled && !btn.getAttribute('aria-disabled'); | |
| return notClipped && visible && enabled; | |
| }); | |
| if (!targets.length) { | |
| console.log('No clip-able coupon buttons found.'); | |
| return; | |
| } | |
| console.log(`Found ${targets.length} coupon buttons. Clicking with ~${delay}ms spacing...`); | |
| for (let i = 0; i < targets.length; i++) { | |
| const btn = targets[i]; | |
| try { | |
| btn.scrollIntoView({ block: 'center' }); | |
| btn.click(); | |
| console.log(`Clicked ${i + 1}/${targets.length}`); | |
| await new Promise(r => setTimeout(r, delay)); | |
| } catch (e) { | |
| console.warn(`Failed clicking button ${i + 1}:`, e); | |
| } | |
| } | |
| console.log('Done.'); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment