Instagram full-size media scroll wall

Creates a scrollable wall of full-size images from any user's instagram page. Just click "Load Images" at the top.

目前为 2021-04-25 提交的版本。查看 最新版本

// ==UserScript==
// @name        Instagram full-size media scroll wall
// @namespace   driver8.net
// @author      driver8
// @description Creates a scrollable wall of full-size images from any user's instagram page. Just click "Load Images" at the top.
// @match       *://*.instagram.com/*
// @exclude     https://www.instagram.com/p/*
// @exclude     https://instagram.com/p/*
// @version     0.1.7
// @grant       none
// ==/UserScript==

(function() {
    'use strict';

    console.log('hi insta scroll');
    // https://www.instagram.com/graphql/query/?query_hash=<hash>&variables={%22shortcode%22:%22<shortcode>%22}

    const IMAGES_PER_QUERY = 12;
    const NTH_TO_LAST_IMAGE = 3;
    const HEIGHT_PCT = .8;
    const WIDTH_PCT = .49;
    const VID_VOLUME = 0.02;
    let m = document.body.innerHTML.match(/profilePage_(\d+)/);
    var userId = m && m[1];
    var notLoaded = true;

    function getQueryHash() {
        let allScripts = Array.from(document.getElementsByTagName('script'));
        let PostPageContainer = allScripts.find(el => el.src && el.src.match(/ProfilePageContainer.js/));
        let ConsumerLibCommons = allScripts.find(el => el.src && el.src.match(/ConsumerLibCommons.js/));
        let Consumer = allScripts.find(el => el.src && el.src.match(/Consumer.js/));

        var query_hash = false,
            query_id = false;

        fetch(ConsumerLibCommons.src)
        .then(resp => {
            console.log('resp 1', resp);
            return resp.text();
        })
        .then(text => {
            let m = text.match(/profilePosts\.byUserId\.get.*?queryId:"([a-f0-9]+)"/); //profilePosts.byUserId.get(n))||void 0===s?void 0:s.pagination},queryId:"e5555555555555555555555555555508"
            console.log('queryId m', m);
            query_id = m && m[1];
            query_id && notLoaded && loadImages(query_id, query_hash);
            // query_id && query_hash && loadImages(query_id, query_hash);
        });

        fetch(PostPageContainer.src)
        .then(resp => {
            console.log('resp 1', resp);
            return resp.text();
        })
        .then(text => {
            let m = text.match(/profilePosts\.byUserId\.get.*?queryId:"([a-f0-9]+)"/); //profilePosts.byUserId.get(n))||void 0===s?void 0:s.pagination},queryId:"e5555555555555555555555555555508"
            console.log('queryId m', m);
            query_id = m && m[1];
            query_id && notLoaded && loadImages(query_id, query_hash);
            // query_id && query_hash && loadImages(query_id, query_hash);
        });

        // l.pagination},queryId:"15b55555555555555555555555555551"
        fetch(Consumer.src)
        .then(resp => {
            console.log('resp 1', resp);
            return resp.text();
        })
        .then(text => {
            //let m = text.match(/l\.pagination\},queryId:"([a-f0-9]+)"/); //const s="05555555555555555555555555555554",E="
            let m = text.match(/profilePosts\.byUserId\.get[^;]+queryId:\s*"([a-f0-9]+)"/);
            console.log('queryId m', m);
            query_id = m && m[1];
            query_id && notLoaded && loadImages(query_id, query_hash);
        });

//         fetch(Consumer.src)
//         .then(resp => {
//             console.log('resp 1', resp);
//             return resp.text();
//         })
//         .then(text => {
//             let m = text.match(/const s="([a-f0-9]+)",E="/); //const s="05555555555555555555555555555554",E="
//             m = m || text.match(/var u="([a-f0-9]+)",s="/);
//             console.log('query_hash m', m);
//             query_hash = m && m[1];
//             query_hash && query_id && loadImages(query_id, query_hash);
//         });
    }

    // https://www.instagram.com/graphql/query/?query_hash=<queryhash>&variables=%7B%22id%22%3A%22<profle_id>%22%2C%22first%22%3A12%2C%22after%22%3A%22<after_code>%3D%3D%22%7D
    function loadImages(query_id, query_hash, after) {
        notLoaded = false;
        console.log('id', query_id, 'hash', query_hash);

        // let userIdMetaTag = document.querySelector('head > meta[property="instapp:owner_user_id"]');
        // let userId = userIdMetaTag && userIdMetaTag.content;
        let m = document.body.innerHTML.match(/profilePage_(\d+)/);
        userId = userId || (m && m[1]);
        if (!userId) return;
        let queryVariables = {"id": userId, "first": IMAGES_PER_QUERY};
        if (after) queryVariables.after = after;
        let queryVariablesString = encodeURIComponent(JSON.stringify(queryVariables));
        let imageListQueryUrl = `https://www.instagram.com/graphql/query/?query_hash=${query_id}&variables=${queryVariablesString}`;

        fetch(imageListQueryUrl, { responseType: 'json' })
        .then(resp => {
            console.log('resp 1', resp);
            return resp.json();
        })
        .then(json => {
            console.log('json', json);

            let timelineMedia = json.data.user.edge_owner_to_timeline_media;
            let end_cursor = timelineMedia.page_info.end_cursor;
            let mediaList = timelineMedia.edges.map(n => n.node);
            console.log('media list', mediaList);

            let bigContainer = document.querySelector('#igBigContainer');
            // Create the main container if it doesn't exist
            if (!bigContainer) {
                let tempDiv = document.createElement('div');
                tempDiv.innerHTML = `<div id="igBigContainer" style="background-color: #112;width: 100%;height: 100%;z-index: 999;position: fixed;top: 0;left: 0;overflow: scroll;">
                    <div id="igAllImages" style="display:block; text-align:center;"></div></div>`;
                bigContainer = tempDiv.firstElementChild;
                document.body.innerHTML = '';
                document.body.appendChild(bigContainer);

                let imgStyle = document.createElement('style');
                imgStyle.type = 'text/css';
                setMaxSize(imgStyle);
                document.body.appendChild(imgStyle);
                window.addEventListener('resize', evt => setMaxSize(imgStyle));
                styleIt();
            }
            let innerContainer = bigContainer.firstElementChild;

            for (let media of mediaList) {
                addMedia(media, innerContainer);
            }

            if (end_cursor) {
                console.log('end_cursor', end_cursor);
                let triggerImage = document.querySelector('#igAllImages a:nth-last-of-type(3)');
                bigContainer.onscroll = (evt) => {
                    let vh = document.documentElement.clientHeight || window.innerHeight || 0;
                    if (triggerImage.getBoundingClientRect().top - 800 < vh) {
                        bigContainer.onscroll = null;
                        console.log('loading next set of images');
                        loadImages(query_id, query_hash, end_cursor);
                    }

                }
            }
        });
    }

    function getBestImage(media) {
        return media.display_resources.reduce((a, b) => a.width > b.width ? a : b).src;
    }

    function addMedia(media, container) {
        let shortcode = media.shortcode;
        let medias = media.edge_sidecar_to_children ? media.edge_sidecar_to_children.edges.map(n => n.node) : [ media ];
        for (let m of medias) {
            let a = document.createElement('a');
            a.href = `https://www.instagram.com/p/${shortcode}/`;
            if (m.is_video) {
                let vid = document.createElement('video');
                vid.src = m.video_url;
                vid.controls = true;
                vid.volume = VID_VOLUME;
                a.textContent = 'Link';
                container.appendChild(vid);
                container.appendChild(a);
            } else {
                a.innerHTML += `<img src="${getBestImage(m)}">`;
                container.appendChild(a);
            }
        }
    }

    function setMaxSize(userStyle) {
        let vw = document.documentElement.clientWidth || window.innerWidth || 0;
        let vh = document.documentElement.clientHeight || window.innerHeight || 0;
        userStyle.innerHTML = `
#igAllImages img, #igAllImages video {
  max-height: ${vh * HEIGHT_PCT}px;
  max-width: ${vw * WIDTH_PCT}px;
}
`;
    }

    function styleIt() {
        let userStyle = document.createElement('style');
        userStyle.type = 'text/css';
        userStyle.innerHTML = `
#igAllImages video {
  border: green solid 2px;
`;
        document.body.appendChild(userStyle);
    }

    function startUp() {
        let tempDiv = document.createElement('div');
        tempDiv.innerHTML = `<div style="margin: 20px;font-size: 18px;font-weight: bold;color: #3897F0; cursor: pointer;"><h2>Load Images</h2></div>`;
        let loadButton = tempDiv.firstElementChild;
        loadButton.onclick = getQueryHash;

        (function insertButton() {
            let insAt = document.querySelector('.ZcHy5, ._47KiJ');
            if (insAt) {
                insAt.parentNode.insertBefore(loadButton, insAt);
            } else {
                window.setTimeout(insertButton, 20);
            }
        })();
    }
    startUp();

})();