Skip to content

Instantly share code, notes, and snippets.

@un4ckn0wl3z
Created December 19, 2025 03:10
Show Gist options
  • Select an option

  • Save un4ckn0wl3z/0c2b5b4fe359d8c92f41d038e7c1e030 to your computer and use it in GitHub Desktop.

Select an option

Save un4ckn0wl3z/0c2b5b4fe359d8c92f41d038e7c1e030 to your computer and use it in GitHub Desktop.
Crop and Get links in Webpage
// ==UserScript==
// @name Ctrl Drag Crop + Auto Scroll (Anchored)
// @namespace https://un4ckn0wl3z.dev/tm/crop-links-scroll-fixed
// @version 1.3
// @description Ctrl + drag to crop, auto-scroll with anchored start point
// @match *://*/*
// @grant GM_setClipboard
// ==/UserScript==
(function () {
'use strict';
let overlay, box;
let startX, startY_doc;
let selecting = false;
let scrollTimer = null;
const EDGE = 40;
const SPEED = 20;
const INTERVAL = 16;
function createOverlay() {
overlay = document.createElement('div');
overlay.style.cssText = `
position: fixed;
inset: 0;
z-index: 999999;
cursor: crosshair;
background: rgba(0,0,0,0.05);
`;
box = document.createElement('div');
box.style.cssText = `
position: absolute;
border: 2px dashed red;
background: rgba(255,0,0,0.15);
pointer-events: none;
`;
overlay.appendChild(box);
document.body.appendChild(overlay);
}
function destroyOverlay() {
stopScroll();
overlay?.remove();
overlay = null;
box = null;
}
function intersect(a, b) {
return !(
b.right < a.left ||
b.left > a.right ||
b.bottom < a.top ||
b.top > a.bottom
);
}
function extractLinks(rect) {
return [...document.querySelectorAll('a')]
.filter(a => intersect(rect, a.getBoundingClientRect()))
.map(a => ({
href: a.href,
text: a.innerText.trim()
}));
}
function startScroll(dir) {
if (scrollTimer) return;
scrollTimer = setInterval(() => {
window.scrollBy(0, dir * SPEED);
}, INTERVAL);
}
function stopScroll() {
clearInterval(scrollTimer);
scrollTimer = null;
}
document.addEventListener('mousedown', e => {
if (!e.ctrlKey || e.button !== 0) return;
e.preventDefault();
selecting = true;
startX = e.clientX;
startY_doc = e.clientY + window.scrollY;
createOverlay();
});
document.addEventListener('mousemove', e => {
if (!selecting) return;
const curX = e.clientX;
const curY_doc = e.clientY + window.scrollY;
const left = Math.min(startX, curX);
const right = Math.max(startX, curX);
const top_doc = Math.min(startY_doc, curY_doc);
const bottom_doc = Math.max(startY_doc, curY_doc);
// Convert document Y back to viewport Y
box.style.left = `${left}px`;
box.style.top = `${top_doc - window.scrollY}px`;
box.style.width = `${right - left}px`;
box.style.height = `${bottom_doc - top_doc}px`;
// Auto scroll
if (e.clientY > window.innerHeight - EDGE) {
startScroll(1);
} else if (e.clientY < EDGE) {
startScroll(-1);
} else {
stopScroll();
}
});
document.addEventListener('mouseup', e => {
if (!selecting) return;
selecting = false;
stopScroll();
const endY_doc = e.clientY + window.scrollY;
const rect = {
left: Math.min(startX, e.clientX),
right: Math.max(startX, e.clientX),
top: Math.min(startY_doc, endY_doc) - window.scrollY,
bottom: Math.max(startY_doc, endY_doc) - window.scrollY
};
const links = extractLinks(rect);
const output = links
//.map(l => `${l.href}${l.text ? ' | ' + l.text : ''}`)
.map(l => `${l.href}`)
.join('\n');
GM_setClipboard(output);
console.log('Extracted links:', links);
alert(`Extracted ${links.length} links (copied)`);
destroyOverlay();
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment