Instagram Link Collector

Collect Instagram post URLs during auto-scroll. Edge hover UI, idle-stop, clipboard copy, .txt export.

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği yüklemek için Tampermonkey gibi bir uzantı yüklemeniz gerekir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

Bu stili yüklemek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için Stylus gibi bir uzantı kurmanız gerekir.

Bu stili yükleyebilmek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı kurmanız gerekir.

Bu stili yükleyebilmek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

(Zateb bir user-style yöneticim var, yükleyeyim!)

// ==UserScript==
// @name         Instagram Link Collector
// @namespace    https://www.instagram.com/
// @version      1.1.5
// @description  Collect Instagram post URLs during auto-scroll. Edge hover UI, idle-stop, clipboard copy, .txt export.
// @author       Gemini 3 Pro (previously ChatGPT 5.2 Thinking)
// @icon         https://web.archive.org/web/20171228000551im_/https://www.instagram.com/static/images/ico/favicon.ico/dfa85bb1fd63.ico
// @match        https://www.instagram.com/*
// @grant        GM_addStyle
// @grant        GM_setClipboard
// @license      MIT
// ==/UserScript==

(function () {
    "use strict";

    var collected = new Set();
    var intervalId = null;
    var countdownInterval = null;
    var lastHeight = 0;
    var idleCounter = 0;

    var DEFAULT_IDLE_SECONDS = 33;

    var TAB_W = 18;
    var TAB_H = 44;
    var TAB_TEXT_PAD = TAB_W + 9;
    var PANEL_W = 340;

    var hideTimer = null;
    var isShown = false;
    var pinnedUntil = 0;

    function nowMs() { return Date.now(); }

    function pinBriefly(ms) {
        pinnedUntil = nowMs() + (ms || 2000);
        showPanel(true);
    }

    function shouldBlockHide() {
        return nowMs() <= pinnedUntil || intervalId !== null || countdownInterval !== null;
    }

    function normalizeUrl(u) {
        if (!u) return "";
        return u.split("?")[0].split("#")[0].replace(/\/+$/, "");
    }

    function updateOutput() {
        var list = Array.from(collected).sort();
        output.value = list.join("\n");
        counter.textContent = list.length + " links";
        if (!intervalId && status.textContent === "Scrolling...") status.textContent = "Idle";
        if (intervalId && status.textContent !== "Scrolling...") status.textContent = "Scrolling...";
    }

    function isLoaderVisible() {
        return !!document.querySelector('svg[aria-label="Loading..."]');
    }

    function collectLinks() {
        var links = document.querySelectorAll('a[href*="/p/"]');
        var initial = collected.size;

        for (var i = 0; i < links.length; i++) {
            var href = links[i].href;
            if (!href) continue;
            collected.add(normalizeUrl(href));
        }

        if (collected.size !== initial) {
            updateOutput();
            return true;
        }
        return false;
    }

    function stopScroll(reason) {
        if (intervalId) {
            clearInterval(intervalId);
            intervalId = null;
        }
        if (countdownInterval) {
            clearInterval(countdownInterval);
            countdownInterval = null;
        }
        status.textContent = reason || "Stopped";
        updateOutput();
    }

    function autoSave() {
        var urls = Array.from(collected);
        if (!urls.length) return;

        var username = "instagram";
        var pathMatch = window.location.pathname.match(/^\/([a-zA-Z0-9_.]+)/);
        if (pathMatch && pathMatch[1]) {
            var bad = ["p", "explore", "direct", "reels", "stories", "accounts"];
            if (bad.indexOf(pathMatch[1]) === -1) username = pathMatch[1];
        }

        var d = new Date();
        var yyyy = d.getFullYear();
        var mm = String(d.getMonth() + 1).padStart(2, "0");
        var dd = String(d.getDate()).padStart(2, "0");
        var dateStr = yyyy + "-" + mm + "-" + dd;

        var filename = username + "_instagram-urls_" + dateStr + ".txt";

        var blob = new Blob([urls.join("\n")], { type: "text/plain" });
        var url = URL.createObjectURL(blob);
        var a = document.createElement("a");
        a.href = url;
        a.download = filename;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
    }

    function autoScrollTick() {
        var currentHeight = document.body.scrollHeight;
        window.scrollBy(0, window.innerHeight);

        var newLinksFound = collectLinks();
        var idleThresholdTicks = Math.max(1, Math.floor(parseInt(idleInput.value, 10) / 2));

        if (newLinksFound || currentHeight > lastHeight || isLoaderVisible()) {
            idleCounter = 0;
            lastHeight = currentHeight;
        } else {
            idleCounter++;
        }

        if (idleCounter >= idleThresholdTicks) {
            stopScroll("Auto-stopped (idle)");
            autoSave();
        }
    }

    function startScroll() {
        if (intervalId || countdownInterval) return;

        var countdown = 3;
        status.textContent = "Starting in " + countdown + "...";
        pinBriefly(3000);

        countdownInterval = setInterval(function () {
            countdown--;
            if (countdown > 0) {
                status.textContent = "Starting in " + countdown + "...";
            } else {
                clearInterval(countdownInterval);
                countdownInterval = null;

                lastHeight = document.body.scrollHeight;
                idleCounter = 0;
                intervalId = setInterval(autoScrollTick, 2000);
                status.textContent = "Scrolling...";
                collectLinks();
                updateOutput();
            }
        }, 1000);
    }

    function copyAll() {
        GM_setClipboard(output.value || "");
        status.textContent = "Copied";
        setTimeout(function () { status.textContent = intervalId ? "Scrolling..." : "Idle"; }, 900);
    }

    function downloadTxt() {
        autoSave();
        status.textContent = "Downloaded";
        setTimeout(function () { status.textContent = intervalId ? "Scrolling..." : "Idle"; }, 900);
    }

    function clearAll() {
        collected.clear();
        updateOutput();
        status.textContent = "Cleared";
        setTimeout(function () { status.textContent = intervalId ? "Scrolling..." : "Idle"; }, 900);
    }

    GM_addStyle(
        '#ig_hover_tab{' +
        'position:fixed;left:0;top:50%;width:' + TAB_W + 'px;height:' + TAB_H + 'px;margin-top:-' + Math.floor(TAB_H / 2) + 'px;' +
        'z-index:100000;cursor:pointer;opacity:0.7;background-color:#bdc5c8;' +
        'border:1px solid #abb0b3;border-left:none;border-radius:0 5px 5px 0;' +
        'display:flex;align-items:center;justify-content:center;' +
        '}' +
        '#ig_hover_tab:hover{opacity:1;}' +
        '#ig_hover_tab svg{display:block;}' +
        '#ig_panel{' +
        'position:fixed;left:0;top:50%;width:' + PANEL_W + 'px;z-index:99999;' +
        'transform:translateX(-100%);transition:transform 140ms linear,opacity 140ms linear;opacity:0.92;' +
        'background:rgba(0,0,0,0.75);color:#fff;padding:10px 10px 10px ' + TAB_TEXT_PAD + 'px;' +
        'border-radius:0 8px 8px 0;font-size:12px;box-shadow:0 2px 10px rgba(0,0,0,0.35);' +
        '}' +
        '#ig_panel.ig_show{transform:translateX(0);opacity:1;}' +
        '#ig_title{font-weight:700;margin:0 0 4px 0;}' +
        '#ig_row{display:flex;align-items:center;justify-content:space-between;gap:8px;margin:0;}' +
        '#ig_status{opacity:0.9;font-size:11px;}' +
        '#ig_actions_row1{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px;margin-bottom:6px;}' +
        '#ig_actions_row2{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;}' +
        '#ig_panel button{' +
        'padding:4px 10px;font-size:12px;cursor:pointer;background:rgba(255,255,255,0.08);color:#fff;' +
        'border:1px solid rgba(255,255,255,0.25);border-radius:999px;line-height:1.2;user-select:none;' +
        '}' +
        '#ig_panel button:hover{background:rgba(255,255,255,0.18);}' +
        '#ig_panel button:active{background:rgba(255,255,255,0.28);}' +
        // CHANGE: Added !important and solid colors to force visibility
        '#ig_start{border:1px solid #4CAF50 !important; box-shadow: 0 0 3px #4CAF50;}' +
        '#ig_stop{border:1px solid #F44336 !important; box-shadow: 0 0 3px #F44336;}' +
        '#ig_clear{border:1px solid #FFEB3B !important; box-shadow: 0 0 3px #FFEB3B; color: #fff;}' +
        '#ig_idle_wrap{display:flex;align-items:center;gap:6px;}' +
        '#ig_idle_wrap span{font-size:11px;opacity:0.9;}' +
        '#ig_idle{width:56px;font-size:12px;padding:2px 6px;border-radius:8px;border:1px solid rgba(255,255,255,0.25);background:rgba(0,0,0,0.35);color:#fff;}' +
        '#ig_output{width:100%;height:180px;margin-top:6px;font-size:11px;resize:vertical;}'
    );

    var tab = document.createElement("div");
    tab.id = "ig_hover_tab";
    tab.innerHTML =
        '<svg width="12" height="12" viewBox="0 0 12 12" aria-hidden="true">' +
        '<path id="ig_arrow_path" d="M4 2 L8 6 L4 10 Z" fill="#2b2f33"></path>' +
        '</svg>';
    document.body.appendChild(tab);

    var arrowPath = document.getElementById("ig_arrow_path");

    var panel = document.createElement("div");
    panel.id = "ig_panel";
    panel.innerHTML =
        '<div id="ig_header">' +
            '<div id="ig_title">Instagram Link Collector</div>' +
            '<div id="ig_row">' +
                '<div id="ig_counter">0 links</div>' +
                '<div id="ig_status">Idle</div>' +
            '</div>' +
        '</div>' +
        '<div id="ig_actions_row1">' +
            '<button id="ig_start" type="button">Start scroll</button>' +
            '<button id="ig_stop" type="button">Stop</button>' +
            '<button id="ig_copy" type="button">Copy</button>' +
            '<button id="ig_clear" type="button">Clear</button>' +
        '</div>' +
        '<div id="ig_actions_row2">' +
            '<button id="ig_txt" type="button">Download .txt</button>' +
            '<div id="ig_idle_wrap"><span>Idle (s)</span><input id="ig_idle" type="number" min="2" value="' + DEFAULT_IDLE_SECONDS + '"></div>' +
        '</div>' +
        '<textarea id="ig_output" readonly></textarea>';
    document.body.appendChild(panel);

    var headerWrap = document.getElementById("ig_header");
    var counter = document.getElementById("ig_counter");
    var status = document.getElementById("ig_status");
    var output = document.getElementById("ig_output");
    var idleInput = document.getElementById("ig_idle");

    function setArrow(open) {
        arrowPath.setAttribute("d", open ? "M8 2 L4 6 L8 10 Z" : "M4 2 L8 6 L4 10 Z");
    }

    function setPanelTopToTab() {
        var tabRect = tab.getBoundingClientRect();
        var headerH = headerWrap.getBoundingClientRect().height;
        var top = Math.round(tabRect.top - headerH - 6);
        panel.style.top = top + "px";
    }

    function showPanel(force) {
        if (hideTimer) {
            clearTimeout(hideTimer);
            hideTimer = null;
        }
        setPanelTopToTab();
        if (isShown && !force) return;
        isShown = true;
        panel.classList.add("ig_show");
        setArrow(true);
    }

    function scheduleHide() {
        if (shouldBlockHide()) return;

        if (hideTimer) clearTimeout(hideTimer);
        hideTimer = setTimeout(function () {
            if (shouldBlockHide()) return;
            isShown = false;
            panel.classList.remove("ig_show");
            setArrow(false);
        }, 140);
    }

    tab.addEventListener("mouseenter", function () { showPanel(false); });
    tab.addEventListener("mouseleave", scheduleHide);
    panel.addEventListener("mouseenter", function () { showPanel(true); });
    panel.addEventListener("mouseleave", scheduleHide);

    window.addEventListener("resize", function () {
        if (isShown) setPanelTopToTab();
    }, { passive: true });

    document.getElementById("ig_start").addEventListener("click", function (e) {
        e.preventDefault();
        pinBriefly(3000);
        startScroll();
    });

    document.getElementById("ig_stop").addEventListener("click", function (e) {
        e.preventDefault();
        pinBriefly(3000);
        stopScroll("Stopped");
    });

    document.getElementById("ig_copy").addEventListener("click", function (e) {
        e.preventDefault();
        pinBriefly(3000);
        copyAll();
    });

    document.getElementById("ig_txt").addEventListener("click", function (e) {
        e.preventDefault();
        pinBriefly(3000);
        downloadTxt();
    });

    document.getElementById("ig_clear").addEventListener("click", function (e) {
        e.preventDefault();
        pinBriefly(3000);
        clearAll();
    });

    setArrow(false);
    collectLinks();
    updateOutput();
})();