// 解析参数 const params = new URL(location.href).searchParams; const _tabId = parseInt(params.get("tabId")); const _type = params.get("type"); // 当前页面 const $mediaList = $('#mediaList'); const $current = $("
"); const $currentCount = $("#currentTab #quantity"); let currentCount = 0; // 其他页面 const $allMediaList = $('#allMediaList'); const $all = $("
"); const $allCount = $("#allTab #quantity"); let allCount = 0; // 疑似密钥 const $maybeKey = $("
"); // 提示 操作按钮 DOM const $tips = $("#Tips"); const $down = $("#down"); const $mergeDown = $("#mergeDown"); // 储存所有资源数据 const allData = new Map([ [true, new Map()], // 当前页面 [false, new Map()] // 其他页面 ]); // 筛选 const $filter_ext = $("#filter #ext"); // 储存所有扩展名,保存是否筛选状态 来判断新加入的资源 立刻判断是否需要隐藏 const filterExt = new Map(); // 删除重复文件名 let duplicateFilenamesSet = null; // 当前所在页面 let activeTab = true; // 储存下载id const downData = []; // 图标地址 const favicon = new Map(); // 当前页面DOM let pageDOM = undefined; // HeartBeat chrome.runtime.sendMessage(chrome.runtime.id, { Message: "HeartBeat" }); // 清理冗余数据 chrome.runtime.sendMessage(chrome.runtime.id, { Message: "clearRedundant" }); // 监听下载 出现服务器拒绝错误 调用下载器 chrome.downloads.onChanged.addListener(function (item) { if (G.catDownload) { delete downData[item.id]; return; } const errorList = ["SERVER_BAD_CONTENT", "SERVER_UNAUTHORIZED", "SERVER_FORBIDDEN", "SERVER_UNREACHABLE", "SERVER_CROSS_ORIGIN_REDIRECT", "SERVER_FAILED", "NETWORK_FAILED"]; if (item.error && errorList.includes(item.error.current) && downData[item.id]) { catDownload(downData[item.id]); delete downData[item.id]; } }); // 复选框状态 点击返回或者全选后 影响新加入的资源 复选框勾选状态 let checkboxState = true; // 生成资源DOM function AddMedia(data, currentTab = true) { data._title = data.title; data.title = stringModify(data.title); //文件名 data.name = isEmpty(data.name) ? data.title + '.' + data.ext : decodeURIComponent(stringModify(data.name)); //截取文件名长度 let trimName = data.name; if (data.name && data.name.length >= 50 && !_tabId) { trimName = trimName.substr(0, 20) + '...' + trimName.substr(-30); } //添加下载文件名 Object.defineProperty(data, "pageDOM", { get() { return pageDOM; } }); data.downFileName = G.TitleName ? templates(G.downFileName, data) : data.name; data.downFileName = filterFileName(data.downFileName); if (isEmpty(data.downFileName)) { data.downFileName = data.name; } // 文件大小单位转换 data._size = data.size; if (data.size) { data.size = byteToSize(data.size); } // 是否需要解析 data.parsing = false; if (isM3U8(data)) { data.parsing = "m3u8"; } else if (isMPD(data)) { data.parsing = "mpd"; } else if (isJSON(data)) { data.parsing = "json"; } // 网站图标 if (data.favIconUrl && !favicon.has(data.webUrl)) { favicon.set(data.webUrl, data.favIconUrl); } data.isPlay = isPlay(data); if (allData.get(currentTab).has(data.requestId)) { data.requestId = data.requestId + "_" + Date.now().toString(); } //添加html data.html = $(`
${G.ShowWebIco ? `` : ""} ${trimName} ${data.size}
${data.title ? `${i18n.title}: ${data.title}` : ""} ${data.type ? `
MIME: ${data.type}` : ""}
${data.url}
`); ////////////////////////绑定事件//////////////////////// //展开网址 data.urlPanel = data.html.find(".url"); data.urlPanelShow = false; data.panelHeading = data.html.find(".panel-heading"); data.panelHeading.click(function (event) { data.urlPanelShow = !data.urlPanelShow; const mediaInfo = data.html.find("#mediaInfo"); const preview = data.html.find("#preview"); if (!data.urlPanelShow) { if (event.target.id == "play") { preview.show().trigger("play"); return false; } data.urlPanel.hide(); !preview[0].paused && preview.trigger("pause"); return false; } data.urlPanel.show(); if (!mediaInfo.data("state")) { mediaInfo.data("state", true); if (isM3U8(data)) { const hls = new Hls({ enableWorker: false }); setRequestHeaders(data.requestHeaders, function () { hls.loadSource(data.url); hls.attachMedia(preview[0]); }); hls.on(Hls.Events.BUFFER_CREATED, function (event, data) { if (data.tracks && !data.tracks.audiovideo) { !data.tracks.audio && mediaInfo.append(`
${i18n.noAudio}`); !data.tracks.video && mediaInfo.append(`
${i18n.noVideo}`); } }); hls.on(Hls.Events.ERROR, function (event, data) { hls.stopLoad(); }); hls.on(Hls.Events.MANIFEST_PARSED, function (event, data) { if (data.levels.length > 1 && !mediaInfo.text().includes(i18n.m3u8Playlist)) { mediaInfo.append(`
${i18n.m3u8Playlist}`); } }); } else if (data.isPlay) { setRequestHeaders(data.requestHeaders, function () { preview.attr("src", data.url); }); } else if (isPicture(data)) { setRequestHeaders(data.requestHeaders, function () { data.html.find("#screenshots").show().attr("src", data.url); }); return false; } else { return false; } preview.on("loadedmetadata", function () { preview.show(); if (this.duration && this.duration != Infinity) { data.duration = this.duration; mediaInfo.append(`
${i18n.duration}: ` + secToTime(this.duration)); } if (this.videoHeight && this.videoWidth) { mediaInfo.append(`
${i18n.resolution}: ` + this.videoWidth + "x" + this.videoHeight); data.videoWidth = this.videoWidth; data.videoHeight = this.videoHeight; } }); } if (event.target.id == "play") { preview.show().trigger("play"); } return false; }); // 二维码 data.html.find("#qrcode").click(function () { const size = data.url.length >= 300 ? 400 : 256; $(this).html("").qrcode({ width: size, height: size, text: data.url }).off("click"); }); // 猫抓下载器 下载 data.html.find("#catDown").click(function () { catDownload(data); }); data.html.find("#catDownFFmpeg").click(function () { catDownload(data, { ffmpeg: "addFile" }); }); //点击复制网址 data.html.find('#copy').click(function () { const text = copyLink(data); navigator.clipboard.writeText(text); Tips(i18n.copiedToClipboard); return false; }); // 发送到Aria2 data.html.find('#aria2').click(function () { aria2AddUri(data, function (data) { Tips(i18n.hasSent + JSON.stringify(data), 2000); }, function (errMsg) { Tips(i18n.sendFailed, 2000); console.error(errMsg); }); return false; }); // 下载 data.html.find('#download').click(function (event) { if (G.m3u8dl && (isM3U8(data) || isMPD(data))) { if (!data.url.startsWith("blob:")) { const m3u8dlArg = data.m3u8dlArg ?? templates(G.m3u8dlArg, data); const url = 'm3u8dl:' + (G.m3u8dl == 1 ? Base64.encode(m3u8dlArg) : m3u8dlArg); if (url.length >= 2046) { navigator.clipboard.writeText(m3u8dlArg); Tips(i18n.M3U8DLparameterLong, 2000); return false; } // 下载前确认参数 if (G.m3u8dlConfirm && event.originalEvent && event.originalEvent.isTrusted) { data.html.find('.confirm').remove(); const confirm = $(`
`); confirm.find("#confirm").click(function () { data.m3u8dlArg = confirm.find("textarea").val(); data.html.find('#download').click(); confirm.hide(); }); confirm.find("#close").click(function () { confirm.remove(); }); data.html.append(confirm); return false; } if (G.isFirefox) { window.location.href = url; return false; } chrome.tabs.update({ url: url }); return false; } Tips(i18n.blobM3u8DLError, 1500); } if (G.m3u8AutoDown && data.parsing == "m3u8") { openParser(data, { autoDown: true }); return false; } chrome.downloads.download({ url: data.url, filename: data.downFileName, saveAs: G.saveAs }, function (id) { downData[id] = data; }); return false; }); // 调用 data.html.find('.invoke').click(function (event) { const url = data.invoke ?? templates(G.invokeText, data); // 下载前确认参数 if (G.invokeConfirm && event.originalEvent && event.originalEvent.isTrusted) { data.html.find('.confirm').remove(); const confirm = $(`
`); confirm.find("#confirm").click(function () { data.invoke = confirm.find("textarea").val(); data.html.find('.invoke').click(); confirm.hide(); }); confirm.find("#close").click(function () { confirm.remove(); }); data.html.append(confirm); return false; } if (G.isFirefox) { window.location.href = url; } else { chrome.tabs.update({ url: url }); } return false; }); //播放 data.html.find('#play').click(function () { if (isEmpty(G.Player)) { return true; } if (G.Player == "$shareApi$" || G.Player == "${shareApi}") { navigator.share({ url: data.url }); return false; } let url = templates(G.Player, data); if (G.isFirefox) { window.location.href = url; return false; } chrome.tabs.update({ url: url }); return false; }); //解析 data.html.find('#parsing').click(function (e) { openParser(data); return false; }); // 多选框 创建checked属性 值和checked状态绑定 data._checked = checkboxState; data.html.find(".DownCheck").prop("checked", data._checked); data.html.find('input').click(function (event) { data._checked = this.checked; mergeDownButton(); event.originalEvent.cancelBubble = true; }); Object.defineProperty(data, "checked", { get() { return data._checked; }, set(newValue) { data._checked = newValue; data.html.find('input').prop("checked", newValue); } }); // 数据发送 data.html.find("#send2local").click(function () { send2local("catch", data, data.tabId).then(function (success) { success && success?.ok && Tips(i18n.hasSent, 1000); }).catch(function (error) { error ? Tips(error, 1000) : Tips(i18n.sendFailed, 1000); }); return false; }); // MQTT 发送 data.html.find("#mqtt").click(function () { const $mqttButton = $(this); // 防止重复点击 if ($mqttButton.hasClass('mqtt-sending')) { return false; } // 禁用按钮并添加发送中状态 $mqttButton.addClass('mqtt-sending').prop('disabled', true); // 1. 点击后,提示 正在发送到MQTT服务器 Tips(i18n.sendingToMQTT || "Sending to MQTT server...", 2000); sendToMQTT(data).then(function (success) { // 5. 已发送消息到 MQTT 服务器 Tips(i18n.messageSentToMQTT || "Message sent to MQTT server", 2000); }).catch(function (error) { // 失败时显示详细错误信息 const errorMsg = error ? error.toString() : (i18n.sendFailed || "Send failed"); Tips(errorMsg, 10000); console.error("MQTT send error:", error); }).finally(function () { // 恢复按钮状态 $mqttButton.removeClass('mqtt-sending').prop('disabled', false); }); return false; }); // 使用Map 储存数据 allData.get(currentTab).set(data.requestId, data); // 筛选 if (!filterExt.has(data.ext)) { filterExt.set(data.ext, true); const html = $(``); html.click(function () { filterExt.set(this.id, html.find("input").prop("checked")); getAllData().forEach(function (value) { if (filterExt.get(value.ext)) { value.checked = true; value.html.show(); } else { value.checked = false; value.html.hide(); } }); }); $filter_ext.append(html); } // 如果被筛选出去 直接隐藏 if (!filterExt.get(data.ext) || duplicateFilenamesSet?.has(data.name)) { data.html.hide(); data.html.find("input").prop("checked", false); } duplicateFilenamesSet && duplicateFilenamesSet.add(data.name); return data.html; } function AddKey(key) { // 检查key是否合法 const base64Key = base64ToHex(key); if (!base64Key) { return; } const data = {}; data.html = $(`
${key}
Hex: ${base64Key}
Base64: ${key}
`); data.html.find('.panel-heading').click(function () { data.html.find(".url").toggle(); }); data.html.find('.copy').click(function () { navigator.clipboard.writeText(key); Tips(i18n.copiedToClipboard); return false; }); data.html.find("#send2local").click(function () { send2local("addKey", key).then(function (success) { success && success?.ok && Tips(i18n.hasSent, 1000); }).catch(function (error) { error ? Tips(error, 1000) : Tips(i18n.sendFailed, 1000); }); return false; }); return data.html; } /********************绑定事件********************/ //标签切换 $(".Tabs .TabButton").click(function () { activeTab = this.id == "currentTab"; const index = $(this).index(); $(".Tabs .TabButton").removeClass('Active'); $(this).addClass("Active"); $(".container").removeClass("TabShow").eq(index).addClass("TabShow"); UItoggle(); $("#filter, #unfold").hide(); $("#features").hide(); }); // 其他页面 $('#allTab').click(function () { !allCount && chrome.runtime.sendMessage(chrome.runtime.id, { Message: "getAllData" }, function (data) { if (!data) { return; } for (let key in data) { if (key == G.tabId) { continue; } allCount += data[key].length; for (let i = 0; i < data[key].length; i++) { $all.append(AddMedia(data[key][i], false)); } } allCount && $allMediaList.append($all); UItoggle(); }); }); // 下载选中文件 $('#DownFile').click(function () { const [checkedData, maxSize] = getCheckedData(); if (checkedData.length >= 10 && !confirm(i18n("confirmDownload", [checkedData.length]))) { return; } if (G.enableAria2Rpc) { Tips(i18n.hasSent, 2000); checkedData.forEach(function (data) { aria2AddUri(data); }); return; } let index = 0; for (let data of checkedData) { if (G.m3u8dl && (data.parsing == "m3u8" || data.parsing == "mpd") && !data.url.startsWith("blob:")) { const m3u8dlArg = templates(G.m3u8dlArg, data); const url = 'm3u8dl:' + (G.m3u8dl == 1 ? Base64.encode(m3u8dlArg) : m3u8dlArg); chrome.tabs.create({ url: url }); continue; } if (G.m3u8AutoDown && data.parsing == "m3u8") { openParser(data, { autoDown: true, autoClose: true }); continue; } // 以防止popup页面被关闭 丢失下载数据 批量下载前临时修改为 后台下载 G.downActive = true; index++; setTimeout(function () { chrome.downloads.download({ url: data.url, filename: data.downFileName }, function (id) { downData[id] = data; }); }, index * 100); }; }); // 合并下载 $mergeDown.click(function () { const [checkedData, maxSize] = getCheckedData(); const taskId = Date.parse(new Date()); // 都是m3u8 自动合并并发送到ffmpeg if (checkedData.every(data => isM3U8(data))) { checkedData.forEach(function (data) { openParser(data, { ffmpeg: "merge", quantity: checkedData.length, taskId: taskId, autoDown: true, autoClose: true }); }); return true; } catDownload(checkedData, { ffmpeg: "merge" }) }); // 复制选中文件 $('#AllCopy').click(function () { const url = []; getData().forEach(function (data) { data.checked && url.push(copyLink(data)); }); navigator.clipboard.writeText(url.join("\n")); Tips(i18n.copiedToClipboard); }); // 全选 反选 $('#AllSelect, #invertSelection').click(function () { checkboxState = !checkboxState; let checked = false; if (this.id == "AllSelect") { checked = true; checkboxState = true; } getData().forEach(function (data) { data.checked = checked ? checked : !data.checked; }); mergeDownButton(); }); // unfoldAll展开全部 unfoldPlay展开可播放 unfoldFilter展开选中的 fold关闭展开 $('#unfoldAll, #unfoldPlay, #unfoldFilter, #fold').click(function () { $("#features").hide(); if (this.id == "unfoldAll") { getData().forEach(function (data) { if (data.html.is(":hidden")) { return true; } !data.urlPanelShow && data.panelHeading.click(); }); } else if (this.id == "unfoldPlay") { getData().forEach(function (data) { if (data.html.is(":hidden")) { return true; } data.isPlay && !data.urlPanelShow && data.panelHeading.click(); }); } else if (this.id == "unfoldFilter") { getData().forEach(function (data) { if (data.html.is(":hidden")) { return true; } data.checked && !data.urlPanelShow && data.panelHeading.click(); }); } else if (this.id == "fold") { getData().forEach(function (data) { if (data.html.is(":hidden")) { return true; } data.urlPanelShow && data.panelHeading.click(); }); } }); // 捕捉/录制 展开按钮 筛选按钮 按钮 // $('#Catch, #openUnfold, #openFilter, #more').click(function () { $('#openFilter, #more').click(function () { // const _height = parseInt($(".container").css("margin-bottom")); // $(".container").css("margin-bottom", ($down[0].offsetHeight + 26) + "px"); const $panel = $(`#${this.getAttribute("panel")}`); $panel.css("bottom", $down[0].offsetHeight + "px"); $(".more").not($panel).hide(); if ($panel.is(":hidden")) { $panel.css("display", "flex"); return; } // $(".container").css("margin-bottom", _height); $panel.hide(); }); // 正则筛选 $("#regular input").bind('keypress', function (event) { if (event.keyCode == "13") { const input = $(this).val(); if (input == "") { getData().forEach(function (data) { data.checked = true; data.html.show(); }); return; } const regex = new RegExp($(this).val()); getData().forEach(function (data) { if (!regex.test(data.url)) { data.checked = false; data.html.hide(); } }); $("#filter").hide(); } }); // 删除重复文件名 $("#duplicateFilenames").click(function () { duplicateFilenamesSet = new Set(); getData().forEach(function (value) { if (duplicateFilenamesSet.has(value.name)) { value.html.hide(); value.checked = false; return; } duplicateFilenamesSet.add(value.name); }); $("#filter").hide(); mergeDownButton(); }); // 清空数据 $('#Clear').click(function () { chrome.runtime.sendMessage({ Message: "clearData", tabId: G.tabId, type: activeTab }); chrome.runtime.sendMessage({ Message: "ClearIcon", type: activeTab, tabId: G.tabId }); if (activeTab) { currentCount = 0; $current.empty(); } else { allCount = 0; $all.empty(); } allData.get(activeTab).clear(); UItoggle(); }); // 模拟手机端 $("#MobileUserAgent").click(function () { chrome.runtime.sendMessage({ Message: "mobileUserAgent", tabId: G.tabId }, function () { G.refreshClear && $('#Clear').click(); updateButton(); }); }); // 自动下载 $("#AutoDown").click(function () { chrome.runtime.sendMessage({ Message: "autoDown", tabId: G.tabId }, function () { updateButton(); }); }); // 深度搜索 缓存捕捉 注入脚本 $("[type='script']").click(function () { chrome.runtime.sendMessage({ Message: "script", tabId: G.tabId, script: this.id + ".js" }, function () { G.autoClearMode > 0 && $('#Clear').click(); updateButton(); }); }); // 102以上开启 捕获按钮/注入脚本 if (G.version >= 102) { $("[type='script']").show(); } // Firefox 关闭一些功能 修复右边滚动条遮挡 if (G.isFirefox) { $("body").addClass("fixFirefoxRight"); $(".firefoxHide").each(function () { $(this).hide(); }); if (G.version < 128) { $(".firefoxHideScript").each(function () { $(this).hide(); }); } } // 跳转页面 $("[go]").click(function () { let url = this.getAttribute("go"); if (url == "ffmpegURL") { chrome.tabs.create({ url: G.ffmpegConfig.url }) return; } chrome.tabs.create({ url: url }); }); // 暂停 启用 $("#enable").click(function () { chrome.runtime.sendMessage({ Message: "enable" }, function (state) { $("#enable").html(state ? i18n.pause : i18n.enable); }); }); // 弹出窗口 $("#popup").click(function () { switch (G.popupMode) { case 0: chrome.tabs.create({ url: `preview.html?tabId=${G.tabId}` }); break; case 1: chrome.tabs.create({ url: `popup.html?tabId=${G.tabId}&type=tab` }); break; case 2: chrome.windows.create({ url: `preview.html?tabId=${G.tabId}`, type: "popup", height: 1080, width: 1920 }); break; case 3: chrome.windows.create({ url: `popup.html?tabId=${G.tabId}&type=window`, type: "popup", height: 1080, width: 1920 }); break; default: chrome.tabs.create({ url: `preview.html?tabId=${G.tabId}` }); break; } }); $("#currentPage").click(function () { chrome.tabs.query({ active: true, currentWindow: false }, function (tabs) { chrome.tabs.update({ url: `popup.html?tabId=${tabs[0].id}${_type ? "&type=" + _type : ""}` }); }); }); // 手动发送 $("#send2localSelect").click(function () { getData().forEach(function (item) { if (item.checked) { send2local("catch", item, item.tabId).then(function (success) { success && success?.ok && Tips(i18n.hasSent, 1000); }).catch(function (error) { error ? Tips(error, 1000) : Tips(i18n.sendFailed, 1000); }); } }); }); async function getPageDOM() { try { const result = await new Promise((resolve, reject) => { chrome.tabs.sendMessage(G.tabId, { Message: "getPage" }, { frameId: 0 }, (response) => { if (chrome.runtime.lastError) { reject(null); } else { resolve(response); } }); }); return new DOMParser().parseFromString(result, 'text/html'); } catch (error) { console.error('Error getting page:', error); return null; } } // 一些需要等待G变量加载完整的操作 const interval = setInterval(async function () { if (!G.initSyncComplete || !G.initLocalComplete || !G.tabId) { return; } clearInterval(interval); if (G.popup && !_tabId) { closeTab(); $("#popup").click(); return; } // 侧边面板模式 body 宽度100% if (_tabId) { G.tabId = _tabId; $("body").css("width", "100%"); $("#down").css("justify-content", "center").find("button").css("margin-left", "5px"); $("#popup").hide(); _type == "window" && $("#currentPage").show(); } // 获取页面DOM if (G.getHtmlDOM) { pageDOM = await getPageDOM(); } // 填充数据 chrome.runtime.sendMessage(chrome.runtime.id, { Message: "getData", tabId: G.tabId }, function (data) { if (!data || data === "OK") { $tips.html(i18n.noData); $tips.attr("data-i18n", "noData"); return; } currentCount = data.length; if (currentCount >= 500 && confirm(i18n("confirmLoading", [currentCount]))) { $mediaList.append($current); UItoggle(); return; } for (let key = 0; key < currentCount; key++) { $current.append(AddMedia(data[key])); } $mediaList.append($current); UItoggle(); }); // 监听资源数据 chrome.runtime.onMessage.addListener(function (Message, sender, sendResponse) { if (!Message.Message || !Message.data) { return; } // 添加资源 if (Message.Message == "popupAddData") { const html = AddMedia(Message.data, Message.data.tabId == G.tabId); if (Message.data.tabId == G.tabId) { !currentCount && $mediaList.append($current); currentCount++; $current.append(html); UItoggle(); } else if (allCount) { allCount++; $all.append(html); UItoggle(); } sendResponse("OK"); return true; } // 添加疑似密钥 if (Message.Message == "popupAddKey") { $("#maybeKeyTab").show(); chrome.tabs.query({}, function (tabs) { let tabId = -1; for (let item of tabs) { if (item.url == Message.url) { tabId = item.id; break; } } if (tabId == -1 || tabId == G.tabId) { $maybeKey.append(AddKey(Message.data)); } !$("#maybeKey .panel").length && $("#maybeKey").append($maybeKey); }); sendResponse("OK"); return true; } }); // 获取模拟手机 自动下载 捕获 状态 updateButton(); // 上一次设定的倍数 $("#playbackRate").val(G.playbackRate); loadCSS(); const observer = new MutationObserver(updateDownHeight); observer.observe($down[0], { childList: true, subtree: true, attributes: true }); setInterval(() => { updateDownHeight(); }, 233); // 疑似密钥 chrome.webNavigation.getAllFrames({ tabId: G.tabId }, function (frames) { if (!frames) { return; } for (let frame of frames) { chrome.tabs.sendMessage(G.tabId, { Message: "getKey" }, { frameId: frame.frameId }, function (result) { if (chrome.runtime.lastError || !result || result.length == 0) { return; } $("#maybeKeyTab").show(); for (let key of result) { $maybeKey.append(AddKey(key)); } $("#maybeKey").append($maybeKey); UItoggle(); }); } }); }, 0); /********************绑定事件END********************/ window.addEventListener('beforeunload', function () { chrome.runtime.sendMessage(chrome.runtime.id, { Message: "clearRedundant" }); }); // 按钮状态更新 function updateButton() { chrome.runtime.sendMessage({ Message: "getButtonState", tabId: G.tabId }, function (state) { for (let key in state) { const $DOM = $(`#${key}`); if (key == "MobileUserAgent") { $DOM.html(state.MobileUserAgent ? i18n.closeSimulation : i18n.simulateMobile); continue; } if (key == "AutoDown") { $DOM.html(state.AutoDown ? i18n.closeDownload : i18n.autoDownload); continue; } if (key == "enable") { $DOM.html(state.enable ? i18n.pause : i18n.enable); continue; } const script = G.scriptList.get(key + ".js"); $DOM.html(state[key] ? script.off : script.name); } }); } /* 格式判断 */ function isPlay(data) { if (G.Player && !isJSON(data) && !isPicture(data)) { return true; } const typeArray = ['video/ogg', 'video/mp4', 'video/webm', 'audio/ogg', 'audio/mp3', 'audio/wav', 'audio/m4a', 'video/3gp', 'video/mpeg', 'video/mov']; return isMediaExt(data.ext) || typeArray.includes(data.type) || isM3U8(data); } // 猫抓下载器 let catDownloadIsProcessing = false; function catDownload(data, extra = {}) { // 防止连续多次提交 if (catDownloadIsProcessing) { setTimeout(() => { catDownload(data, extra); }, 233); return; } catDownloadIsProcessing = true; if (!Array.isArray(data)) { data = [data]; } // 储存数据到临时变量 提高检索速度 localStorage.setItem('downloadData', JSON.stringify(data)); // 如果大于2G 询问是否使用流式下载 if (!extra.ffmpeg && !G.downStream && Math.max(...data.map(item => item._size)) > G.chromeLimitSize && confirm(i18n("fileTooLargeStream", ["2G"]))) { extra.downStream = 1; } // 发送消息给下载器 chrome.runtime.sendMessage(chrome.runtime.id, { Message: "catDownload", data: data }, (message) => { // 不存在下载器或者下载器出错 新建一个下载器 if (chrome.runtime.lastError || !message || message.message != "OK") { createCatDownload(data, extra); return; } catDownloadIsProcessing = false; }); } function createCatDownload(data, extra) { chrome.tabs.get(G.tabId, function (tab) { const arg = { url: `/downloader.html?${new URLSearchParams({ requestId: data.map(item => item.requestId).join(","), ...extra })}`, index: tab.index + 1, active: !G.downActive }; chrome.tabs.create(arg, (tab) => { // 循环获取tab.id 的状态 准备就绪 重置任务状态 const interval = setInterval(() => { chrome.tabs.get(tab.id, (tab) => { if (chrome.runtime.lastError || tab.status == "complete") { clearInterval(interval); catDownloadIsProcessing = false; } }); }); }); }); } // 提示 function Tips(text, delay = 200) { // 获取当前提示元素 const $tips = $('#TipsFixed'); // 停止当前所有动画 $tips.stop(true, true); // 设置新内容并显示 $tips .html(text) .fadeIn(500) .delay(delay) .fadeOut(500); } /* * 有资源 隐藏无资源提示 * 更新数量显示 * 如果标签是其他设置 隐藏底部按钮 */ function UItoggle() { const size = getData().size; size > 0 ? $tips.hide() : $tips.show().html(i18n.noData); $currentCount.text(currentCount ? `[${currentCount}]` : ""); $allCount.text(allCount ? `[${allCount}]` : ""); const id = $('.TabShow').attr("id"); if (id != "mediaList" && id != "allMediaList") { $tips.hide(); $down.hide(); } else if ($down.is(":hidden")) { $down.show(); } // 更新图标 $(".faviconFlag").each(function () { const data = getData(this.getAttribute("requestId")); if (data && data.webUrl && favicon.has(data.webUrl)) { this.setAttribute("src", favicon.get(data.webUrl)); this.classList.remove("faviconFlag"); } }); size >= 2 ? mergeDownButton() : $mergeDown.attr('disabled', true); } // 检查是否符合条件 更改 合并下载 按钮状态 function mergeDownButtonCheck(data) { if (!data.type) { return isMediaExt(data.ext); } return isMediaExt(data.ext) || data.type.startsWith("video") || data.type.startsWith("audio") || data.type.endsWith("octet-stream"); } function mergeDownButton() { const [checkedData, maxSize] = getCheckedData(); if (checkedData.length != 2 || (!G.isFirefox && maxSize > G.chromeLimitSize)) { // $mergeDown.hide(); $mergeDown.attr('disabled', true); return; } if (checkedData.every(mergeDownButtonCheck) || checkedData.every(data => isM3U8(data))) { // $mergeDown.show(); $mergeDown.removeAttr('disabled'); } } // 获取当前标签 所有选择的文件 function getCheckedData() { const checkedData = []; let maxSize = 0; getData().forEach(function (data) { if (data.checked) { const size = data._size ?? 0; maxSize = size > maxSize ? size : maxSize; checkedData.push(data); } }); return [checkedData, maxSize]; } // 获取当前标签的资源列表 存在requestId返回该资源 function getData(requestId = false) { if (requestId) { return allData.get(activeTab).get(requestId); } return allData.get(activeTab); } // 获取所有资源列表 function getAllData() { const data = []; data.push(...allData.get(true).values()); data.push(...allData.get(false).values()); return data; } // 更新底部按钮高度 function updateDownHeight() { $(".container").css("margin-bottom", ($down[0].offsetHeight + 2) + "px"); } function base64ToHex(base64) { let binaryString; try { binaryString = atob(base64); } catch (error) { console.error("Invalid Base64 string:", error, base64); return false; } let hexString = ''; for (let i = 0; i < binaryString.length; i++) { let hex = binaryString.charCodeAt(i).toString(16); if (hex.length === 1) { hex = '0' + hex; } hexString += hex; } return hexString; }