This commit is contained in:
ChuXun
2025-10-19 20:55:27 +08:00
parent e879ccefb3
commit 53f9554f38
99 changed files with 22308 additions and 2 deletions

869
js/background.js Normal file
View File

@@ -0,0 +1,869 @@
importScripts("/js/function.js", "/js/init.js");
// Service Worker 5分钟后会强制终止扩展
// https://bugs.chromium.org/p/chromium/issues/detail?id=1271154
// https://stackoverflow.com/questions/66618136/persistent-service-worker-in-chrome-extension/70003493#70003493
chrome.webNavigation.onBeforeNavigate.addListener(function () { return; });
chrome.webNavigation.onHistoryStateUpdated.addListener(function () { return; });
chrome.runtime.onConnect.addListener(function (Port) {
if (chrome.runtime.lastError || Port.name !== "HeartBeat") return;
Port.postMessage("HeartBeat");
Port.onMessage.addListener(function (message, Port) { return; });
const interval = setInterval(function () {
clearInterval(interval);
Port.disconnect();
}, 250000);
Port.onDisconnect.addListener(function () {
interval && clearInterval(interval);
if (chrome.runtime.lastError) { return; }
});
});
/**
* 定时任务
* nowClear clear 清理冗余数据
* save 保存数据
*/
chrome.alarms.onAlarm.addListener(function (alarm) {
if (alarm.name === "nowClear" || alarm.name === "clear") {
clearRedundant();
return;
}
if (alarm.name === "save") {
(chrome.storage.session ?? chrome.storage.local).set({ MediaData: cacheData });
return;
}
});
// onBeforeRequest 浏览器发送请求之前使用正则匹配发送请求的URL
// chrome.webRequest.onBeforeRequest.addListener(
// function (data) {
// try { findMedia(data, true); } catch (e) { console.log(e); }
// }, { urls: ["<all_urls>"] }, ["requestBody"]
// );
// 保存requestHeaders
chrome.webRequest.onSendHeaders.addListener(
function (data) {
if (G && G.initSyncComplete && !G.enable) { return; }
if (data.requestHeaders) {
G.requestHeaders.set(data.requestId, data.requestHeaders);
data.allRequestHeaders = data.requestHeaders;
}
try { findMedia(data, true); } catch (e) { console.log(e); }
}, { urls: ["<all_urls>"] }, ['requestHeaders',
chrome.webRequest.OnBeforeSendHeadersOptions.EXTRA_HEADERS].filter(Boolean)
);
// onResponseStarted 浏览器接收到第一个字节触发,保证有更多信息判断资源类型
chrome.webRequest.onResponseStarted.addListener(
function (data) {
try {
data.allRequestHeaders = G.requestHeaders.get(data.requestId);
if (data.allRequestHeaders) {
G.requestHeaders.delete(data.requestId);
}
findMedia(data);
} catch (e) { console.log(e, data); }
}, { urls: ["<all_urls>"] }, ["responseHeaders"]
);
// 删除失败的requestHeadersData
chrome.webRequest.onErrorOccurred.addListener(
function (data) {
G.requestHeaders.delete(data.requestId);
G.blackList.delete(data.requestId);
}, { urls: ["<all_urls>"] }
);
function findMedia(data, isRegex = false, filter = false, timer = false) {
// Service Worker被强行杀死之后重新自我唤醒等待全局变量初始化完成。
if (!G || !G.initSyncComplete || !G.initLocalComplete || G.tabId == undefined || cacheData.init) {
if (timer) { return; }
setTimeout(() => {
findMedia(data, isRegex, filter, true);
}, 500);
return;
}
// 检查 是否启用 是否在当前标签是否在屏蔽列表中
const blockUrlFlag = data.tabId && data.tabId > 0 && G.blockUrlSet.has(data.tabId);
if (!G.enable || (G.blockUrlWhite ? !blockUrlFlag : blockUrlFlag)) {
return;
}
data.getTime = Date.now();
if (!isRegex && G.blackList.has(data.requestId)) {
G.blackList.delete(data.requestId);
return;
}
// 屏蔽特殊页面发起的资源
if (data.initiator != "null" &&
data.initiator != undefined &&
isSpecialPage(data.initiator)) { return; }
if (G.isFirefox &&
data.originUrl &&
isSpecialPage(data.originUrl)) { return; }
// 屏蔽特殊页面的资源
if (isSpecialPage(data.url)) { return; }
const urlParsing = new URL(data.url);
let [name, ext] = fileNameParse(urlParsing.pathname);
//正则匹配
if (isRegex && !filter) {
for (let key in G.Regex) {
if (!G.Regex[key].state) { continue; }
G.Regex[key].regex.lastIndex = 0;
let result = G.Regex[key].regex.exec(data.url);
if (result == null) { continue; }
if (G.Regex[key].blackList) {
G.blackList.add(data.requestId);
return;
}
data.extraExt = G.Regex[key].ext ? G.Regex[key].ext : undefined;
if (result.length == 1) {
findMedia(data, true, true);
return;
}
result.shift();
result = result.map(str => decodeURIComponent(str));
if (!result[0].startsWith('https://') && !result[0].startsWith('http://')) {
result[0] = urlParsing.protocol + "//" + data.url;
}
data.url = result.join("");
findMedia(data, true, true);
return;
}
return;
}
// 非正则匹配
if (!isRegex) {
// 获取头部信息
data.header = getResponseHeadersValue(data);
//检查后缀
if (!filter && ext != undefined) {
filter = CheckExtension(ext, data.header?.size);
if (filter == "break") { return; }
}
//检查类型
if (!filter && data.header?.type != undefined) {
filter = CheckType(data.header.type, data.header?.size);
if (filter == "break") { return; }
}
//查找附件
if (!filter && data.header?.attachment != undefined) {
const res = data.header.attachment.match(reFilename);
if (res && res[1]) {
[name, ext] = fileNameParse(decodeURIComponent(res[1]));
filter = CheckExtension(ext, 0);
if (filter == "break") { return; }
}
}
//放过类型为media的资源
if (data.type == "media") {
filter = true;
}
}
if (!filter) { return; }
// 谜之原因 获取得资源 tabId可能为 -1 firefox中则正常
// 检查是 -1 使用当前激活标签得tabID
data.tabId = data.tabId == -1 ? G.tabId : data.tabId;
cacheData[data.tabId] ??= [];
cacheData[G.tabId] ??= [];
// 缓存数据大于9999条 清空缓存 避免内存占用过多
if (cacheData[data.tabId].length > G.maxLength) {
cacheData[data.tabId] = [];
(chrome.storage.session ?? chrome.storage.local).set({ MediaData: cacheData });
return;
}
// 查重 避免CPU占用 大于500 强制关闭查重
// if (G.checkDuplicates && cacheData[data.tabId].length <= 500) {
// for (let item of cacheData[data.tabId]) {
// if (item.url.length == data.url.length &&
// item.cacheURL.pathname == urlParsing.pathname &&
// item.cacheURL.host == urlParsing.host &&
// item.cacheURL.search == urlParsing.search) { return; }
// }
// }
if (G.checkDuplicates && cacheData[data.tabId].length <= 500) {
const tabFingerprints = G.urlMap.get(data.tabId) || new Set();
if (tabFingerprints.has(data.url)) {
return; // 找到重复,直接返回
}
tabFingerprints.add(data.url);
G.urlMap.set(data.tabId, tabFingerprints);
if (tabFingerprints.size >= 500) {
tabFingerprints.clear();
}
}
chrome.tabs.get(data.tabId, async function (webInfo) {
if (chrome.runtime.lastError) { return; }
data.requestHeaders = getRequestHeaders(data);
// requestHeaders 中cookie 单独列出来
if (data.requestHeaders?.cookie) {
data.cookie = data.requestHeaders.cookie;
data.requestHeaders.cookie = undefined;
}
const info = {
name: name,
url: data.url,
size: data.header?.size,
ext: ext,
type: data.mime ?? data.header?.type,
tabId: data.tabId,
isRegex: isRegex,
requestId: data.requestId ?? Date.now().toString(),
initiator: data.initiator,
requestHeaders: data.requestHeaders,
cookie: data.cookie,
// cacheURL: { host: urlParsing.host, search: urlParsing.search, pathname: urlParsing.pathname },
getTime: data.getTime
};
// 不存在扩展使用类型
if (info.ext === undefined && info.type !== undefined) {
info.ext = info.type.split("/")[1];
}
// 正则匹配的备注扩展
if (data.extraExt) {
info.ext = data.extraExt;
}
// 不存在 initiator 和 referer 使用web url代替initiator
if (info.initiator == undefined || info.initiator == "null") {
info.initiator = info.requestHeaders?.referer ?? webInfo?.url;
}
// 装载页面信息
info.title = webInfo?.title ?? "NULL";
info.favIconUrl = webInfo?.favIconUrl;
info.webUrl = webInfo?.url;
// 屏蔽资源
if (!isRegex && G.blackList.has(data.requestId)) {
G.blackList.delete(data.requestId);
return;
}
// 发送到popup 并检查自动下载
chrome.runtime.sendMessage({ Message: "popupAddData", data: info }, function () {
if (G.featAutoDownTabId.size > 0 && G.featAutoDownTabId.has(info.tabId) && chrome.downloads?.State) {
try {
const downDir = info.title == "NULL" ? "CatCatch/" : stringModify(info.title) + "/";
let fileName = isEmpty(info.name) ? stringModify(info.title) + '.' + info.ext : decodeURIComponent(stringModify(info.name));
if (G.TitleName) {
fileName = filterFileName(templates(G.downFileName, info));
} else {
fileName = downDir + fileName;
}
chrome.downloads.download({
url: info.url,
filename: fileName
});
} catch (e) { return; }
}
if (chrome.runtime.lastError) { return; }
});
// 数据发送
if (G.send2local) {
try { send2local("catch", { ...info, requestHeaders: data.allRequestHeaders }, info.tabId); } catch (e) { console.log(e); }
}
// 储存数据
cacheData[info.tabId] ??= [];
cacheData[info.tabId].push(info);
// 当前标签媒体数量大于100 开启防抖 等待5秒储存 或 积累10个资源储存一次。
if (cacheData[info.tabId].length >= 100 && debounceCount <= 10) {
debounceCount++;
clearTimeout(debounce);
debounce = setTimeout(function () { save(info.tabId); }, 5000);
return;
}
// 时间间隔小于500毫秒 等待2秒储存
if (Date.now() - debounceTime <= 500) {
clearTimeout(debounce);
debounceTime = Date.now();
debounce = setTimeout(function () { save(info.tabId); }, 2000);
return;
}
save(info.tabId);
});
}
// cacheData数据 储存到 chrome.storage.local
function save(tabId) {
clearTimeout(debounce);
debounceTime = Date.now();
debounceCount = 0;
(chrome.storage.session ?? chrome.storage.local).set({ MediaData: cacheData }, function () {
chrome.runtime.lastError && console.log(chrome.runtime.lastError);
});
cacheData[tabId] && SetIcon({ number: cacheData[tabId].length, tabId: tabId });
}
/**
* 监听 扩展 message 事件
*/
chrome.runtime.onMessage.addListener(function (Message, sender, sendResponse) {
if (chrome.runtime.lastError) { return; }
if (!G.initLocalComplete || !G.initSyncComplete) {
sendResponse("error");
return true;
}
// 以下检查是否有 tabId 不存在使用当前标签
Message.tabId = Message.tabId ?? G.tabId;
// 从缓存中保存数据到本地
if (Message.Message == "pushData") {
(chrome.storage.session ?? chrome.storage.local).set({ MediaData: cacheData });
sendResponse("ok");
return true;
}
// 获取所有数据
if (Message.Message == "getAllData") {
sendResponse(cacheData);
return true;
}
/**
* 设置扩展图标数字
* 提供 type 删除标签为 tabId 的数字
* 不提供type 删除所有标签的数字
*/
if (Message.Message == "ClearIcon") {
Message.type ? SetIcon({ tabId: Message.tabId }) : SetIcon();
sendResponse("ok");
return true;
}
// 启用/禁用扩展
if (Message.Message == "enable") {
G.enable = !G.enable;
chrome.storage.sync.set({ enable: G.enable });
chrome.action.setIcon({ path: G.enable ? "/img/icon.png" : "/img/icon-disable.png" });
sendResponse(G.enable);
return true;
}
/**
* 提供requestId数组 获取指定的数据
*/
if (Message.Message == "getData" && Message.requestId) {
// 判断Message.requestId是否数组
if (!Array.isArray(Message.requestId)) {
Message.requestId = [Message.requestId];
}
const response = [];
if (Message.requestId.length) {
for (let item in cacheData) {
for (let data of cacheData[item]) {
if (Message.requestId.includes(data.requestId)) {
response.push(data);
}
}
}
}
sendResponse(response.length ? response : "error");
return true;
}
/**
* 提供 tabId 获取该标签数据
*/
if (Message.Message == "getData") {
sendResponse(cacheData[Message.tabId]);
return true;
}
/**
* 获取各按钮状态
* 模拟手机 自动下载 启用 以及各种脚本状态
*/
if (Message.Message == "getButtonState") {
let state = {
MobileUserAgent: G.featMobileTabId.has(Message.tabId),
AutoDown: G.featAutoDownTabId.has(Message.tabId),
enable: G.enable,
}
G.scriptList.forEach(function (item, key) {
state[item.key] = item.tabId.has(Message.tabId);
});
sendResponse(state);
return true;
}
// 对tabId的标签 进行模拟手机操作
if (Message.Message == "mobileUserAgent") {
mobileUserAgent(Message.tabId, !G.featMobileTabId.has(Message.tabId));
chrome.tabs.reload(Message.tabId, { bypassCache: true });
sendResponse("ok");
return true;
}
// 对tabId的标签 开启 关闭 自动下载
if (Message.Message == "autoDown") {
if (G.featAutoDownTabId.has(Message.tabId)) {
G.featAutoDownTabId.delete(Message.tabId);
} else {
G.featAutoDownTabId.add(Message.tabId);
}
(chrome.storage.session ?? chrome.storage.local).set({ featAutoDownTabId: Array.from(G.featAutoDownTabId) });
sendResponse("ok");
return true;
}
// 对tabId的标签 脚本注入或删除
if (Message.Message == "script") {
if (!G.scriptList.has(Message.script)) {
sendResponse("error no exists");
return false;
}
const script = G.scriptList.get(Message.script);
const scriptTabid = script.tabId;
const refresh = Message.refresh ?? script.refresh;
if (scriptTabid.has(Message.tabId)) {
scriptTabid.delete(Message.tabId);
if (Message.script == "search.js") {
G.deepSearchTemporarilyClose = Message.tabId;
}
refresh && chrome.tabs.reload(Message.tabId, { bypassCache: true });
sendResponse("ok");
return true;
}
scriptTabid.add(Message.tabId);
if (refresh) {
chrome.tabs.reload(Message.tabId, { bypassCache: true });
} else {
const files = [`catch-script/${Message.script}`];
script.i18n && files.unshift("catch-script/i18n.js");
chrome.scripting.executeScript({
target: { tabId: Message.tabId, allFrames: script.allFrames },
files: files,
injectImmediately: true,
world: script.world
});
}
sendResponse("ok");
return true;
}
// 脚本注入 脚本申请多语言文件
if (Message.Message == "scriptI18n") {
chrome.scripting.executeScript({
target: { tabId: Message.tabId, allFrames: true },
files: ["catch-script/i18n.js"],
injectImmediately: true,
world: "MAIN"
});
sendResponse("ok");
return true;
}
// Heart Beat
if (Message.Message == "HeartBeat") {
chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
if (tabs[0] && tabs[0].id) {
G.tabId = tabs[0].id;
}
});
sendResponse("HeartBeat OK");
return true;
}
// 清理数据
if (Message.Message == "clearData") {
// 当前标签
if (Message.type) {
delete cacheData[Message.tabId];
(chrome.storage.session ?? chrome.storage.local).set({ MediaData: cacheData });
clearRedundant();
sendResponse("OK");
return true;
}
// 其他标签
for (let item in cacheData) {
if (item == Message.tabId) { continue; }
delete cacheData[item];
}
(chrome.storage.session ?? chrome.storage.local).set({ MediaData: cacheData });
clearRedundant();
sendResponse("OK");
return true;
}
// 清理冗余数据
if (Message.Message == "clearRedundant") {
clearRedundant();
sendResponse("OK");
return true;
}
// 从 content-script 或 catch-script 传来的媒体url
if (Message.Message == "addMedia") {
chrome.tabs.query({}, function (tabs) {
for (let item of tabs) {
if (item.url == Message.href) {
findMedia({ url: Message.url, tabId: item.id, extraExt: Message.extraExt, mime: Message.mime, requestId: Message.requestId, requestHeaders: Message.requestHeaders }, true, true);
return true;
}
}
findMedia({ url: Message.url, tabId: -1, extraExt: Message.extraExt, mime: Message.mime, requestId: Message.requestId, initiator: Message.href, requestHeaders: Message.requestHeaders }, true, true);
});
sendResponse("ok");
return true;
}
// ffmpeg网页通信
if (Message.Message == "catCatchFFmpeg") {
const data = { ...Message, Message: "ffmpeg", tabId: Message.tabId ?? sender.tab.id, version: G.ffmpegConfig.version };
chrome.tabs.query({ url: G.ffmpegConfig.url + "*" }, function (tabs) {
if (chrome.runtime.lastError || !tabs.length) {
chrome.tabs.create({ url: G.ffmpegConfig.url, active: Message.active ?? true }, function (tab) {
if (chrome.runtime.lastError) { return; }
G.ffmpegConfig.tab = tab.id;
G.ffmpegConfig.cacheData.push(data);
});
return true;
}
if (tabs[0].status == "complete") {
chrome.tabs.sendMessage(tabs[0].id, data);
} else {
G.ffmpegConfig.tab = tabs[0].id;
G.ffmpegConfig.cacheData.push(data);
}
});
sendResponse("ok");
return true;
}
// 发送数据到本地
if (Message.Message == "send2local" && G.send2local) {
try { send2local(Message.action, Message.data, Message.tabId); } catch (e) { console.log(e); }
sendResponse("ok");
return true;
}
});
// 选定标签 更新G.tabId
// chrome.tabs.onHighlighted.addListener(function (activeInfo) {
// if (activeInfo.windowId == -1 || !activeInfo.tabIds || !activeInfo.tabIds.length) { return; }
// G.tabId = activeInfo.tabIds[0];
// });
/**
* 监听 切换标签
* 更新全局变量 G.tabId 为当前标签
*/
chrome.tabs.onActivated.addListener(function (activeInfo) {
G.tabId = activeInfo.tabId;
if (cacheData[G.tabId] !== undefined) {
SetIcon({ number: cacheData[G.tabId].length, tabId: G.tabId });
return;
}
SetIcon({ tabId: G.tabId });
});
// 切换窗口更新全局变量G.tabId
chrome.windows.onFocusChanged.addListener(function (activeInfo) {
if (activeInfo == -1) { return; }
chrome.tabs.query({ active: true, windowId: activeInfo }, function (tabs) {
if (tabs[0] && tabs[0].id) {
G.tabId = tabs[0].id;
} else {
G.tabId = -1;
}
});
}, { filters: ["normal"] });
/**
* 监听 标签页面更新
* 检查 清理数据
* 检查 是否在屏蔽列表中
*/
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
if (isSpecialPage(tab.url) || tabId <= 0 || !G.initSyncComplete) { return; }
if (changeInfo.status && changeInfo.status == "loading" && G.autoClearMode == 2) {
G.urlMap.delete(tabId);
chrome.alarms.get("save", function (alarm) {
if (!alarm) {
delete cacheData[tabId];
SetIcon({ tabId: tabId });
chrome.alarms.create("save", { when: Date.now() + 1000 });
}
});
}
// 检查当前标签是否在屏蔽列表中
if (changeInfo.url && tabId > 0 && G.blockUrl.length) {
G.blockUrlSet.delete(tabId);
if (isLockUrl(changeInfo.url)) {
G.blockUrlSet.add(tabId);
}
}
chrome.sidePanel.setOptions({
tabId,
path: "popup.html?tabId=" + tabId
});
});
/**
* 监听 frame 正在载入
* 检查 是否在屏蔽列表中 (frameId == 0 为主框架)
* 检查 自动清理 (frameId == 0 为主框架)
* 检查 注入脚本
*/
chrome.webNavigation.onCommitted.addListener(function (details) {
if (isSpecialPage(details.url) || details.tabId <= 0 || !G.initSyncComplete) { return; }
// 刷新页面 检查是否在屏蔽列表中
if (details.frameId == 0 && details.transitionType == "reload") {
G.blockUrlSet.delete(details.tabId);
if (isLockUrl(details.url)) {
G.blockUrlSet.add(details.tabId);
}
}
// 刷新清理角标数
if (details.frameId == 0 && (!['auto_subframe', 'manual_subframe', 'form_submit'].includes(details.transitionType)) && G.autoClearMode == 1) {
delete cacheData[details.tabId];
G.urlMap.delete(details.tabId);
(chrome.storage.session ?? chrome.storage.local).set({ MediaData: cacheData });
SetIcon({ tabId: details.tabId });
}
// chrome内核版本 102 以下不支持 chrome.scripting.executeScript API
if (G.version < 102) { return; }
if (G.deepSearch && G.deepSearchTemporarilyClose != details.tabId) {
G.scriptList.get("search.js").tabId.add(details.tabId);
G.deepSearchTemporarilyClose = null;
}
// catch-script 脚本
G.scriptList.forEach(function (item, script) {
if (!item.tabId.has(details.tabId) || !item.allFrames) { return true; }
const files = [`catch-script/${script}`];
item.i18n && files.unshift("catch-script/i18n.js");
chrome.scripting.executeScript({
target: { tabId: details.tabId, frameIds: [details.frameId] },
files: files,
injectImmediately: true,
world: item.world
});
});
// 模拟手机
if (G.initLocalComplete && G.featMobileTabId.size > 0 && G.featMobileTabId.has(details.tabId)) {
chrome.scripting.executeScript({
args: [G.MobileUserAgent.toString()],
target: { tabId: details.tabId, frameIds: [details.frameId] },
func: function () {
Object.defineProperty(navigator, 'userAgent', { value: arguments[0], writable: false });
},
injectImmediately: true,
world: "MAIN"
});
}
});
/**
* 监听 标签关闭 清理数据
*/
chrome.tabs.onRemoved.addListener(function (tabId) {
// 清理缓存数据
chrome.alarms.get("nowClear", function (alarm) {
!alarm && chrome.alarms.create("nowClear", { when: Date.now() + 1000 });
});
if (G.initSyncComplete) {
G.blockUrlSet.has(tabId) && G.blockUrlSet.delete(tabId);
}
});
/**
* 浏览器 扩展快捷键
*/
chrome.commands.onCommand.addListener(function (command) {
if (command == "auto_down") {
if (G.featAutoDownTabId.has(G.tabId)) {
G.featAutoDownTabId.delete(G.tabId);
} else {
G.featAutoDownTabId.add(G.tabId);
}
(chrome.storage.session ?? chrome.storage.local).set({ featAutoDownTabId: Array.from(G.featAutoDownTabId) });
} else if (command == "catch") {
const scriptTabid = G.scriptList.get("catch.js").tabId;
scriptTabid.has(G.tabId) ? scriptTabid.delete(G.tabId) : scriptTabid.add(G.tabId);
chrome.tabs.reload(G.tabId, { bypassCache: true });
} else if (command == "m3u8") {
chrome.tabs.create({ url: "m3u8.html" });
} else if (command == "clear") {
delete cacheData[G.tabId];
(chrome.storage.session ?? chrome.storage.local).set({ MediaData: cacheData });
clearRedundant();
SetIcon({ tabId: G.tabId });
} else if (command == "enable") {
G.enable = !G.enable;
chrome.storage.sync.set({ enable: G.enable });
chrome.action.setIcon({ path: G.enable ? "/img/icon.png" : "/img/icon-disable.png" });
} else if (command == "reboot") {
chrome.runtime.reload();
} else if (command == "deepSearch") {
const script = G.scriptList.get("search.js");
const scriptTabid = script.tabId;
if (scriptTabid.has(G.tabId)) {
scriptTabid.delete(G.tabId);
G.deepSearchTemporarilyClose = G.tabId;
chrome.tabs.reload(G.tabId, { bypassCache: true });
return;
}
scriptTabid.add(G.tabId);
chrome.tabs.reload(G.tabId, { bypassCache: true });
}
});
/**
* 监听 页面完全加载完成 判断是否在线ffmpeg页面
* 如果是在线ffmpeg 则发送数据
*/
chrome.webNavigation.onCompleted.addListener(function (details) {
if (G.ffmpegConfig.tab && details.tabId == G.ffmpegConfig.tab) {
setTimeout(() => {
G.ffmpegConfig.cacheData.forEach(data => {
chrome.tabs.sendMessage(details.tabId, data);
});
G.ffmpegConfig.cacheData = [];
G.ffmpegConfig.tab = 0;
}, 500);
}
});
/**
* 检查扩展名和大小
* @param {String} ext
* @param {Number} size
* @returns {Boolean|String}
*/
function CheckExtension(ext, size) {
const Ext = G.Ext.get(ext);
if (!Ext) { return false; }
if (!Ext.state) { return "break"; }
if (Ext.size != 0 && size != undefined && size <= Ext.size * 1024) { return "break"; }
return true;
}
/**
* 检查类型和大小
* @param {String} dataType
* @param {Number} dataSize
* @returns {Boolean|String}
*/
function CheckType(dataType, dataSize) {
const typeInfo = G.Type.get(dataType.split("/")[0] + "/*") || G.Type.get(dataType);
if (!typeInfo) { return false; }
if (!typeInfo.state) { return "break"; }
if (typeInfo.size != 0 && dataSize != undefined && dataSize <= typeInfo.size * 1024) { return "break"; }
return true;
}
/**
* 获取文件名及扩展名
* @param {String} pathname
* @returns {Array}
*/
function fileNameParse(pathname) {
let fileName = decodeURI(pathname.split("/").pop());
let ext = fileName.split(".");
ext = ext.length == 1 ? undefined : ext.pop().toLowerCase();
return [fileName, ext ? ext : undefined];
}
/**
* 获取响应头信息
* @param {Object} data
* @returns {Object}
*/
function getResponseHeadersValue(data) {
const header = {};
if (data.responseHeaders == undefined || data.responseHeaders.length == 0) { return header; }
for (let item of data.responseHeaders) {
item.name = item.name.toLowerCase();
if (item.name == "content-length") {
header.size ??= parseInt(item.value);
} else if (item.name == "content-type") {
header.type = item.value.split(";")[0].toLowerCase();
} else if (item.name == "content-disposition") {
header.attachment = item.value;
} else if (item.name == "content-range") {
let size = item.value.split('/')[1];
if (size !== '*') {
header.size = parseInt(size);
}
}
}
return header;
}
/**
* 获取请求头
* @param {Object} data
* @returns {Object|Boolean}
*/
function getRequestHeaders(data) {
if (data.allRequestHeaders == undefined || data.allRequestHeaders.length == 0) { return false; }
const header = {};
for (let item of data.allRequestHeaders) {
item.name = item.name.toLowerCase();
if (item.name == "referer") {
header.referer = item.value;
} else if (item.name == "origin") {
header.origin = item.value;
} else if (item.name == "cookie") {
header.cookie = item.value;
} else if (item.name == "authorization") {
header.authorization = item.value;
}
}
if (Object.keys(header).length) {
return header;
}
return false;
}
//设置扩展图标
function SetIcon(obj) {
if (obj?.number == 0 || obj?.number == undefined) {
chrome.action.setBadgeText({ text: "", tabId: obj?.tabId ?? G.tabId }, function () { if (chrome.runtime.lastError) { return; } });
// chrome.action.setTitle({ title: "还没闻到味儿~", tabId: obj.tabId }, function () { if (chrome.runtime.lastError) { return; } });
} else if (G.badgeNumber) {
obj.number = obj.number > 999 ? "999+" : obj.number.toString();
chrome.action.setBadgeText({ text: obj.number, tabId: obj.tabId }, function () { if (chrome.runtime.lastError) { return; } });
// chrome.action.setTitle({ title: "抓到 " + obj.number + " 条鱼", tabId: obj.tabId }, function () { if (chrome.runtime.lastError) { return; } });
}
}
// 模拟手机端
function mobileUserAgent(tabId, change = false) {
if (change) {
G.featMobileTabId.add(tabId);
(chrome.storage.session ?? chrome.storage.local).set({ featMobileTabId: Array.from(G.featMobileTabId) });
chrome.declarativeNetRequest.updateSessionRules({
removeRuleIds: [tabId],
addRules: [{
"id": tabId,
"action": {
"type": "modifyHeaders",
"requestHeaders": [{
"header": "User-Agent",
"operation": "set",
"value": G.MobileUserAgent
}]
},
"condition": {
"tabIds": [tabId],
"resourceTypes": Object.values(chrome.declarativeNetRequest.ResourceType)
}
}]
});
return true;
}
G.featMobileTabId.delete(tabId) && (chrome.storage.session ?? chrome.storage.local).set({ featMobileTabId: Array.from(G.featMobileTabId) });
chrome.declarativeNetRequest.updateSessionRules({
removeRuleIds: [tabId]
});
}
// 判断特殊页面
function isSpecialPage(url) {
if (!url || url == "null") { return true; }
return !(url.startsWith("http://") || url.startsWith("https://") || url.startsWith("blob:"));
}
// 测试
// chrome.storage.local.get(function (data) { console.log(data.MediaData) });
// chrome.declarativeNetRequest.getSessionRules(function (rules) { console.log(rules); });
// chrome.tabs.query({}, function (tabs) { for (let item of tabs) { console.log(item.id); } });