diff --git a/igHelper.user.js b/igHelper.user.js new file mode 100644 index 0000000..fd65853 --- /dev/null +++ b/igHelper.user.js @@ -0,0 +1,432 @@ +// ==UserScript== +// @name [Unsupported] IG Helper: download Instagram pic & vids +// @name:zh-CN IG Helper备份版: 下载 Instagram 图片和视频 +// @description Unsupported +// @description:zh-cn 原作者不再维护 +// @version 1.9.10 +// @namespace InstagramHelper +// @require https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.3/FileSaver.min.js +// @match https://www.instagram.com/* +// @match https://*.cdninstagram.com/* +// @grant GM_addStyle +// @grant GM_xmlhttpRequest +// @grant GM_download +// @license MIT License +// ==/UserScript== + +(function() { + 'use strict'; + + /* + Common function + */ + Element.prototype.parents = function(selector) { + // Vanilla JS jQuery.parents() realisation + // https://gist.github.com/ziggi/2f15832b57398649ee9b + + var elements = []; + var elem = this; + var ishaveselector = selector !== undefined; + + while ((elem = elem.parentElement) !== null) { + if (elem.nodeType !== Node.ELEMENT_NODE) { + continue; + } + + if (!ishaveselector || elem.matches(selector)) { + elements.push(elem); + } + } + + return elements; + }; + + var GM_download_extra = function(url, name) { + // https://gist.github.com/ccloli/832a8350b822f3ff5094 + + if (url == null) return; + + var data = { + method: 'GET', + responseType: 'arraybuffer', + + onload: function(res) { + var blob = new Blob([res.response], { + type: 'application/octet-stream' + }); + var url = URL.createObjectURL(blob); // blob url + + var a = document.createElement('a'); + a.setAttribute('href', url); + a.setAttribute('download', data.name != null ? data.name : 'filename'); + document.documentElement.appendChild(a); + + // call download + // a.click() or CLICK the download link can't modify filename in Firefox (why?) + // Solution from FileSaver.js, https://github.com/eligrey/FileSaver.js/ + var e = new MouseEvent('click'); + a.dispatchEvent(e); + + document.documentElement.removeChild(a); + + setTimeout(function() { + // reduce memory usage + URL.revokeObjectURL(url); + if ('close' in blob) blob.close(); // File Blob.close() API, not supported by all the browser right now + blob = undefined; + }, 1000); + + if (typeof data.onafterload === 'function') data.onafterload(); // call onload function + } + + // error object of onerror function is not supported right now + }; + + if (typeof url === 'string') { + data.url = url; + data.name = name; + } else { + if (url instanceof Object === false) return; + + // as documentation, you can only use [url, name, headers, saveAs, onload, onerror] function, but we won't check them + // Notice: saveAs is not supported + if (url.url == null) return; + + for (var i in url) { + if (i === 'onload') data.onafterload = url.onload; // onload function support + else data[i] = url[i]; + } + } + + // it returns this GM_xhr, thought not mentioned in documentation + return GM_xmlhttpRequest(data); + }; + + var GM_download_extra_img = function(src, title) { + var img = new Image(); + img.crossOrigin = 'Anonymous'; + img.onload = function() { + var canvas = document.createElement('CANVAS'); + var ctx = canvas.getContext('2d'); + var dataURL; + canvas.height = this.height; + canvas.width = this.width; + ctx.drawImage(this, 0, 0); + + // Save image + canvas.toBlob(function(blob) { + saveAs(blob, title); + }, 'image/jpeg', 0.8); + + canvas = null; + }; + + img.src = src; + if (img.complete || img.complete === undefined) { + img.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=='; + img.src = src; + } + }; + + var GM_download_extra_video = function(src, title) { + window.open(src); + + // TODO + /* fetch(src).then(function(res) { + + res.blob().then(function(blob) { + var _link = document.createElement('a'); + _link.download = title; + _link.style.display = 'none'; + + var _blob = new Blob([blob]); + _link.href = URL.createObjectURL(_blob); + + document.body.appendChild(_link); + _link.click(); + document.body.removeChild(_link); + }); + + }); */ + }; + + var GM_addStyle_extra = function(css) { + var _head = document.getElementsByTagName('head')[0]; + if (_head) { + var _style = document.createElement('style'); + _style.setAttribute('type', 'text/css'); + _style.textContent = css; + _head.appendChild(_style); + return _style; + } + return null; + }; + + var ig_helper_style = '.downloadBtn {' + + 'position:absolute; width:46px; height:28px; opacity:0; right:25px; top:25px; z-index:1; text-align:center;' + + 'font-size:14px; line-height:26px; padding:0 8px; font-weight:600; color:#fff; white-space:nowrap; outline:0;' + + 'cursor:pointer; -webkit-user-select:none; -moz-user-select:none; user-select:none;' + + 'transition:opacity .2s ease-out; transition-delay:.1s; border-radius:3px; border:1px solid #db2d74;' + + 'background-color:#db2d74; background-size:22px; background-position:center; background-repeat:no-repeat;' + + 'background-image:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiB2aWV3Qm94PSIwIDAgMjU2IDI1NiIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWw6c3BhY2U9InByZXNlcnZlIiBzdHlsZT0iZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjEuNDE0MjE7Ij48dXNlIGlkPSJpY29uIC8gZG93bmxvYWQiIHhsaW5rOmhyZWY9IiNfSW1hZ2UxIiB4PSIxNC4wMDkiIHk9IjMzIiB3aWR0aD0iMjI3LjQ5MXB4IiBoZWlnaHQ9IjE5MC40OTdweCIvPjxkZWZzPjxpbWFnZSBpZD0iX0ltYWdlMSIgd2lkdGg9IjIyOHB4IiBoZWlnaHQ9IjE5MXB4IiB4bGluazpocmVmPSJkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQU9RQUFBQy9DQVlBQUFEdUhuQzVBQUFBQ1hCSVdYTUFBQTdFQUFBT3hBR1ZLdzRiQUFBSm8wbEVRVlI0bk8yZDJhN2pLaEFBbStqKy95LzdQaVRPT0Q3ZXNPa05xcVNSUnJPY3hOQkZOeGpqTWsyVFFEZzJPK1ZPWDVWU2R2K3Erb2VCT2dVaDNmbDJnRWRmTElSRjBBQWdwRDJ1QXA2eHlxaElhZ3hDMmpDSnhCVHdEREtvTFFpcFIxb0o5MEJPZlJDeVBWUHZiWXFZZWlCa0c3ckxobGRCenJZZzVETzZ6NFpYUWN3MklPUTloczJJWjN6RVJNcWJJR1E5Wk1VTElPWTlFUEk2aUhnRHhLd0RJYzlCeEljd3Y3d09RdTdEUExFeFpNdHpFSElic3FJaWlMblB5L3NMQkFRWmxmbTBMNDI4QVVMK1l4SmtOQU1wdDZGa2ZZT0lUckRnOHd0Q0ltTUltRmUrR2Ixa1JjWWdVTUsrR1ZsSVpBd0dVbzVic3FhUmNlTk1uSnF5THZUcEJIdU1YTDZPS0dSWUdZMk96MGdoNmFoU2ppWmtPQm1EckRLRzNKVTBvcFFqQ1JsR3hpQVM3aEZLenRHa0hFVklkeG1EUzdoRkdERkhrbklFSVYxbFRDamlGbEVHdE14dGVJbmVoWXdnWTA5QlJIc3EwN09RYnNFelFPRFF0a3IwS3FSTHdQUWVMQnZRem8zcGNhZU9lWkNVVXJvT2tnUEt3Y3Q4NEFZOUNtbktRc1JSSTdOOE1QdkFucmZZOVNha2FYWWNOQ3Z1Z1pRTjZHa09hU1lqSXA1aTJSZGQ5VU0zR1JJWlEySHBTVGNaUmFRZklVMDZCUm1yTUpHeXQ5SzFCeUZOeWlOa3ZBVlNWcEplU0dRTVQyL1RQRld5QzZsdUl6STJRVjNLWHJKa2FpRzFzeU15Tm9WTWVZSE1RcXJhaUl3cXFFclpRNWJNS3FUcVFnNHlxbUloWlZxeUNxa0dNcHFnWGI2bXRUS2prR3JaRVJuN0lIT1d6Q2lrSnNob0IxbHlnMnhDYW1kSHNFVk55cXhaTXBPUWxLcDlvdGJ1bjRDWmY2VWcrdE1lSmllZmNZUE1IY3Z0anlLQkI5OW9RcG9mUFVoMkRJUExTUS96YjAwLytJRC92TC9BQjg1bWdTTEdwZVVpNXFZb3NlQXRwUHQ1bnhDSFVvcmJZc3k4eThkYlRLK1MxVjFFNzRhSFhkeGpROFF2UHF3elpJakcvb0NNc0l0WHhyUVNNcEtJM0hPTWpmbGM4Z2hyTVMzdVE0YVNFZUlUY2NDMGVwSkVXOGh3TWpKM1RFSEkvckdRVXF0a0RTY2k1TUp6eGZVSTdSSldJME9HbFpIc21JclEvYVNWTFZzS09VbGdHU0VmRWVlU1N6U2tiQ1hrTkUxVHlCSmpSZXdlaG5TMGxyS0ZrQ215WXZUUkZqWkowV2t0cGN6MCtCVU1TSmFCdEpXVVQ0Vk1rUjAvNU9oWlNFc0xLWjhJbVViR0xLTXNiSktxODU1S2VWZklOREpDZnJJTnFFK2t2UE8wUjFnWkR6b3VWNC9DbXNPQUN4NlBWYkZYSzJRSUdWZmlJUnNzK2ZmVWNaeFl2UnlqTlVLNnloanh1QVZJZ2ZteE1HdHFwUFErTWVBVXRydkJROTRCOUk2akVCWGVFVmN6cE5jQlJJZ0lHb1NONXl0Q21uNTVTbE13SXVRSmg2ZENXdHBJVnF6aVQwQ3gySFVMNjRUelNFakxBMndKb0d0YzdoUGF0WW9Rc1g2ME1TREVGNFFmcXZxa2h4ZVlHbUp5Z1AxWm43aHVMa2ZHS200TmtFaFpoZnRiSlhhRk5IaWZoZ2d5WHVWUnRZS1VWYWhMZWRTWGUwS3FkaDR5MXRGaWNJeCsveTBZRnBseXMwTTJoZFRzUEdTc3BtVm5ZT1YxVktYY2MyeExTTFZPUTBaSWh2bGJudjhJeVV0UlkwR3A2WTdwVzU3WFF0TDdIWVBjSWZucGxCOGh5WTVEZ0pYMW1HVkpxL3VReUFqWk1ZbmhwWkFxSTZmM2pWYUFWaWpHOHRjOTFReEpxUXFkb1g1Lzhpc2tFMzRBSDVidXpVSTJ0NUhzQ0oyaWxTVW5FVTR1QndpRnBwQmtSK2dWdGRoK2liU2ZQN0t5Q3IzVE9zWm5CMS9DaldLQUtFeGFKU3NwRW5wSEpjWloxQUVJUkhNaG1UL0NLR2pFT2hrU0lCQXZkdWdBeEdDYUpqSWtRQ1EwaEdRU0NhUFFQTmJKa0FDQlFFaUFRQ0FrUUNBUUVpQVFDQWtRQ0lRRUNJU0drT3cwZ0ZGb0h1dGtTSUJBSUNSQUlCQVNJQkF2cmFNSUFIcEg0K2diclF5SmxkQTdLakZPeVFvUUNCVWhLVnVoZDdSaS9DVjZqMHRoSmZTS1ZteVhsd2puNEFCNE16dW9Ob2VrYklWZTBZeHQ3VVVkcklUZVVJM3BXVWlkMS9tOFJ4S2toRjZZRkxOakVWbGtTT2FSQUQ0czNWTy9EMG1XaEU3UXpJNWZsa0tTSWdGOCtMcjNreUcxeWxheUpDUkhMVHV1blRQYk9vZVVrQlNUVW5WbUxhUnEyWXFVa0F3TEdYK2MrNU1odFZkYjJUQUFXZENPMVMzWHRrcFdpOFVkcklUb1dNVG9IOWYrMi94WHBhaU9EblBwK2hraFdOMkZTSmpNR2ZjcTBiMUZuV0t4VVlBNUpRVERVc1pOd2R3ZlVFWktDSUxwYXVvZVIwS2FaRWtScEFSM3pHUThtNlp0emlFOVlGNEpEb1RJaWt2T1NsYXpMRG16eUpheFdncDZZaElIR2E4a216QVpjc25jVUtXVVNjaVcwSlp3V1hISkZTRkxLY1hsSWxabHJBaHl3ajNlZ2VRbzR0V3AyTlVNNlNhbHlFOURJaWRjeFYzQ21acDFrWnFTMVZYS21hV2NJcHMzV0JGMUxINEMwanMrMTlRdVV0Yk9JWXNFVzJ6WjZJRHZINnhrUmRUYy9CdUpnMGwzUWxYY1ZTL3FhRytyYThucWUzSkxKU2Z1VmRsZDd0eWh1TE5UeC94V1NDdW1hWnA3TjJjUGo4WDB3ZnQ3M09MdTRIOTM2MXhhS1VYWUdaU0F0Q0tLM0pkUjVObGUxaDZraEhnTUs2UEk4ODNscWFVVXNpUTBwTVVhUll1ZE9pRnVoOXhobXFZV3U0R09ManoxYUhXQTFqV25qQ09STmpLS3ROczZsMWJLQjF5NTN0NVdkcS9jYk8vdG1rOXBlYjB0bjRkTVdiN2VHRVNxTmlaM3RJQTBmVmFwci94RGtSc1BDR1FjMEZzUFBxMGZVRTRwWlFXWGczTDFuMFJ5UzFsZC9TemFLZk4xSDZKUkNXaWNHRkErS1B6b3ZDUU96dEdtSXFlVVV1Yk0wenpJTlkvdzZFM0t4NEdaVU1vUnIva1E3Zm14OXBrNjVUT2FLSCtNUHEyeVJHOEJlb1VlTXV3aWpsV0QyZUtRcXlLQnhmVDRUa21rOUhxaVBoUXJFZFcvb09XcGMxOHhFOUk4TW9OTHFTRmoxR3ZkeFZMRUdZOWpJRm4wK1JCVXl1RVhjVFFYYmM3d1BKZlZ2WXlOY0FNN21KVGVNcm9PMUZienhDTzhEMHFleTFqemp2QnUrQ1ZCcFBTV2NjWWxGaFlaMFRVbUlwMDZOM2VFK2xrb0VjdmxSdnRxSDN4OENCbS9hRDhJSC9Wc3BraEN6cnhUMTBKT2tYYUNSc3FNYTV5a3RKS3g1cHJtR0dqMjNiSWM1MUtpall3bjNEN1FxTUdJNkhMY2ZPc1BYUTFJN2krWHVVQjF4WlQ1NExPSUdmS0kzMkh1YjhOdjlWcWF6cGd4eXBUaHl0UWRsaFdUU0NkOXZFZTJET21OYVJCcnpLUG13STd5Y2huNHhYdVZOUnVtSzRCYTBqQUl4NFVNZVk4czVaNHJaTWQ2eUpEM1lLZlJDY2g0RDRTOEQxTHVnSXozUWNobklPVUtaSHdHUWo0SEtUOGc0M01Rc2czRFM0bU1iVURJZGd3ckpUSzJBeUhiTXB5VXlOZ1doR3pQTUZJaVkzc1FVb2Z1cFVSR0hSQlNqMjZsUkVZOUVGS1g3cVJFUmwwUVVwOXVwRVJHZlJEU2h2UlNJcU1OQ0dsSFdpbVIwUTZFdENXZGxNaG9DMExhazBaS1pMUUhJWDBJTHlVeStvQ1Fmb1NWRWhuOVFFaGZ3a21Kakw0Z3BEOWhwRVJHZnhBeUJ1NVNJbU1NRURJT2JsSWlZeHdRTWhaRHZ3VU1FRElpWmxJaVl6d1FNaWJxVWlKalRCQXlMbXBTSW1OY0VESTJ6YVZFeHRnZ1pIeWFTWW1NOFVISUhEeVdFaGx6Z0pCNXVDMGxNdVlCSVhOUkxTVXk1b0wzUStaa0V0bC84ZXBDV2tSTXh2OEJ3WXI4Qm1Mcm9RQUFBQUJKUlU1RXJrSmdnZz09Ii8+PC9kZWZzPjwvc3ZnPg==")' + + '}' + + '.downloadBtn.inStories {width:28px; top:10px; right:10px; border-radius:50%; font-size:12px; background-size:18px;}' + + '.KL4Bh:hover .downloadBtn,.OAXCp:hover .downloadBtn, .qbCDp:hover ~ .downloadBtn {opacity:1} ' + + '._9AhH0 {display:none !important}' + + '._2us5i:hover .downloadBtn {opacity:1}' + + '._lz6s {z-index:3 !important}'; + + if (typeof GM_addStyle !== 'undefined') { + GM_addStyle(ig_helper_style); + } else { + // Greasemonkey 4.0 remove the GM_addStyle function. + GM_addStyle_extra(ig_helper_style); + } + + + /* + Main + */ + var observer = new MutationObserver(init); + var config = { + 'childList': true, + 'subtree': true + }; + observer.observe(document.body, config); + + function init() { + + /* Home page */ + if (window.location.pathname === '/') { + var _box_home = document.querySelector('#react-root > section > main > section > div > div > div'); + + // Logged in + if (_box_home) { + findMedia(_box_home); + } + } + + /* Detail page */ + if (window.location.pathname.match('/p/')) { + var _box_detail = ''; + + /* + Absolute + + box class: QBXjJ + */ + if (document.querySelector('article.QBXjJ')) { + _box_detail = document.querySelector('article.QBXjJ'); + findMedia(_box_detail); + } + /* + Dialog + */ + else { + setTimeout(function() { + if (document.querySelector('div[role="dialog"]')) { + if (document.querySelector('div[role="dialog"]').querySelector('article')) { + _box_detail = document.querySelector('div[role="dialog"]').querySelector('article'); + findMedia(_box_detail); + } + } + }, 1000); // TODO: first click can't find dialog + } + } + + /* Stories page */ + if (window.location.pathname.match('/stories/')) { + setTimeout(function() { + var _box_story = document.querySelector('#react-root > section div.yS4wN'); + + if (_box_story) { + findMedia(_box_story, 'stories'); + } + }, 50); + } + + } + + function findMedia(box, way) { + var _box = box, _way = way; + var _parent, _url, _username, _title; + + _box.addEventListener('mouseover', function(event) { + event.stopPropagation(); + + /* + Picture + + img class: FFVAD + */ + if (event.target.className === 'FFVAD') { + _parent = event.target.parentNode; + _url = event.target.src; + _title = _url.match(/[a-zA-Z0-9_]+.jpg/g); + _username = ''; + + // title class: FPmhX + if (_parent.parents('article')[0].querySelector('.FPmhX')) { + // TODO: 此内容不应在缩略图页面出现,但不明原因出现了。暂时做判断,如果在缩略图页面时不下载图片。同时避免报错。 + _username = _parent.parents('article')[0].querySelector('.FPmhX').title; + addBtn(_parent, _url, _username, _title); + } + } + + /* + Video + + video class: tWeCl + video play button class: QvAa1 + */ + if (event.target.className.indexOf('QvAa1') >= 0) { + _parent = event.target.parentNode; + _url = _parent.querySelector('.tWeCl').src; + _title = _url.match(/[a-zA-Z0-9_]+.mp4/g); + _username = _parent.parents('article')[0].querySelector('.FPmhX').title; + + addBtn(_parent, _url, _username, _title); + } + + /* + Stories Picture & Video + + _8XqED: #react-root > div > div > section._8XqED + z6Odz parent: cover box (when autoplay videos disable, user click the cover box to play the video) + + Debug: click more button stop auto video + */ + if (event.target.className.indexOf('_8XqED') >= 0 && _way === 'stories') { + var _current_target = document.querySelector('.z6Odz').parentNode; + _parent = _current_target.parentNode.parentNode; + + // Stories Video: video 'if' in front of the image + if (_parent.querySelector('video')) { + _url = _parent.querySelector('video > source').src; + _title = _url.match(/[a-zA-Z0-9_]+.mp4/g); + _username = _parent.parents('section')[0].querySelector('.FPmhX').title; + + addBtn(_parent, _url, _username, _title); + + return false; + } + + // Stories Picture + if (_parent.querySelector('img')) { + _url = _parent.querySelector('img').src; + _title = _url.match(/[a-zA-Z0-9_]+.jpg/g); + _username = _parent.parents('section')[0].querySelector('.FPmhX').title; + + addBtn(_parent, _url, _username, _title); + + return false; + } + + } + + }); + } + + function addBtn(parent, url, username, title) { + + if (!parent.querySelector('.downloadBtn')) { + var _parent = parent; + var _url = url; + var _url_param = _url.indexOf('?') >= 0 ? _url.substring(0, _url.indexOf('?')) : _url; + _url_param = _url_param.replace(/\?ig_cache_key=[a-zA-Z0-9%.]+/, ''); + var _title = title[0]; + var _filename = username + '_' + _url_param.substring(_url_param.lastIndexOf('/') + 1, _url_param.length); + var _btn = document.createElement('button'); + var _ua = navigator.userAgent.toLowerCase(); + + var removeBtn = function() { + if (_parent.querySelector('.downloadBtn')) { + _parent.removeChild(_parent.querySelector('.downloadBtn')); + } + }; + + if (window.location.pathname.match('/stories/')) { + _btn.className = 'downloadBtn inStories'; + } else { + _btn.className = 'downloadBtn'; + } + + // Download + _btn.addEventListener('click', function(event) { + event.stopPropagation(); + + // Support DM_download + if (typeof GM_download !== 'undefined') { + + // Safari GM_download unavailable + if (_ua.match(/version\/([\d.]+)/)) { + if (_title.indexOf('.mp4') >= 0) { + GM_download_extra_video(_url, _filename); + } else { + GM_download_extra_img(_url, _filename); + } + } + + // Other browser + else { + // Chrome + if (_ua.match(/chrome\/\d./g)) { + GM_download(_url, _filename); + } + + // Firefox + else if (_ua.match(/firefox\/\d./g)) { + GM_download_extra(_url, _filename); + } + } + + } + + // Firefox Greasemonkey not support DM_download + else { + if (_title.indexOf('.mp4') >= 0) { + GM_download_extra_video(_url, _filename); + } else { + GM_download_extra_img(_url, _filename); + } + } + + }, false); + + _parent.appendChild(_btn); + + // Show stories btn + if (document.querySelector('.z6Odz')) { + document.querySelector('.z6Odz').addEventListener('mouseover', function(event) { + event.stopPropagation(); + + document.querySelector('.downloadBtn').style.opacity = '1'; + }, false); + + document.querySelector('.GHEPc').addEventListener('mouseleave', function(event) { + event.stopPropagation(); + + document.querySelector('.downloadBtn').style.opacity = '0'; + }, false); + } + + // More media on one box, ignore stories page + if (!window.location.pathname.match('/stories/')) { + var _left_btn = '._2Igxi'; + var _right_btn = '.Zk-Zb'; + + if (_parent.querySelector(_right_btn) || _parent.parents('article')[0].querySelector(_right_btn)) { + var _btn_right = _parent.querySelector(_right_btn) ? _parent.querySelector(_right_btn) : _parent.parents('article')[0].querySelector(_right_btn); + _btn_right.addEventListener('click', removeBtn, false); + } + + if (_parent.querySelector(_left_btn) || _parent.parents('article')[0].querySelector(_left_btn)) { + var _btn_left = _parent.querySelector(_left_btn) ? _parent.querySelector(_left_btn) : _parent.parents('article')[0].querySelector(_left_btn); + _btn_left.addEventListener('click', removeBtn, false); + } + } + } + + } + +})();