From 0bc06aa38b111520a7d1e2e27fd63daaccb3ec5a Mon Sep 17 00:00:00 2001 From: Hex Date: Mon, 6 Mar 2023 15:51:13 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- bot.js | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++ smzdm_task.js | 148 +++------------------------------------------- 3 files changed, 169 insertions(+), 142 deletions(-) create mode 100644 bot.js diff --git a/README.md b/README.md index a08d42e..29e1673 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ ### 青龙拉库 ```bash -ql repo https://github.com/hex-ci/smzdm_script.git "" "env.js" "env.js" +ql repo https://github.com/hex-ci/smzdm_script.git "" "env.js|bot.js" "env.js|bot.js" ``` 建议更改定时为随机时间 diff --git a/bot.js b/bot.js new file mode 100644 index 0000000..2a910a5 --- /dev/null +++ b/bot.js @@ -0,0 +1,161 @@ +const crypto = require('crypto'); +const got = require('got'); + +// ------------------------------------ + +const APP_VERSION = '10.4.26'; +const APP_VERSION_REV = '866'; + +const DEFAULT_USER_AGENT = `smzdm_android_V${APP_VERSION} rv:${APP_VERSION_REV} (Redmi Note 3;Android10.0;zh)smzdmapp`; +const DEFAULT_WEB_USER_AGENT = `Mozilla/5.0 (Linux; Android 10.0; Redmi Build/Redmi Note 3; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/95.0.4638.74 Mobile Safari/537.36{ smzdm_android_V${APP_VERSION} rv:${APP_VERSION_REV} (Redmi;Android10.0;zh) jsbv_1.0.0 webv_2.0 smzdmapp }`; + +const SIGN_KEY = 'apr1$AwP!wRRT$gJ/q.X24poeBInlUJC'; + +// ------------------------------------ + +const randomStr = (len = 18) => { + const char = '0123456789'; + let str = ''; + + for (let i = 0; i < len; i++) { + str += char.charAt(Math.floor(Math.random() * char.length)); + } + + return str; +}; + +const parseJSON = (str) => { + try { + return JSON.parse(str); + } + catch (e) { + return {}; + } +}; + +const removeTags = (str) => str.replace(/<[^<]+?>/g, ''); + +// 添加公共参数并签名数据 +const signFormData = (data) => { + const newData = { + weixin: 1, + basic_v: 0, + f: 'android', + v: APP_VERSION, + time: `${Math.round(new Date().getTime() / 1000)}000`, + ...data + }; + + const keys = Object.keys(newData).filter(key => newData[key] !== '').sort(); + const signData = keys.map(key => `${key}=${newData[key]}`).join('&'); + const sign = crypto.createHash('md5').update(`${signData}&key=${SIGN_KEY}`).digest('hex').toUpperCase(); + + return { + ...newData, + sign + }; +}; + +// 公共请求函数 +const requestApi = async (url, inputOptions = {}) => { + const options = { ...inputOptions }; + + if (!options.method) { + options.method = 'get'; + } + + if (!options.data) { + options.data = {}; + } + + Object.keys(options.data).forEach(key => options.data[key] === undefined && delete options.data[key]); + + if (options.sign !== false) { + options.data = signFormData(options.data); + } + + const gotOptions = { + method: options.method.toUpperCase(), + headers: options.headers, + }; + + if (options.method === 'get') { + gotOptions.searchParams = options.data; + } + else { + gotOptions.form = options.data; + } + + return got(url, gotOptions).then((response) => { + const data = options.parseJSON === false ? response.body : parseJSON(response.body); + + return { + isSuccess: options.parseJSON === false ? true : (data.error_code == '0'), + response: options.parseJSON === false ? response.body : JSON.stringify(data), + data + }; + }).catch((error) => { + return { + isSuccess: false, + response: error, + data: error + }; + }) +}; + +const updateCookie = (cookie, name, value) => { + const re = new RegExp(`(^|;)${name}=[^;]+;`, 'ig'); + + return cookie.replace(re, `$1${name}=${encodeURIComponent(value)};`); +}; + +// ------------------------------------ + +class SmzdmBot { + constructor(cookie) { + this.cookie = cookie; + + const match = this.cookie.match(/sess=(.*?);/); + this.token = match ? match[1] : ''; + + // 处理 cookie + this.androidCookie = this.cookie.replace('iphone', 'android').replace('iPhone', 'Android'); + this.androidCookie = updateCookie(this.androidCookie, 'smzdm_version', APP_VERSION); + this.androidCookie = updateCookie(this.androidCookie, 'device_smzdm_version', APP_VERSION); + this.androidCookie = updateCookie(this.androidCookie, 'v', APP_VERSION); + this.androidCookie = updateCookie(this.androidCookie, 'device_smzdm_version_code', APP_VERSION_REV); + this.androidCookie = updateCookie(this.androidCookie, 'device_system_version', '10.0'); + this.androidCookie = updateCookie(this.androidCookie, 'apk_partner_name', 'smzdm_download'); + this.androidCookie = updateCookie(this.androidCookie, 'partner_name', 'smzdm_download'); + this.androidCookie = updateCookie(this.androidCookie, 'device_type', 'Android'); + this.androidCookie = updateCookie(this.androidCookie, 'device_smzdm', 'android'); + this.androidCookie = updateCookie(this.androidCookie, 'device_name', 'Android'); + } + + getHeaders() { + return { + Accept: '*/*', + 'Accept-Language': 'zh-Hans-CN;q=1', + 'Accept-Encoding': 'gzip', + 'request_key': randomStr(18), + 'User-Agent': DEFAULT_USER_AGENT, + Cookie: this.androidCookie + }; + } + + getHeadersForWeb() { + return { + Accept: '*/*', + 'Accept-Language': 'zh-CN,zh-Hans;q=0.9', + 'Accept-Encoding': 'gzip', + 'User-Agent': DEFAULT_WEB_USER_AGENT, + Cookie: this.androidCookie + }; + } +} + +module.exports = { + SmzdmBot, + requestApi, + removeTags +}; diff --git a/smzdm_task.js b/smzdm_task.js index 977cad3..f1202b7 100644 --- a/smzdm_task.js +++ b/smzdm_task.js @@ -5,151 +5,17 @@ cron: 20 14 * * * */ -const crypto = require('crypto'); const Env = require('./env'); +const { SmzdmBot, requestApi, removeTags } = require('./bot'); const notify = require('./sendNotify'); // ------------------------------------ -const APP_VERSION = '10.4.26'; -const APP_VERSION_REV = '866'; - -const DEFAULT_USER_AGENT = `smzdm_android_V${APP_VERSION} rv:${APP_VERSION_REV} (Redmi Note 3;Android10.0;zh)smzdmapp`; -const DEFAULT_WEB_USER_AGENT = `Mozilla/5.0 (Linux; Android 10.0; Redmi Build/Redmi Note 3; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/95.0.4638.74 Mobile Safari/537.36{ smzdm_android_V${APP_VERSION} rv:${APP_VERSION_REV} (Redmi;Android10.0;zh) jsbv_1.0.0 webv_2.0 smzdmapp }`; - -const SIGN_KEY = 'apr1$AwP!wRRT$gJ/q.X24poeBInlUJC'; - -// ------------------------------------ - const $ = new Env('什么值得买任务'); -const randomStr = (len = 18) => { - const char = '0123456789'; - let str = ''; - - for (let i = 0; i < len; i++) { - str += char.charAt(Math.floor(Math.random() * char.length)); - } - - return str; -}; - -const parseJSON = (str) => { - try { - return JSON.parse(str); - } - catch (e) { - return {}; - } -}; - -const removeTags = (str) => str.replace(/<[^<]+?>/g, ''); - -// 添加公共参数并签名数据 -const signFormData = (data) => { - const newData = { - weixin: 1, - basic_v: 0, - f: 'android', - v: APP_VERSION, - time: `${Math.round(new Date().getTime() / 1000)}000`, - ...data - }; - - const keys = Object.keys(newData).filter(key => newData[key] !== '').sort(); - const signData = keys.map(key => `${key}=${newData[key]}`).join('&'); - const sign = crypto.createHash('md5').update(`${signData}&key=${SIGN_KEY}`).digest('hex').toUpperCase(); - - return { - ...newData, - sign - }; -}; - -// 公共请求函数 -const requestApi = async (url, inputOptions = {}) => { - const options = { ...inputOptions }; - - if (!options.method) { - options.method = 'get'; - } - - if (!options.data) { - options.data = {}; - } - - Object.keys(options.data).forEach(key => options.data[key] === undefined && delete options.data[key]); - - if (options.sign !== false) { - options.data = signFormData(options.data); - } - - return $.http[options.method]({ - url, - headers: options.headers, - form: options.method === 'post' ? options.data : undefined, - searchParams: options.method === 'get' ? options.data : undefined, - }).then((response) => { - const data = options.parseJSON === false ? response.body : parseJSON(response.body); - - return { - isSuccess: options.parseJSON === false ? true : (data.error_code == '0'), - response: options.parseJSON === false ? response.body : JSON.stringify(data), - data - }; - }).catch((error) => { - return { - isSuccess: false, - response: error, - data: error - }; - }) -}; - -const updateCookie = (cookie, name, value) => { - const re = new RegExp(`(^|;)${name}=[^;]+;`, 'ig'); - - return cookie.replace(re, `$1${name}=${encodeURIComponent(value)};`); -}; - -// ------------------------------------ - -class SmzdmBot { +class SmzdmTaskBot extends SmzdmBot { constructor(cookie) { - this.cookie = cookie; - - const match = this.cookie.match(/sess=(.*?);/); - this.token = match ? match[1] : ''; - - // 处理 cookie - this.androidCookie = this.cookie.replace('iphone', 'android').replace('iPhone', 'Android'); - this.androidCookie = updateCookie(this.androidCookie, 'smzdm_version', APP_VERSION); - this.androidCookie = updateCookie(this.androidCookie, 'device_smzdm_version', APP_VERSION); - this.androidCookie = updateCookie(this.androidCookie, 'v', APP_VERSION); - this.androidCookie = updateCookie(this.androidCookie, 'device_smzdm_version_code', APP_VERSION_REV); - this.androidCookie = updateCookie(this.androidCookie, 'device_system_version', '10.0'); - this.androidCookie = updateCookie(this.androidCookie, 'apk_partner_name', 'smzdm_download'); - this.androidCookie = updateCookie(this.androidCookie, 'partner_name', 'smzdm_download'); - this.androidCookie = updateCookie(this.androidCookie, 'device_type', 'Android'); - this.androidCookie = updateCookie(this.androidCookie, 'device_smzdm', 'android'); - this.androidCookie = updateCookie(this.androidCookie, 'device_name', 'Android'); - } - - getHeaders(isWeb = false) { - return isWeb ? { - Accept: '*/*', - 'Accept-Language': 'zh-CN,zh-Hans;q=0.9', - 'Accept-Encoding': 'gzip', - 'User-Agent': DEFAULT_WEB_USER_AGENT, - Cookie: this.androidCookie - } : { - Accept: '*/*', - 'Accept-Language': 'zh-Hans-CN;q=1', - 'Accept-Encoding': 'gzip', - 'request_key': randomStr(18), - 'User-Agent': DEFAULT_USER_AGENT, - Cookie: this.androidCookie - }; + super(cookie); } // 主函数 @@ -560,7 +426,7 @@ class SmzdmBot { method: 'post', sign: false, headers: { - ...this.getHeaders(true), + ...this.getHeadersForWeb(), Origin: 'https://zhiyou.m.smzdm.com', Referer: `https://zhiyou.m.smzdm.com/user/crowd/p/${id}/` }, @@ -592,7 +458,7 @@ class SmzdmBot { const { isSuccess, data, response } = await requestApi('https://zhiyou.smzdm.com/user/crowd/', { sign: false, parseJSON: false, - headers: this.getHeaders(true) + headers: this.getHeadersForWeb() }); if (isSuccess) { @@ -738,7 +604,7 @@ class SmzdmBot { const { isSuccess, data, response } = await requestApi('https://post.smzdm.com/json_more/?tab_id=tuijian&filterUrl=tuijian', { sign: false, headers: { - ...this.getHeaders(true), + ...this.getHeadersForWeb(), Referer: 'https://post.smzdm.com/' } }); @@ -872,7 +738,7 @@ class SmzdmBot { $.log(sep); - const bot = new SmzdmBot(cookie); + const bot = new SmzdmTaskBot(cookie); const msg = await bot.run(); $.log(msg + '\n');