~(function (exports) { // 消息策略 const tactics = { // 请求价格限制配置 async request(requestOptions, sender, sendResponse, callback) { const res = await exports.req(requestOptions).catch(err => console.log(err)) Object.assign(state.wx, res['weixin.qq.com']) Object.assign(state.tencent, res['e.qq.com']) sendResponse(state) callback && callback(state) } } const simpleRequest = new Set(['get', 'head']) // xhr请求 exports.req = function (options = {}) { const { url = "", method = "get", data = {}, headers = {}, responseType = '', withCredentials = false, timeout = 18000 } = options const xhr = new XMLHttpRequest() const defaultHeaders = { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' } const finalHeaders = { ...defaultHeaders, ...headers } const finalData = (Object.prototype.toString.call(data).slice(8, -1) === 'Object' && String(finalHeaders['Content-Type']).includes('x-www-form-urlencoded')) ? Object.keys(data).map(key => `${key}=${encodeURIComponent(data[key])}`).join("&") : data const finalUrl = simpleRequest.has(method.toLowerCase()) ? `${url}?${finalData}` : url xhr.responseType = responseType xhr.withCredentials = withCredentials xhr.timeout = timeout return new Promise((resolve, reject) => { xhr.addEventListener("readystatechange", function () { if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { try { resolve(JSON.parse(xhr.responseText)) } catch { resolve(xhr.responseText) } finally { resolve(xhr.response) } } }) xhr.addEventListener("error", function () { reject(xhr.response) }) xhr.addEventListener('timeout', function () { reject('timeout') }) xhr.open(method, finalUrl) Object.keys(finalHeaders).forEach(key => { xhr.setRequestHeader(key, headers[key]) }) xhr.send(simpleRequest.has(method.toLowerCase()) ? null : finalData) }) } // 状态 exports.state = { // 微信公众平台价格限制 wx: { ocpa: 0, ocpx: 0 }, // 腾讯广告价格限制 tencent: { ocpa: 0, ocpx: 0 }, // 广告id -> 出价类型 映射 adMap: new Map() } // 监听content-scripts 消息 exports.listenContentMessage = function () { return new Promise((resolve, reject) => { chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) { const handler = tactics[message.type] handler && handler(message.payload, sender, sendResponse, function (res) { resolve(res) }) return true }) }) } // 拦截出价 exports.beforeWxPriceRequest = function () { chrome.webRequest.onBeforeRequest.addListener( details => { const { args } = details.requestBody.formData || {} if (!args) return const jsonArgs = JSON.parse(args) const priceType = exports.state.adMap.get((jsonArgs.oper_aids[0] || {}).aid) const max = +state.wx[priceType] let invalid = jsonArgs.oper_aids.some(item => item.bid / 100 > max) if (invalid) { return { cancel: true } } }, { urls: ["https://mp.weixin.qq.com/promotion/v3/batch_update_adgroup"] }, ["requestBody", "blocking"] ) } // 拦截计划 exports.beforeWxPlansRequest = function (priceType = 'ocpa') { chrome.webRequest.onBeforeRequest.addListener( details => { const { formData } = details.requestBody const { args } = formData || {} const max = +state.wx[priceType] let invalid = !args || JSON.parse(args).target_groups.some(target => target.ad_groups.some(ad => ad.ad_group.bid / 100 > max)) if (invalid) { return { cancel: true } } }, { urls: [ "https://mp.weixin.qq.com/promotion/v3/update_campaign_info", 'https://mp.weixin.qq.com/promotion/v3/create_campaign_info' ] }, ["requestBody", "blocking"] ) } // 获取cookie function getCookie(callback) { chrome.tabs.query({ active: true }, (tabs) => { const tabId = tabs[0] && tabs[0].id chrome.tabs.sendMessage(tabId, { type: 'getCookie' }, res => { callback(res) }) }) } // 拦截出价列表 exports.beforeWxRequestPriceList = function () { const filters = { urls: ["https://mp.weixin.qq.com/promotion/as_rock*"] } const typeMap = { '按下单出价': 'ocpx', '按关注出价': 'ocpa', '按曝光出价': 'ocpa', '按点击出价': 'ocpa' } const callback = function (details) { const query = helper.queryToJson(details.url) if (query.action === 'get_adgroup_data' && query.custom !== '1') { let headers = details.requestHeaders.reduce((pre, cur) => { pre[cur.name] = cur.value return pre }, {}) getCookie(async (Cookie) => { const res = await exports.req({ method: 'get', url: `${details.url}&custom=1`, headers: { ...headers, Cookie, 'Accept-Encoding': 'gzip, deflate, br', 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8', Connection: 'keep-alive', Host: 'mp.weixin.qq.com', Referer: 'https://mp.weixin.qq.com/promotion/readtemplate?t=campaign/manage&lang=zh_CN&token=1483508456&type=1' } }) if (res.msg === 'ok') { let map = new Map() res.list && res.list.forEach(item => { map.set(item.adgroup_info.aid, typeMap[item.adgroup_info.bid_action_type] || 'ocpa') }) exports.state.adMap = map } }) } } chrome.webRequest.onBeforeSendHeaders.addListener(callback, filters, ['requestHeaders']) } })(this || window)