您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Allows the user to open the original source of an instagram post or story
当前为
// ==UserScript== // @name Instagram Source Opener // @version 0.6 // @description Allows the user to open the original source of an instagram post or story // @author jomifepe // @icon https://www.instagram.com/favicon.ico // @require https://cdnjs.cloudflare.com/ajax/libs/arrive/2.4.1/arrive.min.js // @include https://www.instagram.com/* // @grant GM_addStyle // @namespace https://gf.qytechs.cn/users/192987 // ==/UserScript== (function() { "use strict"; /* this script relies a lot on class names, I'll keep an eye on changes */ const C_STORY_CONTAINER = "yS4wN"; const C_STORY_MEDIA_CONTAINER = "qbCDp"; const C_POST_IMG = "FFVAD"; const C_POST_VIDEO = "tWeCl"; const C_SINGLE_POST_CONTAINER = "JyscU"; const C_MULTI_POST_SCROLLER = "MreMs"; const C_MULTI_POST_LIST_ITEM = "_-1_m6"; const S_POSTS_CONTAINER = ".cGcGK > div > div"; const S_POST_BUTTONS = ".eo2As > section"; const C_BTN_STORY = "iso-story-btn"; const C_BTN_STORY_CONTAINER = "iso-story-container"; const C_POST_WITH_BUTTON = "iso-post"; const C_BTN_POST_OUTER_SPAN = "iso-post-container"; const C_BTN_POST = "iso-post-btn"; const C_BTN_POST_INNER_SPAN = "iso-post-span"; /* injects the needed CSS into DOM */ injectStyles(); /* triggered whenever a new instagram post is loaded on the feed */ document.arrive(`${S_POSTS_CONTAINER} article`, (node) => { generatePostButton(node); }); /* triggered whenever a single post is opened (on a profile) */ document.arrive(`.${C_SINGLE_POST_CONTAINER}`, (node) => { generatePostButton(node); }); /* triggered whenever a story is opened */ document.arrive(`.${C_STORY_CONTAINER}`, (node) => { generateStoryButton(node); }); window.onload = ((e) => { /* aditional check because sometimes the arive functions aren't triggered when the page is hard reloaded */ if (window.location.href.indexOf("instagram.com/p/") > -1) { let node = document.querySelector(`.${C_SINGLE_POST_CONTAINER}`); if (node != null) { generatePostButton(node); } } else if (window.location.href.indexOf("/stories/") > -1) { let node = document.querySelector(`.${C_STORY_CONTAINER}`); if (node == null) { generateStoryButton(node); } } }) function generateStoryButton(node) { /* exits if the story button already exists */ if (elementExistsInNode(`.${C_BTN_STORY_CONTAINER}`, node)) return; try { let buttonStoryContainer = document.createElement("span"); let buttonStory = document.createElement("button"); buttonStoryContainer.classList.add(C_BTN_STORY_CONTAINER); buttonStory.classList.add(C_BTN_STORY); buttonStoryContainer.setAttribute("title", "Open source"); buttonStory.addEventListener("click", () => openStoryContent(node)); buttonStoryContainer.appendChild(buttonStory); node.appendChild(buttonStoryContainer); } catch (err) { showDefaultErrorMessage(err); } } function generatePostButton(node) { /* exits if the post button already exists */ if (elementExistsInNode(`.${C_BTN_POST_OUTER_SPAN}`, node)) return; try { let buttonsContainer = node.querySelector(S_POST_BUTTONS); let newElementOuterSpan = document.createElement("span"); let newElementButton = document.createElement("button"); let newElementInnerSpan = document.createElement("span"); newElementOuterSpan.classList.add(C_BTN_POST_OUTER_SPAN); newElementButton.classList.add(C_BTN_POST); newElementInnerSpan.classList.add(C_BTN_POST_INNER_SPAN); newElementOuterSpan.setAttribute("title", "Open source"); newElementButton.addEventListener("click", () => openPostSourceFromSrcAttribute(node)); newElementButton.appendChild(newElementInnerSpan); newElementOuterSpan.appendChild(newElementButton); buttonsContainer.appendChild(newElementOuterSpan); node.classList.add(C_POST_WITH_BUTTON); } catch (err) { showDefaultErrorMessage(err); } } function openStoryContent(node) { try { let container = node.querySelector(`.${C_STORY_MEDIA_CONTAINER}`); let video = container.querySelector("video"); let image = container.querySelector("img"); if (video) { let videoElement = video.querySelector("source"); let videoSource = videoElement ? videoElement.getAttribute("src") : null; if (!videoSource) { throw "Failed to open video source"; } window.open(videoSource, "_blank"); } else if (image) { let imageSource = image.getAttribute("src"); if (!imageSource) { throw "Failed to open image source"; } window.open(imageSource, "_blank"); } else { throw "Failed to open media source" } } catch (err) { showDefaultErrorMessage(err); } } function openPostSourceFromSrcAttribute(node) { let nodeListItems = node.querySelectorAll(`.${C_MULTI_POST_LIST_ITEM}`); try { if (/* is multi post */ nodeListItems.length != 0) { let scroller = node.querySelector(`.${C_MULTI_POST_SCROLLER}`); let scrollerOffset = Math.abs((() => { let scrollerStyles = window.getComputedStyle(scroller); return parseInt(scrollerStyles.getPropertyValue("transform").split(",")[4]); })()); let mediaIndex = 0; if (scrollerOffset != 0) { let totalWidth = 0; nodeListItems.forEach(item => { let itemStyles = window.getComputedStyle(item); totalWidth += parseInt(itemStyles.getPropertyValue("width")); }); mediaIndex = ((scrollerOffset * nodeListItems.length) / totalWidth); } openPostMediaSource(nodeListItems[mediaIndex]); } else /* is single post */ { openPostMediaSource(node); } } catch (err) { showDefaultErrorMessage(err); } } function openPostMediaSource(nodeToSearchForMedia) { let image = nodeToSearchForMedia.querySelector(`.${C_POST_IMG}`); let video = nodeToSearchForMedia.querySelector(`.${C_POST_VIDEO}`); if (!image && !video) { throw "Failed to open source, no media found"; } window.open((video || image).getAttribute("src"), "_blank"); } function elementExistsInNode(selector, node) { return (node.querySelector(selector) != null); } function injectStyles() { let b64icon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAQAAABKfvVzAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QAAKqNIzIAAAAJcEhZcwAADdcAAA3XAUIom3gAAAAHdElNRQfiAxwDOBTFNFQBAAABKklEQVQ4y6WTvUoDQRSFvwkbxCqijY2okEIEixQpBMHKykIFC8H/yiew8Rl8i4ClCoJYWGkhaGXjrkmTbsUiTQoVf45Ndp1lZ8eIp7vnnnPvnBkG/gjjb2uAOcoW0fplnvaVRccAaIFZhnPqW3OkMa4Zz84o60RunAFoQm2bDDhgmSsOHad7BjBtrXFjb3jUi0Y8KUYV2hvQly77kH/qKTFIF33Id5MsHoMl30njdwoNlnw75SqaLDC45EnLYbDkW/lZOYMl3wRQTTW/4bQn3+jVoUK/YUqxPrSe1pGin26QD2wizVM15+7LDlykadIseswSbwzhgUpUeLWJO0nTHsOSpIa1XSsc06VR8PnqrGKom3t7xp66KkasxUw+AA0y4/iiADEP5p3/4BuEXi9gkPrfQgAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxOC0wMy0yOFQwMzo1NjoyMCswMjowMO7sj9MAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTgtMDMtMjhUMDM6NTY6MjArMDI6MDCfsTdvAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAABJRU5ErkJggg=="; let styles = [ `.${C_BTN_POST_OUTER_SPAN}{margin-left:10px;margin-right:-10px;}`, `.${C_BTN_POST}{outline:none;-webkit-box-align:center;align-items:center;background:00;border:0;cursor:pointer;display:flex;-webkit-box-flex:0;flex-grow:0;-webkit-box-pack:center;justify-content:center;min-height:40px;min-width:40px;padding:0;}`, `.${C_BTN_POST_INNER_SPAN}{display:block;background-repeat:no-repeat;background-position:100%-26px;height:24px;width:24px;background-image:url(/static/bundles/base/sprite_glyphs.png/4b550af4600d.png);cursor:pointer;}`, `.${C_BTN_STORY}{border:none;position:fixed;top:0;right:0;margin:20px;cursor:pointer;width:24px;height:24px;background-color:transparent;background-image:url(${b64icon})}` ]; styles.forEach((style) => GM_addStyle(style)); } function showDefaultErrorMessage(error) { alert(`${error}\n\nSorry for the inconvenience, the developer is on it!`); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址