您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Quick 'n dirty little userscript for accessing pictures and videos off of Instagram.
当前为
// ==UserScript== // @name Instagram Downloader // @namespace https://lawrenzo.com/p/direct-picture-link // @version 0.7 // @description Quick 'n dirty little userscript for accessing pictures and videos off of Instagram. // @author Lawrence Sim // @license WTFPL (http://www.wtfpl.net) // @match https://*.instagram.com/* // @grant none // ==/UserScript== (function() { var contextMenu, styles = { 'position': 'absolute', 'background': '#efefef', 'border-radius': '0.2em', 'box-shadow': '1px 1px 3px 1px rgba(0,0,0,0.4)', 'padding': '0.2em 0.5em', 'font-size': '0.85em', 'z-index': '999999' }; var openContextMenu = (evt, src, type) => { let a; if(!contextMenu) { contextMenu = document.createElement("div"); for(let key in styles) contextMenu.style[key] = styles[key]; a = document.createElement("a"); a.innerHTML = "> view direct source"; a.setAttribute("target", "_blank"); contextMenu.append(a); document.body.append(contextMenu); } a = a || contextMenu.querySelector("a"); a.setAttribute("href", src); if(type === "video") { a.setAttribute("download", "video"); a.innerHTML = "> view direct video"; } else { a.setAttribute("download", ""); a.innerHTML = "> view direct image"; } contextMenu.style.left = `${evt.pageX}px`; contextMenu.style.top = `${evt.pageY}px`; }; document.body.addEventListener("click", () => { if(!contextMenu) return; contextMenu.remove(); contextMenu = null; }); var fixVideoUrl = url => "https://scontent"+url.slice(url.indexOf(".cdninstagram.com")); var postRegExp = /https?:\/\/(?:www\.)?instagram\.com\/(?:p|reel|tv)\/([A-Za-z0-9\-\_]+)\//, mediaUrlMap = {}; var getMediaUrls = (postID, onComplete) => { return new Promise((resolve, reject) => { if(mediaUrlMap[postID]) { resolve(mediaUrlMap[postID]); return; } var req = new XMLHttpRequest(); req.onerror = () => reject(req); req.onreadystatechange = () => { if(req.readyState == XMLHttpRequest.DONE && req.status == 200) { let json, shortcodeMedia; try { json = JSON.parse(req.responseText); shortcodeMedia = json.graphql.shortcode_media; } catch(e) { } if(!shortcodeMedia) return; let mediaUrls; switch(shortcodeMedia.__typename) { case 'GraphImage': mediaUrls = [shortcodeMedia.display_url]; break; case 'GraphVideo': var url = shortcodeMedia.video_url; mediaUrls = [fixVideoUrl(shortcodeMedia.video_url)]; break; default: var edges = (shortcodeMedia.edge_sidecar_to_children && shortcodeMedia.edge_sidecar_to_children.edges) || []; mediaUrls = edges.map(edge => { return edge.node.is_video ? fixVideoUrl(edge.node.video_url) : edge.node.display_url; }); break; } mediaUrlMap[postID] = mediaUrls; resolve(mediaUrlMap[postID]); } }; req.open("GET", "https://www.instagram.com/p/"+postID+"/?__a=1"); req.send(); }); }; var link = (mutated, observer) => { mutated = mutated || [{target: document.body}]; let matchPost = window.location.href.match(postRegExp); matchPost ? linkPost(mutated, matchPost[1]) : linkFeed(mutated); }; var linkPicture = (img, src, multi) => { let btn = multi ? multi.querySelector("div[role='button']") : img.closest("div[role='button']"); if(!btn) return; btn.addEventListener("contextmenu", evt => { evt.preventDefault(); openContextMenu(evt, src || img.getAttribute("src")); }); img.setAttribute("ilnkd", 1); }; var linkVideo = (vid, src, multi) => { let btn = multi ? multi.firstChild : vid.parentNode.parentNode.parentNode.parentNode; if(!btn) return; btn.addEventListener("contextmenu", evt => { evt.preventDefault(); openContextMenu(evt, src, "video"); }); vid.setAttribute("ilnkd", 1); }; var linkFeed = mutated => { mutated.forEach(mutant => { mutant.target.querySelectorAll("article img").forEach(img => { if(img.getAttribute("ilnkd")) return; linkPicture(img, img.getAttribute("src"), img.closest("li > div")); }); //mutant.target.querySelectorAll("article video").forEach(vid => { // if(vid.getAttribute("ilnkd")) return; // linkVideo(vid, vid.getAttribute("src"), vid.closest("li > div")); //}); }); }; var linkPost = async function(mutated, postID, onComplete) { var mediaUrls = await getMediaUrls(postID); mutated.forEach(mutant => { mutant.target.querySelectorAll("li").forEach(li => { let media = li.querySelector("img, video"); if(!media || media.getAttribute("ilnkd") !== null) return; let thisIndex = 0; [li.previousSibling, li.nextSibling].find((sibling, i) => { if(!sibling) return; let siblingMedia = sibling && sibling.querySelector("img, video"), nearIndex = parseInt(siblingMedia && siblingMedia.getAttribute("ilnkd") || -1); if(~nearIndex) { thisIndex = nearIndex + (i ? -1 : 1); return true; } }); if(media.tagName === "IMG") { linkPicture(media, mediaUrls[thisIndex], media.closest("li > div")); } else { linkVideo(media, mediaUrls[thisIndex], media.closest("li > div")); } media.setAttribute("ilnkd", thisIndex); }); let media = mutant.target.querySelector("article img, article video"); if(media.getAttribute("ilnkd")) return; if(media.tagName === "IMG") { linkPicture(media, mediaUrls[0]); } else { linkVideo(media, mediaUrls[0]); } }); }; link(); var obs = new MutationObserver(link); obs.observe(document.body, {childList:true, subtree:true}); })();