// ==UserScript== // @name Instagram Image Source and Search // @namespace instagram_search // @version 0.3.6 // @description Adds buttons for simple image saving and searching in Instagram // @homepageURL https://github.com/0xC0FFEEC0DE/instagram-source-image // @supportURL https://github.com/0xC0FFEEC0DE/instagram-source-image/issues // @downloadURL https://raw.githubusercontent.com/0xC0FFEEC0DE/instagram-source-image/master/instagram-source-image.user.js // @updateURL https://raw.githubusercontent.com/0xC0FFEEC0DE/instagram-source-image/master/instagram-source-image.user.js // @author 0xC0FFEEC0DE // @include https://*.instagram.com/* // @license MIT // ==/UserScript== //Search icon made by Smashicons from www.flaticon.com, Google icon made by SimpleIcon from www.flaticon.com, Camera icon by Gregor Cresnar from www.flaticon.com (function() { 'use strict'; const SEARCH_ICON = 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMTkuMC4wLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDU2Ljk2NiA1Ni45NjYiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDU2Ljk2NiA1Ni45NjY7IiB4bWw6c3BhY2U9InByZXNlcnZlIiB3aWR0aD0iMjRweCIgaGVpZ2h0PSIyNHB4Ij4KPHBhdGggZD0iTTU1LjE0Niw1MS44ODdMNDEuNTg4LDM3Ljc4NmMzLjQ4Ni00LjE0NCw1LjM5Ni05LjM1OCw1LjM5Ni0xNC43ODZjMC0xMi42ODItMTAuMzE4LTIzLTIzLTIzcy0yMywxMC4zMTgtMjMsMjMgIHMxMC4zMTgsMjMsMjMsMjNjNC43NjEsMCw5LjI5OC0xLjQzNiwxMy4xNzctNC4xNjJsMTMuNjYxLDE0LjIwOGMwLjU3MSwwLjU5MywxLjMzOSwwLjkyLDIuMTYyLDAuOTIgIGMwLjc3OSwwLDEuNTE4LTAuMjk3LDIuMDc5LTAuODM3QzU2LjI1NSw1NC45ODIsNTYuMjkzLDUzLjA4LDU1LjE0Niw1MS44ODd6IE0yMy45ODQsNmM5LjM3NCwwLDE3LDcuNjI2LDE3LDE3cy03LjYyNiwxNy0xNywxNyAgcy0xNy03LjYyNi0xNy0xN1MxNC42MSw2LDIzLjk4NCw2eiIgZmlsbD0iIzAwMDAwMCIvPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8L3N2Zz4K'; const GOOGLE_ICON = 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMTYuMC4wLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjI0cHgiIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDkwIDkwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA5MCA5MDsiIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8Zz4KCTxwYXRoIGlkPSJHb29nbGUiIGQ9Ik03NC40OTksMEg1MC4xNDRjLTYuMzgyLDAtMTQuNDIxLDAuOTQyLTIxLjE1OCw2LjQ5Yy01LjA5LDQuMzc0LTcuNTY2LDEwLjM5Mi03LjU2NiwxNS44MjggICBjMCw5LjIxMSw3LjA5NCwxOC41NDYsMTkuNjI1LDE4LjU0NmMxLjE4MiwwLDIuNDc3LTAuMTIsMy43ODctMC4yMzVjLTAuNTkyLDEuNDEzLTEuMTg5LDIuNTk0LTEuMTg5LDQuNjA1ICAgYzAsMy42NjIsMS44OTMsNS45MDIsMy41NDcsOC4wMjljLTUuMzE0LDAuMzUzLTE1LjI0OSwwLjk0Mi0yMi41ODMsNS40MjhjLTYuOTc1LDQuMTQzLTkuMTA3LDEwLjE2LTkuMTA3LDE0LjQxNCAgIEMxNS40OTksODEuODQ2LDIzLjc3OCw5MCw0MC45MjMsOTBjMjAuMzM2LDAsMzEuMDk4LTExLjIyLDMxLjA5OC0yMi4zM2MwLTguMTQzLTQuNzI5LTEyLjE2NC05LjkzMi0xNi41MzRsLTQuMjU4LTMuMzA1ICAgYy0xLjI5NS0xLjA2NS0zLjA2OC0yLjQ3OS0zLjA2OC01LjA4YzAtMi41OTcsMS43NzMtNC4yNTQsMy4zMDctNS43ODljNC45NjQtMy44OTYsOS45MzMtOC4wMyw5LjkzMy0xNi43NyAgIGMwLTguOTc5LTUuNjgtMTMuNzA0LTguMzk2LTE1Ljk0N2g3LjMzNEw3NC40OTksMHogTTY0LjEwMyw3Mi4yNzljMCw3LjMyMi02LjAzMywxMi43NTMtMTcuMzg1LDEyLjc1MyAgIGMtMTIuNjQ4LDAtMjAuODA5LTYuMDI0LTIwLjgwOS0xNC40MDVjMC04LjM5Myw3LjU2OC0xMS4yMTgsMTAuMTY2LTEyLjE2NGM0Ljk2OS0xLjY1NiwxMS4zNTItMS44OTEsMTIuNDE0LTEuODkxICAgYzEuMTg0LDAsMS43NzUsMCwyLjcyNSwwLjExNUM2MC4yMDIsNjMuMDY0LDY0LjEwMyw2Ni4yNTcsNjQuMTAzLDcyLjI3OXogTTU0LjY0MiwzNC4yNDljLTEuODkzLDEuODg2LTUuMDg4LDMuMzA1LTguMDQ1LDMuMzA1ICAgYy0xMC4xNjQsMC0xNC43NzItMTMuMTEzLTE0Ljc3Mi0yMS4wMjNjMC0zLjA3MiwwLjU5Mi02LjI1OCwyLjU5OC04Ljc0YzEuODkzLTIuMzYyLDUuMjAxLTMuODk5LDguMjc3LTMuODk5ICAgYzkuODEyLDAsMTQuODk5LDEzLjIyOSwxNC44OTksMjEuNzNDNTcuNTk5LDI3Ljc1Miw1Ny4zNTgsMzEuNTI4LDU0LjY0MiwzNC4yNDl6IiBmaWxsPSIjMDAwMDAwIi8+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPC9zdmc+Cg=='; const SCREENSHOT_ICON = 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMTkuMC4wLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ5MCA0OTAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDQ5MCA0OTA7IiB4bWw6c3BhY2U9InByZXNlcnZlIiB3aWR0aD0iMjRweCIgaGVpZ2h0PSIyNHB4Ij4KPGc+Cgk8Zz4KCQk8cGF0aCBkPSJNMCwxNjcuODV2MjE2LjJjMCwzMywyNi44LDU5LjgsNTkuOCw1OS44aDM3MC40YzMzLDAsNTkuOC0yNi44LDU5LjgtNTkuOHYtMjE2LjJjMC0zMS40LTI1LjUtNTYuOS01Ni45LTU2LjloLTc5LjYgICAgbC0xLjktOC4zYy03LjctMzMuMy0zNy01Ni41LTcxLjItNTYuNWgtNzAuOWMtMzQuMSwwLTYzLjQsMjMuMi03MS4yLDU2LjVsLTEuOSw4LjNINTYuOUMyNS41LDExMC45NSwwLDEzNi41NSwwLDE2Ny44NXogICAgIE0xNDYuMiwxMzUuNDVjNS43LDAsMTAuNi0zLjksMTEuOS05LjVsNC4xLTE3LjhjNS4yLTIyLjEsMjQuNi0zNy41LDQ3LjMtMzcuNWg3MC45YzIyLjcsMCw0Mi4xLDE1LjQsNDcuMywzNy41bDQuMSwxNy44ICAgIGMxLjMsNS41LDYuMiw5LjUsMTEuOSw5LjVINDMzYzE3LjksMCwzMi40LDE0LjUsMzIuNCwzMi40djIxNi4yYzAsMTkuNS0xNS44LDM1LjMtMzUuMywzNS4zSDU5LjhjLTE5LjUsMC0zNS4zLTE1LjgtMzUuMy0zNS4zICAgIHYtMjE2LjJjMC0xNy45LDE0LjUtMzIuNCwzMi40LTMyLjRIMTQ2LjJ6IiBmaWxsPSIjMDAwMDAwIi8+CgkJPGNpcmNsZSBjeD0iODIuOSIgY3k9IjE4Ny43NSIgcj0iMTYuNCIgZmlsbD0iIzAwMDAwMCIvPgoJCTxwYXRoIGQ9Ik0yNDUsMzgwLjk1YzU2LjcsMCwxMDIuOS00Ni4yLDEwMi45LTEwMi45cy00Ni4yLTEwMi45LTEwMi45LTEwMi45cy0xMDIuOSw0Ni4xLTEwMi45LDEwMi45UzE4OC4zLDM4MC45NSwyNDUsMzgwLjk1eiAgICAgTTI0NSwxOTkuNjVjNDMuMiwwLDc4LjQsMzUuMiw3OC40LDc4LjRzLTM1LjIsNzguNC03OC40LDc4LjRzLTc4LjQtMzUuMi03OC40LTc4LjRTMjAxLjgsMTk5LjY1LDI0NSwxOTkuNjV6IiBmaWxsPSIjMDAwMDAwIi8+Cgk8L2c+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPC9zdmc+Cg=='; const sourceBtnClass = 'source_button'; const googleBtnClass = 'google_source_button'; const screenBtnClass = 'screenshot_button'; const footerPanelID = 'footerPanel'; const galleryClass = 'XCodT'; let firstArticles = document.querySelectorAll('article'); firstArticles.forEach(article => { let gallery = article.querySelector(`.${galleryClass}`); if (gallery) { processGallery(article); return; } let img = article.querySelector('img[srcset]'); if (img) { let src = extractUrlFromSet(img.srcset); addButtons(article, src, src); return; } let video = article.querySelector('video'); if (video) { let article = video.closest('article'); if (article) { addButtons(article, video.src, video.poster); } } }); let imageObserver = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { // console.log(mutation); let img = mutation.target; let article = img.closest('article'); if (img.closest('ul.YlNGR')) { // img is in gallery processGallery(article); return; } if (article) { let src = extractUrlFromSet(img.srcset); addButtons(article, src, src); } }); }).observe(document.body, { attributes: true, subtree: true, attributeFilter: ['srcset'], }); function processGallery(article) { let div = article.querySelector(`.${galleryClass}`); let galleryCursor = [...div.parentElement.children].indexOf(div); let li = article.querySelectorAll('ul.YlNGR li')[galleryCursor]; let img = li.querySelector('img[srcset]'); if (img) { let src = extractUrlFromSet(img.srcset); addButtons(article, src, src); } } let galleryObserver = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { let div = mutation.target; if (div.classList.contains(galleryClass)) { let article = div.closest('article'); processGallery(article); } }); }).observe(document.body, { attributes: true, subtree: true, attributeFilter: ['class'], }); let videoObserver = new MutationObserver(function(mutations) { mutations = Array.from(mutations); function videoClassCount(removedNodes) { return Array.from(removedNodes) .filter(node => node.classList && node.classList.contains('_8jZFn')).length; } let videoMutations = mutations .filter(m => m.removedNodes && videoClassCount(m.removedNodes) > 0); if(videoMutations.length === 0) return; videoMutations.forEach(m => { var video = m.previousSibling; if (video && video.tagName && video.tagName.toLowerCase() === 'video') { if (video.classList.contains('processed')) return; let playPromise = video.play(); playPromise.then(() => { video.crossOrigin = 'anonymous'; video.load(); video.play(); }); video.classList.add('processed'); let article = video.closest('article'); if (article) { addButtons(article, video.src, video.poster, /*screenBtn:*/ true); } } }); }).observe(document.body, { childList: true, subtree: true, attributes: false, characterData: false, }); function addButtons(article, src, googleLink, isScreenBtnNeed) { let menuBar = article.querySelector('.ltpMr.Slqrh'); // xD if (!menuBar) { //return console.log("no menu in this article"); return; } addSourceButton(menuBar, src); addGoogleButton(menuBar, googleLink); addScreenButton(article, menuBar, isScreenBtnNeed); } function addScreenButton(article, menuBar, isScreenBtnNeed) { let existBtn = menuBar.querySelector(`.${screenBtnClass}`); if (existBtn) { existBtn.parentNode.removeChild(existBtn); } if (!isScreenBtnNeed) { return; } let screenBtn = document.createElement('button'); screenBtn.title = 'Make screenshot'; screenBtn.className += screenBtnClass; screenBtn.style.width = '24px'; screenBtn.style.height = '24px'; screenBtn.style.margin = '8px 0 8px 8px'; screenBtn.style.backgroundImage = `url(data:image/svg+xml;utf8;base64,${SCREENSHOT_ICON})`; screenBtn.style['background-color'] = 'white'; screenBtn.style.border = 'none'; screenBtn.style.cursor = 'pointer'; screenBtn.onclick = () => { let video = article.querySelector('video'); let img; if (video.played.length === 0) { img = document.createElement('img'); img.src = video.poster; } else { img = makeScreenshot(video); } let panel = document.getElementById(footerPanelID); if (!panel) { panel = createFooterPanel(); } img.style.width = '230px'; img.style.margin = '5px'; panel.appendChild(img); }; menuBar.appendChild(screenBtn); } function addSourceButton(menuBar, url) { let existBtn = menuBar.querySelector(`.${sourceBtnClass}`); if (existBtn) { existBtn.parentNode.removeChild(existBtn); } let sourceBtn = document.createElement('a'); sourceBtn.target = '_blank'; sourceBtn.title = 'Source'; sourceBtn.className += sourceBtnClass; sourceBtn.style.width = '24px'; sourceBtn.style.height = '24px'; sourceBtn.style.margin = '8px 0 8px 10px'; sourceBtn.style.backgroundImage = `url(data:image/svg+xml;utf8;base64,${SEARCH_ICON})`; sourceBtn.href = url; menuBar.appendChild(sourceBtn); } function addGoogleButton(menuBar, url) { let existBtn = menuBar.querySelector(`.${googleBtnClass}`); if (existBtn) { existBtn.parentNode.removeChild(existBtn); } let googleBtn = document.createElement('a'); googleBtn.target = '_blank'; googleBtn.title = 'Google it'; googleBtn.className += googleBtnClass; googleBtn.style.width = '24px'; googleBtn.style.height = '24px'; googleBtn.style.margin = '8px 0 8px 8px'; googleBtn.href = `https://www.google.com/searchbyimage?image_url=${encodeURIComponent(url)}`; googleBtn.style.backgroundImage = `url(data:image/svg+xml;utf8;base64,${GOOGLE_ICON})`; menuBar.appendChild(googleBtn); } function extractUrlFromSet(srcset) { let urls = srcset.split(','); return urls[urls.length - 1].split(' ')[0]; } function createFooterPanel() { let panel = document.createElement('div'); panel.id = footerPanelID; panel.style.position = 'fixed'; panel.style.right = '4px'; panel.style.bottom = 0; panel.style['background-color'] = '#21212121'; panel.style['z-index'] = 42; let closeBtn = document.createElement('div'); closeBtn.textContent = 'close'; closeBtn.style.position = 'fixed'; closeBtn.style.right = '250px'; closeBtn.style.bottom = '4px'; closeBtn.style.cursor = 'pointer'; closeBtn.style['z-index'] = 42; closeBtn.onclick = () => { panel.parentNode.removeChild(panel); closeBtn.parentNode.removeChild(closeBtn); }; let body = document.querySelector('body'); body.appendChild(panel); body.appendChild(closeBtn); return panel; } function makeScreenshot(video) { let canvas = document.createElement('canvas'); canvas.width = video.videoWidth; canvas.height = video.videoHeight; let ctx = canvas.getContext('2d'); ctx.drawImage(video, 0, 0, canvas.width, canvas.height); var img = new Image(); img.src = canvas.toDataURL('image/jpeg'); return img; } })();