// UserScript
// @name         Bypass Instagram Login Redirects
// @namespace    http://tampermonkey.net/
// @version      2.1
// @description  a workaround to bypass Instagram login page
// @author       VeloxMoto
// @match        *://*/*
// @run-at       document-body
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @license      GNU GPLv3
// @downloadURL  https://update.greasyfork.org/scripts/420604/Bypass%20Instagram%20Login%20Redirects.user.js
// @updateURL    https://update.greasyfork.org/scripts/420604/Bypass%20Instagram%20Login%20Redirects.meta.js
// /UserScript

(async () => {
    // Instagram profile & post URLs regex
    const instaProfile = /(?<!^https\:\/\/www\.google\.com\/imgres\?imgurl.*)(?:https?\:\/\/)?(?:www\.)?(?<!help\.|api\.|business\.|about\.|lookaside\.)(?:(?:(?:instagram\.com|instagr\.am)\/accounts\/login\/\?next=)|(?:instagram\.com))(?:\/|%2f)(?!accounts|explore|developer|reel)([a-zA-Z._0-9]{3,})/i;
    const instaPost = /(?<!^https\:\/\/www\.google\.com\/imgres\?imgurl.*)(?:https?\:\/\/)?(?:www\.)?(?:(?:(?:instagram\.com|instagr\.am)\/accounts\/login\/\?next=)|(?:instagram\.com))(?:(?:\/|%2f)p|(?:\/|%2f)reel)(?:\/|%2f)([a-zA-Z._0-9-]+)/i;

    // Viewer class
    class Viewer {
        constructor(name, profilePrefix, postPrefix, identifier, reverseMediaId) {
            this.name = name;
            this.profilePrefix = profilePrefix;
            this.postPrefix = postPrefix;
            this.identifier = identifier;
            this.reverseMediaId = reverseMediaId;
        }
    }

    // Default viewer
    const defaultViewer = new Viewer("imginn", "https://imginn.com/", "https://imginn.com/p/", "shortcode", false);
    var currentViewer = await GM_getValue("viewerConfig", defaultViewer);

    // Menu Options
    const viewerOptions = [
        { name: "Picnob", func: picnob },
        { name: "Picuki", func: picuki },
        { name: "Dumpor", func: dumpor },
        { name: "imginn", func: imginn }
    ];

    // Register menu commands
    for (let option of viewerOptions) {
        if (currentViewer.name === option.name) {
            GM_registerMenuCommand(`${option.name} ✔️`, option.func);
        } else {
            GM_registerMenuCommand(option.name, option.func);
        }
    }

    async function switchViewer(name, profilePrefix, postPrefix, identifier, reverseMediaId) {
        if (currentViewer.name !== name) {
            await GM_setValue("viewerConfig", new Viewer(name, profilePrefix, postPrefix, identifier, reverseMediaId));
            location.reload();
            alert(`Viewer is now set to ${name}`);
        }
    }

    async function picuki() {
        await switchViewer("Picuki", "https://picuki.com/profile/", "https://picuki.com/media/", "mediaId", false);
    }

    async function dumpor() {
        await switchViewer("Dumpor", "https://dumpor.com/v/", "https://dumpor.com/c/", "mediaId", true);
    }

    async function imginn() {
        await switchViewer("imginn", "https://imginn.com/", "https://imginn.com/p/", "shortcode", false);
    }

    async function picnob() {
        await switchViewer("Picnob", "https://www.picnob.com/profile/", "https://www.picnob.com/post/", "shortcode", false);
    }

    function getMediaId(url) {
        const shortcode = url.match(instaPost)[1];
        if (currentViewer.identifier === "shortcode") {
            return shortcode;
        } else if (currentViewer.identifier === "mediaId") {
            const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
            let mediaId = BigInt(0);
            shortcode.split("").forEach(letter => {
                mediaId = BigInt(mediaId * 64n) + BigInt(alphabet.indexOf(letter));
            });
            return currentViewer.reverseMediaId ? mediaId.toString().split("").reverse().join("") : mediaId;
        }
    }

    function getUsername(url) {
        url = decodeURIComponent(url);
        return url.match(instaProfile)[1];
    }

    // Address checker function
    (() => {
        const address = window.location.href;
        if (/next=(?:\/|%2f)(?!accounts|explore|developer|reel)[a-zA-Z._0-9]{3,}/i.test(address)) {
            window.location.href = currentViewer.profilePrefix + getUsername(address);
        } else if (/next=(?:\/|%2f)(p|reel)(?:\/|%2f)[a-zA-Z._0-9-]+/i.test(address)) {
            window.location.href = currentViewer.postPrefix + getMediaId(address);
        }
    })();

    if (!document.cookie.includes("ds_user_id")) {
        let aTags = [];
        const body = document.documentElement || document.body;
        const observer = new MutationObserver(() => {
            aTags = [...new Set([...aTags, ...document.querySelectorAll("a")])];
            for (let x of aTags) {
                try {
                    if (instaProfile.test(decodeURIComponent(x.href))) {
                        x.addEventListener("click", event => event.stopPropagation(), true);
                        x.href = currentViewer.profilePrefix + getUsername(x.href);
                    }
                    if (instaPost.test(decodeURIComponent(x.href))) {
                        x.addEventListener("click", event => event.stopPropagation(), true);
                        x.href = currentViewer.postPrefix + getMediaId(x.href);
                    }
                } catch {} // ignore errors
            }
        });
        observer.observe(body, {
            subtree: true,
            childList: true,
            attributeFilter: ["href"]
        });
    }
})();

// references:
// https://stackoverflow.com/questions/16758316/where-do-i-find-the-instagram-media-id-of-a-image
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt
// https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
// https://codeburst.io/how-to-merge-arrays-without-duplicates-in-javascript-91c66e7b74cf
// https://stackoverflow.com/questions/19469881/remove-all-event-listeners-of-specific-type
// https://stackoverflow.com/questions/56024629/what-is-the-accesskey-parameter-of-gm-registermenucommand-and-how-to-use-it
Pub: 1724860079762 Edit: 1724861012982 Views: 0