|
|
@@ -0,0 +1,211 @@
|
|
|
+~(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)
|