1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005 |
- function MagicJS(scriptName = "MagicJS", logLevel = "INFO") {
- const MagicEnvironment = () => {
- const isLoon = typeof $loon !== "undefined";
- const isQuanX = typeof $task !== "undefined";
- const isNode = typeof module !== "undefined";
- const isSurge = typeof $httpClient !== "undefined" && !isLoon;
- const isStorm = typeof $storm !== "undefined";
- const isStash = typeof $environment !== "undefined" && typeof $environment["stash-build"] !== "undefined";
- const isSurgeLike = isSurge || isLoon || isStorm || isStash;
- const isScriptable = typeof importModule !== "undefined";
- return {
- isLoon: isLoon,
- isQuanX: isQuanX,
- isNode: isNode,
- isSurge: isSurge,
- isStorm: isStorm,
- isStash: isStash,
- isSurgeLike: isSurgeLike,
- isScriptable: isScriptable,
- get name() {
- if (isLoon) {
- return "Loon";
- } else if (isQuanX) {
- return "QuantumultX";
- } else if (isNode) {
- return "NodeJS";
- } else if (isSurge) {
- return "Surge";
- } else if (isScriptable) {
- return "Scriptable";
- } else {
- return "unknown";
- }
- },
- get build() {
- if (isSurge) {
- return $environment["surge-build"];
- } else if (isStash) {
- return $environment["stash-build"];
- } else if (isStorm) {
- return $storm.buildVersion;
- }
- },
- get language() {
- if (isSurge || isStash) {
- return $environment["language"];
- }
- },
- get version() {
- if (isSurge) {
- return $environment["surge-version"];
- } else if (isStash) {
- return $environment["stash-version"];
- } else if (isStorm) {
- return $storm.appVersion;
- } else if (isNode) {
- return process.version;
- }
- },
- get system() {
- if (isSurge) {
- return $environment["system"];
- } else if (isNode) {
- return process.platform;
- }
- },
- get systemVersion() {
- if (isStorm) {
- return $storm.systemVersion;
- }
- },
- get deviceName() {
- if (isStorm) {
- return $storm.deviceName;
- }
- }
- };
- };
- const MagicLogger = (scriptName, logLevel = "INFO") => {
- let _level = logLevel;
- let logSeparator = '\n';
- const logLevels = {
- SNIFFER: 6,
- DEBUG: 5,
- INFO: 4,
- NOTIFY: 3,
- WARNING: 2,
- ERROR: 1,
- CRITICAL: 0,
- NONE: -1
- };
- const logEmoji = {
- SNIFFER: "",
- DEBUG: "",
- INFO: "",
- NOTIFY: "",
- WARNING: "❗ ",
- ERROR: "❌ ",
- CRITICAL: "❌ ",
- NONE: ""
- };
- const _log = (msg, level = "INFO") => {
- // let level = "INFO";
- // if (logs.length > 1) {
- // let lastParam = logs[logs.length-1];
- // let leveArr = ["SNIFFER","DEBUG","INFO","NOTIFY","WARNING","ERROR","RETRY"];
- // if(typeof(lastParam) == 'string' && leveArr.indexOf(lastParam) > 0){
- // level = lastParam;
- // logs.length = logs.length-1;
- // }
- // }
- // let msg = logs.join('\n');
- if (!(logLevels[_level] < logLevels[level.toUpperCase()])) console.log(`██[${scriptName}][${level}]` + '' + `${logEmoji[level.toUpperCase()]}${msg}` + '\n' + ``);
- };
- const setLevel = logLevel => {
- _level = logLevel;
- };
- return {
- getLevel: () => {
- return _level;
- },
- setLevel: setLevel,
- sniffer: (...logs) => {
- let msg = logs.join(logSeparator);
- _log(msg, "SNIFFER");
- },
- log: (...logs) => {
- let msg = logs.join(logSeparator);
- console.log(`██[${scriptName}]` + '' + `${msg}` + '\n' + ``);
- },
- debug: (...logs) => {
- let msg = logs.join(logSeparator);
- _log(msg, "DEBUG");
- },
- info: (...logs) => {
- let msg = logs.join(logSeparator);
- _log(msg, "INFO");
- },
- notify: (...logs) => {
- let msg = logs.join(logSeparator);
- _log(msg, "NOTIFY");
- },
- warning: (...logs) => {
- let msg = logs.join(logSeparator);
- _log(msg, "WARNING");
- },
- error: (...logs) => {
- let msg = logs.join(logSeparator);
- _log(msg, "ERROR");
- },
- retry: (...logs) => {
- let msg = logs.join(logSeparator);
- _log(msg, "RETRY");
- }
- };
- };
- return new class {
- constructor(scriptName, logLevel) {
- this._startTime = Date.now();
- this.version = "3.0.0";
- this.scriptName = scriptName;
- this.env = MagicEnvironment();
- this.logger = MagicLogger(scriptName, logLevel);
- this.http = typeof MagicHttp === "function" ? MagicHttp(this.env, this.logger) : undefined;
- this.data = typeof MagicData === "function" ? MagicData(this.env, this.logger) : undefined;
- this.notification = typeof MagicNotification === "function" ? MagicNotification(this.scriptName, this.env, this.logger, this.http) : undefined;
- this.utils = typeof MagicUtils === "function" ? MagicUtils(this.env, this.logger) : undefined;
- this.qinglong = typeof MagicQingLong === "function" ? MagicQingLong(this.env, this.data, this.logger) : undefined;
- if (typeof this.data !== "undefined") {
- let magicLoglevel = this.data.read("magic_loglevel");
- const barkUrl = this.data.read("magic_bark_url");
- if (magicLoglevel) {
- this.logger.setLevel(magicLoglevel.toUpperCase());
- }
- if (barkUrl) {
- this.notification.setBark(barkUrl);
- }
- }
- this.logger.info(`${scriptName}, 开始执行!`);
- // this.checkRecordRequestBody();
- }
- get isRequest() {
- return typeof $request !== "undefined";
- }
- get isStrictRequest() {
- return typeof $request !== "undefined" && typeof $response === "undefined";
- }
- get isResponse() {
- return typeof $response !== "undefined";
- }
- get isDebug() {
- return this.logger.level === "DEBUG";
- }
- get request() {
- return typeof $request !== "undefined" ? $request : undefined;
- }
- get response() {
- if (typeof $response !== "undefined") {
- if ($response.hasOwnProperty("status")) $response["statusCode"] = $response["status"];
- if ($response.hasOwnProperty("statusCode")) $response["status"] = $response["statusCode"];
- return $response;
- } else {
- return undefined;
- }
- }
- log(...logs) {
- this.logger.log(logs);
- }
- toStr(data, defVal = null) {
- try {
- return JSON.stringify(data);
- } catch {
- return defVal;
- }
- }
- toObj(str, defVal = null) {
- try {
- return JSON.parse(str);
- } catch {
- return defVal;
- }
- }
- checkRecordRequestBody() {
- if (!this.isRequest) {
- return;
- }
- const reqBody = $request.body;
- if (!reqBody) {
- return;
- }
- const env = this.env;
- const path = $request.path;
- let cacheKey = this.scriptName + "#" + path.replace("/", "_");
- cacheKey = cacheKey.replace("?", "#");
- if (env.isQuanX) $prefs.setValueForKey(reqBody, cacheKey);
- if (env.isLoon || env.isSurge) $persistentStore.write(reqBody, cacheKey);
- if (env.isNode) {
- const node_fs = require("fs");
- node_fs.writeFileSync(
- `${cacheKey}.json`,
- reqBody,
- {
- flag: "w"
- },
- (err) => console.log(err)
- );
- }
- }
- getRequestBody() {
- const env = this.env;
- const path = $request.path;
- let cacheKey = this.scriptName + "#" + path.replace("/", "_");
- cacheKey = cacheKey.replace("?", "#");
- if (env.isSurge || env.isLoon) {
- return $persistentStore.read(cacheKey);
- }
- if (env.isQuanX) {
- return $prefs.valueForKey(cacheKey);
- }
- if (env.isNode) {
- const fpath = `${cacheKey}.json`;
- const node_fs = require("fs");
- if (!node_fs.existsSync(fpath)) {
- return JSON.parse(
- node_fs.readFileSync(fpath)
- );
- }
- }
- }
- getResponseBody() {
- if ($response) {
- return $response.body;
- }
- }
- // 解析cookie字符串的函数
- parseCookies(cookieString, decodeURI = false) {
- let dict = {};
- if (decodeURI) {
- cookieString && cookieString.split(';').forEach(function (cookie) {
- let parts = cookie.split('=');
- dict[parts.shift().trim()] = decodeURIComponent(parts.join('='));
- });
- } else {
- cookieString && cookieString.split(';').forEach(function (cookie) {
- let parts = cookie.split('=');
- dict[parts.shift().trim()] = parts.join('=');
- });
- }
- return dict;
- }
- // 系列化为cookie字符串
- serializeCookies(cookieData, encodeURI = false) {
- const parts = [];
- if (encodeURI) {
- for (let key in cookieData) {
- let value = cookieData[key];
- let cookiePart = `${key}=${encodeURIComponent(value)}`;
- parts.push(cookiePart);
- }
- } else {
- for (let key in cookieData) {
- let value = cookieData[key];
- let cookiePart = `${key}=${value}`;
- parts.push(cookiePart);
- }
- }
- return parts.join('; ');
- }
- parseSetCookies(setCookieStr) {
- let tmpArr = setCookieStr.split(/,\s*/).map(cookieStr => {
- const cookieParts = cookieStr.trim().split(/;\s*(?=[^=]+=[^;]*)/); // 使用正则表达式分割
- const nameValue = cookieParts[0].split('=').map(part => part.trim());
- const cookieObject = { name: nameValue[0], value: nameValue[1] };
- // 解析其他属性
- cookieParts.slice(1).forEach(attr => {
- const [key, val] = attr.split('=').map(part => part.trim());
- cookieObject[key] = val || true; // 如果没有值,则设置为 true
- });
- return cookieObject;
- });
- let retData = [];
- let i = 0;
- while (i < tmpArr.length) {
- const curItem = tmpArr[i];
- retData.push(curItem);
- if (curItem.Expires) {
- const nextItem = tmpArr[i + 1];
- if (nextItem) {
- curItem.Expires = `${curItem.Expires},${nextItem.name}`;
- }
- i += 2;
- } else {
- i += 1;
- }
- }
- return retData;
- }
- objToQueryStr(obj, encode) {
- let str = '';
- for (const key in obj) {
- let value = obj[key];
- if (value != null && value !== '') {
- if (typeof value === 'object') {
- value = JSON.stringify(value);
- } else if (encode) {
- value = encodeURIComponent(value);
- }
- str += `${key}=${value}&`;
- }
- }
- str = str.substring(0, str.length - 1);
- return str;
- }
- parseQueryStr(str) {
- let obj = {};
- if (str.indexOf("?") > -1) {
- str = str.split("?")[1];
- }
- let arr = str.split("&");
- for (let i = 0; i < arr.length; i++) {
- let kv = arr[i].split("=");
- obj[kv[0]] = kv[1];
- }
- return obj;
- }
- deepClone(obj, newObj) {
- newObj = newObj || {};
- for (let key in obj) {
- if (typeof obj[key] == 'object') {
- newObj[key] = (obj[key].constructor === Array) ? [] : {};
- this.deepClone(obj[key], newObj[key]);
- } else {
- newObj[key] = obj[key];
- }
- }
- return newObj;
- }
- /**
- * formatDate y:年 M:月 d:日 q:季 H:时 m:分 s:秒 S:毫秒
- */
- formatDate(date, format) {
- let o = {
- 'M+': date.getMonth() + 1,
- 'd+': date.getDate(),
- 'H+': date.getHours(),
- 'm+': date.getMinutes(),
- 's+': date.getSeconds(),
- 'q+': Math.floor((date.getMonth() + 3) / 3),
- 'S': date.getMilliseconds()
- }
- if (/(y+)/.test(format)) format = format.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
- for (let k in o)
- if (new RegExp('(' + k + ')').test(format))
- format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length))
- return format
- }
- /**
- * parseDate 字符串格式,默认'yyyy-MM-dd',支持如下:y、M、d、H、m、s、S,不支持w和q
- */
- parseDate(str, format) {
- format = format || 'yyyy-MM-dd';
- let obj = { y: 0, M: 1, d: 0, H: 0, h: 0, m: 0, s: 0, S: 0 };
- format.replace(/([^yMdHmsS]*?)(([yMdHmsS])\3*)([^yMdHmsS]*?)/g, function (m, $1, $2, $3, $4, idx, old) {
- str = str.replace(new RegExp($1 + '(\\d{' + $2.length + '})' + $4), function (_m, _$1) {
- obj[$3] = parseInt(_$1);
- return '';
- });
- return '';
- });
- obj.M--; // 月份是从0开始的,所以要减去1
- let date = new Date(obj.y, obj.M, obj.d, obj.H, obj.m, obj.s);
- if (obj.S !== 0) date.setMilliseconds(obj.S); // 如果设置了毫秒
- return date;
- }
- getBaseDoneHeaders(mixHeaders = {}) {
- return Object.assign(
- {
- 'Access-Control-Allow-Origin': '*',
- 'Access-Control-Allow-Methods': 'POST,GET,OPTIONS,PUT,DELETE',
- 'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept'
- },
- mixHeaders
- )
- }
- getHtmlDoneHeaders() {
- return this.getBaseDoneHeaders({
- 'Content-Type': 'text/html;charset=UTF-8'
- })
- }
- getJsonDoneHeaders() {
- return this.getBaseDoneHeaders({
- 'Content-Type': 'text/json; charset=utf-8',
- 'Connection': 'keep-alive'
- })
- }
- /**
- * 推送微信消息
- * 管理后台 https://wxpusher.zjiecode.com/admin/
- * 通用助手 AT_7wDWqSoT8xpJCQqJtHpshKhw7kXc0XCW
- * 光予助手 AT_rTc93GQYIdMU8XLRnoJaSea8WkfhSzhX
- * i茅台助手 AT_6b8KjFF3bYqcr7Cv7woUUES7KadNFbvR
- * 个人uid UID_6P4B00X6Zv8U2oKC0I2R09emxtqq
- */
- doWxpusherSend(data) {
- // let data = {
- // appToken: "AT_rTc93GQYIdMU8XLRnoJaSea8WkfhSzhX",
- // content: content,// 这是主体内容
- // summary: summary,// 该参数可选,默认为 msg 的前10个字符
- // contentType: 1,
- // topicIds: [],
- // uids: [
- // "UID_6P4B00X6Zv8U2oKC0I2R09emxtqq"
- // ],
- // url: "",
- // verifyPay: false
- // };
- // if (url) {
- // data.url = url;
- // }
- const headers = this.getJsonDoneHeaders();
- headers.Host = 'wxpusher.zjiecode.com';
- headers['Content-Type'] = 'application/json;charset=UTF-8';
- let options = {
- url: 'https://wxpusher.zjiecode.com/api/send/message',
- headers: headers,
- body: JSON.stringify(data),
- };
- return this.http.post(options);
- }
- fastWxpusherSend(content, summary = "", url = "") {
- let data = {
- appToken: "AT_7wDWqSoT8xpJCQqJtHpshKhw7kXc0XCW",
- content: content,// 这是主体内容
- summary: summary,// 该参数可选,默认为 msg 的前10个字符
- contentType: 1,//内容类型 1表示文字 2表示html(只发送body标签内部的数据即可,不包括body标签,推荐使用这种) 3表示markdown
- // topicIds: [32852],
- topicIds: [],
- uids: [
- "UID_6P4B00X6Zv8U2oKC0I2R09emxtqq"
- ],
- url: url,
- verifyPay: false,
- verifyPayType: 0,
- };
- return this.doWxpusherSend(data);
- }
- isEmpty(obj) {
- return typeof obj == "undefined" || obj == null || obj == "" || obj == "null" || obj == "undefined" || obj.length === 0
- }
- base64Encode(str) {
- let base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- let out, i, len;
- let c1, c2, c3;
- len = str.length;
- i = 0;
- out = "";
- while (i < len) {
- c1 = str.charCodeAt(i++) & 0xff;
- if (i == len) {
- out += base64EncodeChars.charAt(c1 >> 2);
- out += base64EncodeChars.charAt((c1 & 0x3) << 4);
- out += "==";
- break;
- }
- c2 = str.charCodeAt(i++);
- if (i == len) {
- out += base64EncodeChars.charAt(c1 >> 2);
- out += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
- out += base64EncodeChars.charAt((c2 & 0xF) << 2);
- out += "=";
- break;
- }
- c3 = str.charCodeAt(i++);
- out += base64EncodeChars.charAt(c1 >> 2);
- out += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
- out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
- out += base64EncodeChars.charAt(c3 & 0x3F);
- }
- return out;
- }
- base64Decode(input) {
- const base64_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
- // 确保输入是一个正确的Base64编码字符串
- if (/([^\s]+[^0-9a-zA-Z\+\/\=]|[^0-9a-zA-Z\+\/\=]\s+)/.test(input)) {
- throw new Error('Invalid base64 input');
- }
- let str = input.replace(/\s/g, '');
- let output = '';
- let chr1, chr2, chr3;
- let enc1, enc2, enc3, enc4;
- let i = 0;
- while (i < str.length) {
- enc1 = base64_chars.indexOf(str.charAt(i++));
- enc2 = base64_chars.indexOf(str.charAt(i++));
- enc3 = base64_chars.indexOf(str.charAt(i++));
- enc4 = base64_chars.indexOf(str.charAt(i++));
- chr1 = (enc1 << 2) | (enc2 >> 4);
- chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
- chr3 = ((enc3 & 3) << 6) | enc4;
- output = output + String.fromCharCode(chr1);
- if (enc3 !== 64) {
- output = output + String.fromCharCode(chr2);
- }
- if (enc4 !== 64) {
- output = output + String.fromCharCode(chr3);
- }
- }
- output = this.utf8Decode(output);
- return output;
- }
- utf8Decode(str_data) {
- let tmp_arr = [],
- i = 0,
- c1 = 0,
- seqlen = 0;
- str_data = str_data.replace(/\r\n/g, "\n");
- while (i < str_data.length) {
- c1 = str_data.charCodeAt(i) & 0xFF;
- seqlen = 0;
- // Single byte sequence (0xxxxxxx)
- if (c1 <= 0xBF) {
- c1 = (c1 & 0x7F);
- seqlen = 1;
- } else if (c1 <= 0xDF) {
- c1 = (c1 & 0x1F);
- seqlen = 2;
- } else if (c1 <= 0xEF) {
- c1 = (c1 & 0x0F);
- seqlen = 3;
- } else {
- c1 = (c1 & 0x07);
- seqlen = 4;
- }
- for (let ai = 1; ai < seqlen; ++ai) {
- c1 = ((c1 << 0x06) | (str_data.charCodeAt(ai + i) & 0x3F));
- }
- if (seqlen === 4) {
- c1 -= 0x10000;
- tmp_arr.push(String.fromCharCode(0xD800 | ((c1 >> 10) & 0x3FF)));
- tmp_arr.push(String.fromCharCode(0xDC00 | (c1 & 0x3FF)));
- } else {
- tmp_arr.push(String.fromCharCode(c1));
- }
- i += seqlen;
- }
- return tmp_arr.join("");
- }
- parseJwt(token) {
- try {
- const segments = token.split('.');
- const base64HeaderUrl = segments[0];
- const base64Header = base64HeaderUrl.replace(/-/g, '+').replace(/_/g, '/');
- const jsonStrHeader = this.base64Decode(base64Header).replace(/\0/g, '');
- const headerData = JSON.parse(jsonStrHeader);
- const base64PayloadUrl = segments[1];
- const base64Payload = base64PayloadUrl.replace(/-/g, '+').replace(/_/g, '/');
- const jsonStrPayload = this.base64Decode(base64Payload).replace(/\0/g, '');
- const payloadData = JSON.parse(jsonStrPayload);
- return {
- header: headerData,
- payload: payloadData,
- signature: segments[2],
- };
- } catch (e) {
- this.log(e);
- return null;
- }
- }
- costTime() {
- let info = `${this.scriptName}执行完毕!`
- // if (this.isNode && this.isExecComm) {
- // info = `指令【${this.comm[1]}】执行完毕!`
- // }
- this._endTime = new Date().getTime();
- const ms = this._endTime - this._startTime;
- const costTime = ms / 1000;
- this.logger.info(`${info}耗时【${costTime}】秒`);
- }
- done = (value = {}) => {
- // this._endTime = Date.now();
- // let span = (this._endTime - this._startTime) / 1e3;
- // this.logger.info(`SCRIPT COMPLETED: ${span} S.`);
- this.costTime();
- if (typeof $done !== "undefined") {
- $done(value);
- }
- };
- }(scriptName, logLevel);
- }
- function MagicHttp(env, logger) {
- const phoneUA = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.5 Mobile/15E148 Safari/604.1";
- const computerUA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36 Edg/84.0.522.59";
- let axiosInstance;
- if (env.isNode) {
- const axios = require("axios");
- axiosInstance = axios.create();
- }
- class InterceptorManager {
- constructor(isRequest = true) {
- this.handlers = [];
- this.isRequest = isRequest;
- }
- use(fulfilled, rejected, options) {
- if (typeof fulfilled === "function") {
- logger.debug(`Register fulfilled ${fulfilled.name}`);
- }
- if (typeof rejected === "function") {
- logger.debug(`Register rejected ${rejected.name}`);
- }
- this.handlers.push({
- fulfilled: fulfilled,
- rejected: rejected,
- synchronous: options && typeof options.synchronous === "boolean" ? options.synchronous : false,
- runWhen: options ? options.runWhen : null
- });
- return this.handlers.length - 1;
- }
- eject(id) {
- if (this.handlers[id]) {
- this.handlers[id] = null;
- }
- }
- forEach(fn) {
- this.handlers.forEach(element => {
- if (element !== null) {
- fn(element);
- }
- });
- }
- }
- function paramsToQueryString(config) {
- let _config = {
- ...config
- };
- if (!!_config.params) {
- if (!env.isNode) {
- let qs = Object.keys(_config.params).map(key => {
- const encodeKey = encodeURIComponent(key);
- _config.url = _config.url.replace(new RegExp(`${key}=[^&]*`, "ig"), "");
- _config.url = _config.url.replace(new RegExp(`${encodeKey}=[^&]*`, "ig"), "");
- return `${encodeKey}=${encodeURIComponent(_config.params[key])}`;
- }).join("&");
- if (_config.url.indexOf("?") < 0) _config.url += "?";
- if (!/(&|\?)$/g.test(_config.url)) {
- _config.url += "&";
- }
- _config.url += qs;
- delete _config.params;
- logger.debug(`Params to QueryString: ${_config.url}`);
- }
- }
- return _config;
- }
- const mergeConfig = (method, configOrUrl) => {
- let config = typeof configOrUrl === "object" ? {
- headers: {},
- ...configOrUrl
- } : {
- url: configOrUrl,
- headers: {}
- };
- if (!config.method) {
- config["method"] = method;
- }
- config = paramsToQueryString(config);
- if (config["rewrite"] === true) {
- if (env.isSurge) {
- config.headers["X-Surge-Skip-Scripting"] = false;
- delete config["rewrite"];
- } else if (env.isQuanX) {
- config["hints"] = false;
- delete config["rewrite"];
- }
- }
- if (env.isSurgeLike) {
- const contentType = config.headers["content-type"] || config.headers["Content-Type"];
- if (config["method"] !== "GET" && contentType && contentType.indexOf("application/json") >= 0 && config.body instanceof Array) {
- config.body = JSON.stringify(config.body);
- logger.debug(`Convert Array object to String: ${config.body}`);
- }
- } else if (env.isQuanX) {
- if (config.hasOwnProperty("body") && typeof config["body"] !== "string") config["body"] = JSON.stringify(config["body"]);
- config["method"] = method;
- } else if (env.isNode) {
- if (method === "POST" || method === "PUT" || method === "PATCH" || method === "DELETE") {
- config.data = config.data || config.body;
- } else if (method === "GET") {
- config.params = config.params || config.body;
- }
- delete config.body;
- }
- return config;
- };
- const modifyResponse = (resp, config = null) => {
- if (resp) {
- let _resp = {
- ...resp,
- config: resp.config || config,
- status: resp.statusCode || resp.status,
- body: resp.body || resp.data,
- headers: resp.headers || resp.header
- };
- if (typeof _resp.body === "string") {
- try {
- _resp.body = JSON.parse(_resp.body);
- } catch { }
- }
- delete _resp.data;
- return _resp;
- } else {
- return resp;
- }
- };
- const convertHeadersToLowerCase = headers => {
- return Object.keys(headers).reduce((acc, key) => {
- acc[key.toLowerCase()] = headers[key];
- return acc;
- }, {});
- };
- const convertHeadersToCamelCase = headers => {
- return Object.keys(headers).reduce((acc, key) => {
- const newKey = key.split("-").map(word => word[0].toUpperCase() + word.slice(1)).join("-");
- acc[newKey] = headers[key];
- return acc;
- }, {});
- };
- const raiseExceptionByStatusCode = (resp, config = null) => {
- if (!!resp && resp.status >= 400) {
- logger.debug(`Raise exception when status code is ${resp.status}`);
- return {
- name: "RequestException",
- message: `Request failed with status code ${resp.status}`,
- config: config || resp.config,
- response: resp
- };
- }
- };
- const interceptors = {
- request: new InterceptorManager(),
- response: new InterceptorManager(false)
- };
- let requestInterceptorChain = [];
- let responseInterceptorChain = [];
- let synchronousRequestInterceptors = true;
- function interceptConfig(config) {
- config = paramsToQueryString(config);
- logger.debug(`HTTP ${config["method"].toUpperCase()}:` + '\n' + `${JSON.stringify(config)}`);
- return config;
- }
- function interceptResponse(resp) {
- try {
- resp = !!resp ? modifyResponse(resp) : resp;
- logger.sniffer(`HTTP ${resp.config["method"].toUpperCase()}:` + '\n' + `${JSON.stringify(resp.config)}` + '\n' + `STATUS CODE:` + '\n' + `${resp.status}` + '\n' + `RESPONSE:` + '\n' + `${typeof resp.body === "object" ? JSON.stringify(resp.body) : resp.body}`);
- const err = raiseExceptionByStatusCode(resp);
- if (!!err) {
- return Promise.reject(err);
- }
- return resp;
- } catch (err) {
- logger.error(err);
- return resp;
- }
- }
- const registerInterceptors = config => {
- try {
- requestInterceptorChain = [];
- responseInterceptorChain = [];
- interceptors.request.forEach(interceptor => {
- if (typeof interceptor.runWhen === "function" && interceptor.runWhen(config) === false) {
- return;
- }
- synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;
- requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
- });
- interceptors.response.forEach(interceptor => {
- responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
- });
- } catch (err) {
- logger.error(`Failed to register interceptors: ${err}.`);
- }
- };
- const request = (method, config) => {
- let dispatchRequest;
- const _method = method.toUpperCase();
- config = mergeConfig(_method, config);
- if (env.isNode) {
- dispatchRequest = axiosInstance;
- } else {
- if (env.isSurgeLike) {
- dispatchRequest = config => {
- return new Promise((resolve, reject) => {
- $httpClient[method.toLowerCase()](config, (err, resp, body) => {
- if (err) {
- let newErr = {
- name: err.name || err,
- message: err.message || err,
- stack: err.stack || err,
- config: config,
- response: modifyResponse(resp)
- };
- reject(newErr);
- } else {
- resp.config = config;
- resp.body = body;
- resolve(resp);
- }
- });
- });
- };
- } else {
- dispatchRequest = config => {
- return new Promise((resolve, reject) => {
- $task.fetch(config).then(resp => {
- resp = modifyResponse(resp, config);
- const err = raiseExceptionByStatusCode(resp, config);
- if (err) {
- return Promise.reject(err);
- }
- resolve(resp);
- }).catch(err => {
- let newErr = {
- name: err.message || err.error,
- message: err.message || err.error,
- stack: err.error,
- config: config,
- response: !!err.response ? modifyResponse(err.response) : null
- };
- reject(newErr);
- });
- });
- };
- }
- }
- let promise;
- registerInterceptors(config);
- const defaultRequestInterceptors = [interceptConfig, undefined];
- const defaultResponseInterceptors = [interceptResponse, undefined];
- if (!synchronousRequestInterceptors) {
- logger.debug("Interceptors are executed in asynchronous mode");
- let chain = [dispatchRequest, undefined];
- Array.prototype.unshift.apply(chain, defaultRequestInterceptors);
- Array.prototype.unshift.apply(chain, requestInterceptorChain);
- chain = chain.concat(defaultResponseInterceptors);
- chain = chain.concat(responseInterceptorChain);
- promise = Promise.resolve(config);
- while (chain.length) {
- try {
- let onFulfilled = chain.shift();
- let onRejected = chain.shift();
- if (!env.isNode && config["timeout"] && onFulfilled === dispatchRequest) {
- onFulfilled = requestTimeout;
- }
- if (typeof onFulfilled === "function") {
- logger.debug(`Executing request fulfilled ${onFulfilled.name}`);
- }
- if (typeof onRejected === "function") {
- logger.debug(`Executing request rejected ${onRejected.name}`);
- }
- promise = promise.then(onFulfilled, onRejected);
- } catch (err) {
- logger.error(`request exception: ${err}`);
- }
- }
- return promise;
- } else {
- logger.debug("Interceptors are executed in synchronous mode");
- Array.prototype.unshift.apply(requestInterceptorChain, defaultRequestInterceptors);
- requestInterceptorChain = requestInterceptorChain.concat([interceptConfig, undefined]);
- while (requestInterceptorChain.length) {
- let onFulfilled = requestInterceptorChain.shift();
- let onRejected = requestInterceptorChain.shift();
- try {
- if (typeof onFulfilled === "function") {
- logger.debug(`Executing request fulfilled ${onFulfilled.name}`);
- }
- config = onFulfilled(config);
- } catch (error) {
- if (typeof onRejected === "function") {
- logger.debug(`Executing request rejected ${onRejected.name}`);
- }
- onRejected(error);
- break;
- }
- }
- try {
- if (!env.isNode && config["timeout"]) {
- promise = requestTimeout(config);
- } else {
- promise = dispatchRequest(config);
- }
- } catch (err) {
- return Promise.reject(err);
- }
- Array.prototype.unshift.apply(responseInterceptorChain, defaultResponseInterceptors);
- while (responseInterceptorChain.length) {
- promise = promise.then(responseInterceptorChain.shift(), responseInterceptorChain.shift());
- }
- return promise;
- }
- function requestTimeout(config) {
- try {
- const timer = new Promise((_, reject) => {
- setTimeout(() => {
- let err = {
- message: `timeout of ${config["timeout"]}ms exceeded.`,
- config: config
- };
- reject(err);
- }, config["timeout"]);
- });
- return Promise.race([dispatchRequest(config), timer]);
- } catch (err) {
- logger.error(`Request Timeout exception: ${err}.`);
- }
- }
- };
- return {
- request: request,
- interceptors: interceptors,
- convertHeadersToLowerCase: convertHeadersToLowerCase,
- convertHeadersToCamelCase: convertHeadersToCamelCase,
- modifyResponse: modifyResponse,
- get: configOrUrl => {
- return request("GET", configOrUrl);
- },
- post: configOrUrl => {
- return request("POST", configOrUrl);
- },
- put: configOrUrl => {
- return request("PUT", configOrUrl);
- },
- patch: configOrUrl => {
- return request("PATCH", configOrUrl);
- },
- delete: configOrUrl => {
- return request("DELETE", configOrUrl);
- },
- head: configOrUrl => {
- return request("HEAD", configOrUrl);
- },
- options: configOrUrl => {
- return request("OPTIONS", configOrUrl);
- }
- };
- }
- function MagicData(env, logger) {
- let node = {
- fs: undefined,
- data: {}
- };
- if (env.isNode) {
- node.fs = require("fs");
- try {
- node.fs.accessSync("./magic.json", node.fs.constants.R_OK | node.fs.constants.W_OK);
- } catch (err) {
- node.fs.writeFileSync("./magic.json", "{}", {
- encoding: "utf8"
- });
- }
- node.data = require("./magic.json");
- }
- const defaultValueComparator = (oldVal, newVal) => {
- if (typeof newVal === "object") {
- return false;
- } else {
- return oldVal === newVal;
- }
- };
- const _typeConvertor = val => {
- if (val === "true") {
- return true;
- } else if (val === "false") {
- return false;
- } else if (typeof val === "undefined") {
- return null;
- } else {
- return val;
- }
- };
- const _valConvertor = (val, default_, session, read_no_session) => {
- if (session) {
- try {
- if (typeof val === "string") val = JSON.parse(val);
- if (val["magic_session"] === true) {
- val = val[session];
- } else {
- val = null;
- }
- } catch {
- val = null;
- }
- }
- if (typeof val === "string" && val !== "null") {
- try {
- val = JSON.parse(val);
- } catch { }
- }
- if (read_no_session === false && !!val && val["magic_session"] === true) {
- val = null;
- }
- if ((val === null || typeof val === "undefined") && default_ !== null && typeof default_ !== "undefined") {
- val = default_;
- }
- val = _typeConvertor(val);
- return val;
- };
- const convertToObject = obj => {
- if (typeof obj === "string") {
- let data = {};
- try {
- data = JSON.parse(obj);
- const type = typeof data;
- if (type !== "object" || data instanceof Array || type === "bool" || data === null) {
- data = {};
- }
- } catch { }
- return data;
- } else if (obj instanceof Array || obj === null || typeof obj === "undefined" || obj !== obj || typeof obj === "boolean") {
- return {};
- } else {
- return obj;
- }
- };
- const readForNode = (key, default_ = null, session = "", read_no_session = false, externalData = null) => {
- let data = externalData || node.data;
- if (!!data && typeof data[key] !== "undefined" && data[key] !== null) {
- val = data[key];
- } else {
- val = !!session ? {} : null;
- }
- val = _valConvertor(val, default_, session, read_no_session);
- return val;
- };
- const read = (key, default_ = null, session = "", read_no_session = false, externalData = null) => {
- let val = "";
- if (externalData || env.isNode) {
- val = readForNode(key, default_, session, read_no_session, externalData);
- } else {
- if (env.isSurgeLike) {
- val = $persistentStore.read(key);
- } else if (env.isQuanX) {
- val = $prefs.valueForKey(key);
- }
- val = _valConvertor(val, default_, session, read_no_session);
- }
- logger.debug(`READ DATA [${key}]${!!session ? `[${session}]` : ""} <${typeof val}>` + '\n' + `${JSON.stringify(val)}`);
- return val;
- };
- const writeForNode = (key, val, session = "", externalData = null) => {
- let data = externalData || node.data;
- data = convertToObject(data);
- if (!!session) {
- let obj = convertToObject(data[key]);
- obj["magic_session"] = true;
- obj[session] = val;
- data[key] = obj;
- } else {
- data[key] = val;
- }
- if (externalData !== null) {
- externalData = data;
- }
- return data;
- };
- const write = (key, val, session = "", externalData = null) => {
- if (typeof val === "undefined" || val !== val) {
- return false;
- }
- if (!env.isNode && (typeof val === "boolean" || typeof val === "number")) {
- val = String(val);
- }
- let data = "";
- if (externalData || env.isNode) {
- data = writeForNode(key, val, session, externalData);
- } else {
- if (!session) {
- data = val;
- } else {
- if (env.isSurgeLike) {
- data = !!$persistentStore.read(key) ? $persistentStore.read(key) : data;
- } else if (env.isQuanX) {
- data = !!$prefs.valueForKey(key) ? $prefs.valueForKey(key) : data;
- }
- data = convertToObject(data);
- data["magic_session"] = true;
- data[session] = val;
- }
- }
- if (!!data && typeof data === "object") {
- data = JSON.stringify(data, null, 4);
- }
- logger.debug(`WRITE DATA [${key}]${session ? `[${session}]` : ""} <${typeof val}>` + '\n' + `${JSON.stringify(val)}`);
- if (!externalData) {
- if (env.isSurgeLike) {
- return $persistentStore.write(data, key);
- } else if (env.isQuanX) {
- return $prefs.setValueForKey(data, key);
- } else if (env.isNode) {
- try {
- node.fs.writeFileSync("./magic.json", data);
- return true;
- } catch (err) {
- logger.error(err);
- return false;
- }
- }
- }
- return true;
- };
- const update = (key, val, session, comparator = defaultValueComparator, externalData = null) => {
- val = _typeConvertor(val);
- const oldValue = read(key, null, session, false, externalData);
- if (comparator(oldValue, val) === true) {
- return false;
- } else {
- const result = write(key, val, session, externalData);
- let newVal = read(key, null, session, false, externalData);
- if (comparator === defaultValueComparator && typeof newVal === "object") {
- return result;
- }
- return comparator(val, newVal);
- }
- };
- const delForNode = (key, session, externalData) => {
- let data = externalData || node.data;
- data = convertToObject(data);
- if (!!session) {
- obj = convertToObject(data[key]);
- delete obj[session];
- data[key] = obj;
- } else {
- delete data[key];
- }
- if (!!externalData) {
- externalData = data;
- }
- return data;
- };
- const del = (key, session = "", externalData = null) => {
- let data = {};
- if (externalData || env.isNode) {
- data = delForNode(key, session, externalData);
- if (!externalData) {
- node.fs.writeFileSync("./magic.json", JSON.stringify(data, null, 4));
- } else {
- externalData = data;
- }
- } else {
- if (!session) {
- if (env.isStorm) {
- return $persistentStore.remove(key);
- } else if (env.isSurgeLike) {
- return $persistentStore.write(null, key);
- } else if (env.isQuanX) {
- return $prefs.removeValueForKey(key);
- }
- } else {
- if (env.isSurgeLike) {
- data = $persistentStore.read(key);
- } else if (env.isQuanX) {
- data = $prefs.valueForKey(key);
- }
- data = convertToObject(data);
- delete data[session];
- const json = JSON.stringify(data, null, 4);
- write(key, json);
- }
- }
- logger.debug(`DELETE KEY [${key}]${!!session ? `[${session}]` : ""}`);
- };
- const allSessionNames = (key, externalData = null) => {
- let _sessions = [];
- let data = read(key, null, null, true, externalData);
- data = convertToObject(data);
- if (data["magic_session"] !== true) {
- _sessions = [];
- } else {
- _sessions = Object.keys(data).filter(key => key !== "magic_session");
- }
- logger.debug(`READ ALL SESSIONS [${key}] <${typeof _sessions}>` + '\n' + `${JSON.stringify(_sessions, null, 4)}`);
- return _sessions;
- };
- const allSessions = (key, externalData = null) => {
- let _sessions = {};
- let data = read(key, null, null, true, externalData);
- data = convertToObject(data);
- if (data["magic_session"] === true) {
- _sessions = {
- ...data
- };
- delete _sessions["magic_session"];
- }
- logger.debug(`READ ALL SESSIONS [${key}] <${typeof _sessions}>` + '\n' + `${JSON.stringify(_sessions, null, 4)}`);
- return _sessions;
- };
- return {
- read: read,
- write: write,
- del: del,
- update: update,
- allSessions: allSessions,
- allSessionNames: allSessionNames,
- defaultValueComparator: defaultValueComparator,
- convertToObject: convertToObject
- };
- }
- function MagicNotification(scriptName, env, logger, http) {
- let _barkUrl = null;
- let _barkKey = null;
- let notifyInfo = []
- const setBark = url => {
- try {
- let _url = url.replace(/\/+$/g, "");
- _barkUrl = `${/^https?:\/\/([^/]*)/.exec(_url)[0]}/push`;
- _barkKey = /\/([^\/]+)\/?$/.exec(_url)[1];
- } catch (ex) {
- logger.error(`Bark url error: ${ex}.`);
- }
- };
- function appendNotifyInfo(info, type) {
- if (type == 1) {
- notifyInfo = info
- } else {
- notifyInfo.push(info)
- }
- }
- function prependNotifyInfo(info) {
- notifyInfo.splice(0, 0, info)
- }
- function msg(subtitle, message, openUrl, mediaUrl) {
- let opts = {};
- if (openUrl) {
- opts["open-url"] = openUrl;
- }
- if (mediaUrl) {
- opts["media-url"] = mediaUrl;
- }
- if (!message || message.length == 0) {
- if (Array.isArray(notifyInfo)) {
- message = notifyInfo.join("\n");
- } else {
- message = notifyInfo;
- }
- }
- if (message && message.length > 0) {
- post(scriptName, "", message, opts);
- }
- }
- function post(title = scriptName, subTitle = "", body = "", opts = "") {
- const _adaptOpts = _opts => {
- try {
- let newOpts = {};
- if (typeof _opts === "string") {
- if (_opts.length > 0) {
- if (env.isLoon) {
- newOpts = {
- openUrl: _opts
- };
- } else if (env.isQuanX) {
- newOpts = {
- "open-url": _opts
- };
- } else if (env.isSurge) {
- newOpts = {
- url: _opts
- };
- }
- }
- } else if (typeof _opts === "object") {
- if (env.isLoon) {
- newOpts["openUrl"] = !!_opts["open-url"] ? _opts["open-url"] : "";
- newOpts["mediaUrl"] = !!_opts["media-url"] ? _opts["media-url"] : "";
- } else if (env.isQuanX) {
- newOpts = !!_opts["open-url"] || !!_opts["media-url"] ? _opts : {};
- } else if (env.isSurge) {
- let openUrl = _opts["open-url"] || _opts["openUrl"];
- newOpts = openUrl ? {
- url: openUrl
- } : {};
- }
- }
- return newOpts;
- } catch (err) {
- logger.error(`通知选项转换失败${err}`);
- }
- return _opts;
- };
- opts = _adaptOpts(opts);
- if (arguments.length === 1) {
- title = scriptName;
- subTitle = "", body = arguments[0];
- }
- logger.notify('\n' + `title:${title}` + '\n' + `subTitle:${subTitle}` + '\n' + `body:${body}` + '\n' + `options:${typeof opts === "object" ? JSON.stringify(opts) : opts}`);
- if (env.isSurge) {
- $notification.post(title, subTitle, body, opts);
- } else if (env.isLoon) {
- if (!!opts) $notification.post(title, subTitle, body, opts); else $notification.post(title, subTitle, body);
- } else if (env.isQuanX) {
- $notify(title, subTitle, body, opts);
- }
- if (_barkUrl && _barkKey) {
- bark(title, subTitle, body);
- }
- }
- function debug(title = scriptName, subTitle = "", body = "", opts = "") {
- if (logger.getLevel() === "DEBUG") {
- if (arguments.length === 1) {
- title = scriptName;
- subTitle = "";
- body = arguments[0];
- }
- this.post(title, subTitle, body, opts);
- }
- }
- function bark(title = scriptName, subTitle = "", body = "", opts = "") {
- if (typeof http === "undefined" || typeof http.post === "undefined") {
- throw "Bark notification needs to import MagicHttp module.";
- }
- let options = {
- url: _barkUrl,
- headers: {
- "content-type": "application/json; charset=utf-8"
- },
- body: {
- title: title,
- body: subTitle ? `${subTitle}` + '\n' + `${body}` : body,
- device_key: _barkKey
- }
- };
- http.post(options).catch(ex => {
- logger.error(`Bark notify error: ${ex}`);
- });
- }
- return {
- post: post,
- debug: debug,
- bark: bark,
- setBark: setBark,
- appendNotifyInfo: appendNotifyInfo,
- prependNotifyInfo: prependNotifyInfo,
- msg: msg,
- };
- }
- function MagicUtils(env, logger) {
- const retry = (fn, retries = 5, interval = 0, callback = null) => {
- return (...args) => {
- return new Promise((resolve, reject) => {
- function _retry(...args) {
- Promise.resolve().then(() => fn.apply(this, args)).then(result => {
- if (typeof callback === "function") {
- Promise.resolve().then(() => callback(result)).then(() => {
- resolve(result);
- }).catch(ex => {
- if (retries >= 1) {
- if (interval > 0) setTimeout(() => _retry.apply(this, args), interval); else _retry.apply(this, args);
- } else {
- reject(ex);
- }
- retries--;
- });
- } else {
- resolve(result);
- }
- }).catch(ex => {
- logger.error(ex);
- if (retries >= 1 && interval > 0) {
- setTimeout(() => _retry.apply(this, args), interval);
- } else if (retries >= 1) {
- _retry.apply(this, args);
- } else {
- reject(ex);
- }
- retries--;
- });
- }
- _retry.apply(this, args);
- });
- };
- };
- const formatTime = (time, fmt = "yyyy-MM-dd hh:mm:ss") => {
- let o = {
- "M+": time.getMonth() + 1,
- "d+": time.getDate(),
- "h+": time.getHours(),
- "m+": time.getMinutes(),
- "s+": time.getSeconds(),
- "q+": Math.floor((time.getMonth() + 3) / 3),
- S: time.getMilliseconds()
- };
- if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (time.getFullYear() + "").substr(4 - RegExp.$1.length));
- for (let k in o) if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length));
- return fmt;
- };
- const now = () => {
- return formatTime(new Date(), "yyyy-MM-dd hh:mm:ss");
- };
- const today = () => {
- return formatTime(new Date(), "yyyy-MM-dd");
- };
- const sleep = time => {
- return new Promise(resolve => setTimeout(resolve, time));
- };
- const assert = (val, msg = null) => {
- if (env.isNode) {
- const _assert = require("assert");
- if (msg) _assert(val, msg); else _assert(val);
- } else {
- if (val !== true) {
- let err = `AssertionError: ${msg || "The expression evaluated to a falsy value."}`;
- logger.error(err);
- }
- }
- };
- return {
- retry: retry,
- formatTime: formatTime,
- now: now,
- today: today,
- sleep: sleep,
- assert: assert
- };
- }
- function MagicQingLong(env, data, logger) {
- let qlUrl = "";
- let qlName = "";
- let qlClient = "";
- let qlSecret = "";
- let qlPwd = "";
- let qlToken = "";
- const magicJsonFileName = "magic.json";
- const timeout = 3e3;
- const http = (() => MagicHttp(env, logger))();
- const init = (url, clientId, clientSecret, username, password) => {
- qlUrl = url;
- qlClient = clientId;
- qlSecret = clientSecret;
- qlName = username;
- qlPwd = password;
- };
- function readQingLongConfig(config) {
- qlUrl = qlUrl || data.read("magic_qlurl");
- qlToken = qlToken || data.read("magic_qltoken");
- logger.debug(`QingLong url: ${qlUrl}` + '\n' + `QingLong token: ${qlToken}`);
- return config;
- }
- function setBaseUrlAndTimeout(config) {
- if (!qlUrl) {
- qlUrl = data.read("magic_qlurl");
- }
- if (config.url.indexOf(qlUrl) < 0) {
- config.url = `${qlUrl}${config.url}`;
- }
- return {
- ...config,
- timeout: timeout
- };
- }
- function setTimestamp(config) {
- config.params = {
- ...config.params,
- t: Date.now()
- };
- return config;
- }
- async function setAuthorization(config) {
- qlToken = qlToken || data.read("magic_qltoken", "");
- if (!qlToken) {
- await getToken();
- }
- config.headers["authorization"] = `Bearer ${qlToken}`;
- return config;
- }
- function switchClientMode(config) {
- qlClient = qlClient || data.read("magic_qlclient");
- if (!!qlClient) {
- config.url = config.url.replace("/api/", "/open/");
- }
- return config;
- }
- async function refreshToken(error) {
- try {
- const message = error.message || error.error || JSON.stringify(error);
- if ((message.indexOf("NSURLErrorDomain") >= 0 && message.indexOf("-1012") >= 0 || !!error.response && error.response.status === 401) && !!error.config && error.config.refreshToken !== true) {
- logger.warning(`QingLong Panel token has expired`);
- logger.info("Refreshing the QingLong Panel token");
- await getToken();
- error.config["refreshToken"] = true;
- logger.info("Call the previous method again");
- return await http.request(error.config.method, error.config);
- } else {
- return Promise.reject(error);
- }
- } catch (ex) {
- return Promise.reject(ex);
- }
- }
- http.interceptors.request.use(setBaseUrlAndTimeout, undefined);
- http.interceptors.request.use(switchClientMode, undefined, {
- runWhen: config => {
- return config.url.indexOf("api/user/login") < 0 && config.url.indexOf("open/auth/token") < 0;
- }
- });
- http.interceptors.request.use(setAuthorization, undefined, {
- runWhen: config => {
- return config.url.indexOf("api/user/login") < 0 && config.url.indexOf("open/auth/token") < 0;
- }
- });
- http.interceptors.request.use(setTimestamp, undefined, {
- runWhen: config => {
- return config.url.indexOf("open/auth/token") < 0;
- }
- });
- http.interceptors.request.use(readQingLongConfig, undefined);
- http.interceptors.response.use(undefined, refreshToken);
- async function getToken() {
- qlClient = qlClient || data.read("magic_qlclient");
- qlSecret = qlSecret || data.read("magic_qlsecrt");
- qlName = qlName || data.read("magic_qlname");
- qlPwd = qlPwd || data.read("magic_qlpwd");
- if (qlUrl && qlClient && qlSecret) {
- logger.info("Get token from QingLong Panel");
- await http.get({
- url: `/open/auth/token`,
- headers: {
- "content-type": "application/json"
- },
- params: {
- client_id: qlClient,
- client_secret: qlSecret
- }
- }).then(resp => {
- if (Object.keys(resp.body).length > 0 && resp.body.data && resp.body.data.token) {
- logger.info("Successfully logged in to QingLong Panel");
- qlToken = resp.body.data.token;
- data.write("magic_qltoken", qlToken);
- } else {
- throw new Error("Get QingLong Panel token failed.");
- }
- }).catch(err => {
- logger.error(`Error logging in to QingLong Panel.` + '\n' + `${err.message || err}`);
- });
- } else if (qlUrl && qlName && qlPwd) {
- await http.post({
- url: `/api/user/login`,
- headers: {
- "content-type": "application/json"
- },
- body: {
- username: qlName,
- password: qlPwd
- }
- }).then(resp => {
- logger.info("Successfully logged in to QingLong Panel");
- qlToken = resp.body.data.token;
- data.write("magic_qltoken", qlToken);
- }).catch(err => {
- logger.error(`Error logging in to QingLong Panel.` + '\n' + `${err.message || err}`);
- });
- }
- return qlToken;
- }
- async function setEnv(name, value, id = null) {
- qlUrl = qlUrl || data.read("magic_qlurl");
- if (id === null) {
- let envIds = await setEnvs([{
- name: name,
- value: value
- }]);
- if (!!envIds && envIds.length === 1) {
- return envIds[0];
- }
- } else {
- await http.put({
- url: `/api/envs`,
- headers: {
- "content-type": "application/json"
- },
- body: {
- name: name,
- value: value,
- id: id
- }
- }).then(resp => {
- if (resp.body.code === 200) {
- logger.debug(`QINGLONG UPDATE ENV ${name} <${typeof value}> (${id})` + '\n' + `${JSON.stringify(value)}`);
- return true;
- } else {
- logger.error(`Error adding environment variable from QingLong Panel.` + '\n' + `${JSON.stringify(resp)}`);
- }
- }).catch(err => {
- logger.error(`Error adding environment variable from QingLong Panel.` + '\n' + `${err.message || err}`);
- return false;
- });
- }
- }
- async function setEnvs(envs) {
- let envIds = [];
- await http.post({
- url: `/api/envs`,
- headers: {
- "content-type": "application/json"
- },
- body: envs
- }).then(resp => {
- if (resp.body.code === 200) {
- resp.body.data.forEach(element => {
- logger.debug(`QINGLONG ADD ENV ${element.name} <${typeof element.value}> (${element.id})` + '\n' + `${JSON.stringify(element)}`);
- envIds.push(element.id);
- });
- } else {
- logger.error(`Error adding environments variable from QingLong Panel.` + '\n' + `${JSON.stringify(resp)}`);
- }
- }).catch(err => {
- logger.error(`Error adding environments variable from QingLong Panel.` + '\n' + `${err.message || err}`);
- });
- return envIds;
- }
- async function delEnvs(ids) {
- return await http.delete({
- url: `/api/envs`,
- headers: {
- accept: "application/json",
- "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
- connection: "keep-alive",
- "content-type": "application/json;charset=UTF-8",
- "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.30"
- },
- body: ids
- }).then(resp => {
- if (resp.body.code === 200) {
- logger.debug(`QINGLONG DELETE ENV IDS: ${ids}`);
- return true;
- } else {
- logger.error(`Error deleting environments variable from QingLong Panel.` + '\n' + `${JSON.stringify(resp)}`);
- return false;
- }
- }).catch(err => {
- logger.error(`Error deleting environments variable from QingLong Panel.` + '\n' + `${err.message || err}`);
- });
- }
- async function getEnvs(name = null, searchValue = "", retired = 0) {
- let envs = [];
- await http.get({
- url: `/api/envs`,
- headers: {
- "content-type": "application/json"
- },
- params: {
- searchValue: searchValue
- }
- }).then(resp => {
- if (resp.body.code === 200) {
- const allEnvs = resp.body.data;
- if (!!name) {
- let _envs = [];
- for (const env of allEnvs) {
- if (env.name === name) {
- envs.push(env);
- }
- }
- envs = _envs;
- }
- envs = allEnvs;
- } else {
- throw new Error(`Error reading environment variable from QingLong Panel.` + '\n' + `${JSON.stringify(resp)}`);
- }
- }).catch(err => {
- throw new Error(`Error reading environments variable from QingLong Panel.` + '\n' + `${err.message || err}`);
- });
- return envs;
- }
- async function getEnv(id) {
- let env = null;
- const allEnvs = await getEnvs();
- for (const _env of allEnvs) {
- if (_env.id === id) {
- env = _env;
- break;
- }
- }
- return env;
- }
- async function disableEnvs(ids) {
- let result = false;
- await http.put({
- url: `/api/envs/disable`,
- headers: {
- accept: "application/json",
- "accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
- connection: "keep-alive",
- "content-type": "application/json;charset=UTF-8",
- "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.30"
- },
- body: ids
- }).then(resp => {
- if (resp.body.code === 200) {
- logger.debug(`QINGLONG DISABLED ENV IDS: ${ids}`);
- result = true;
- } else {
- logger.error(`Error disabling environments variable from QingLong Panel.` + '\n' + `${JSON.stringify(resp)}`);
- }
- }).catch(err => {
- logger.error(`Error disabling environments variable from QingLong Panel.` + '\n' + `${err.message || err}`);
- });
- return result;
- }
- async function enableEnvs(ids) {
- let result = false;
- await http.put({
- url: `/api/envs/enable`,
- headers: {
- accept: "application/json",
- "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
- connection: "keep-alive",
- "content-type": "application/json;charset=UTF-8",
- "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.30"
- },
- body: ids
- }).then(resp => {
- if (resp.body.code === 200) {
- logger.debug(`QINGLONG ENABLED ENV IDS: ${ids}`);
- result = true;
- } else {
- logger.error(`Error enabling environments variable from Qilong panel.` + '\n' + `${JSON.stringify(resp)}`);
- }
- }).catch(err => {
- logger.error(`Error enabling environments variable from Qilong panel.` + '\n' + `${err.message || err}`);
- });
- return result;
- }
- async function addScript(name, path = "", content = "") {
- let result = false;
- await http.post({
- url: `/api/scripts`,
- headers: {
- "content-type": "application/json"
- },
- body: {
- filename: name,
- path: path,
- content: content
- }
- }).then(resp => {
- if (resp.body.code === 200) {
- result = true;
- } else {
- logger.error(`Error reading data from QingLong Panel.` + '\n' + `${JSON.stringify(resp)}`);
- }
- }).catch(err => {
- logger.error(`Error reading data from QingLong Panel.` + '\n' + `${err.message || err}`);
- });
- return result;
- }
- async function getScript(name, path = "") {
- let content = "";
- await http.get({
- url: `/api/scripts/${name}`,
- params: {
- path: path
- }
- }).then(resp => {
- if (resp.body.code === 200) {
- content = resp.body.data;
- } else {
- throw new Error(`Error reading data from QingLong Panel.` + '\n' + `${JSON.stringify(resp)}`);
- }
- }).catch(err => {
- throw new Error(`Error reading data from QingLong Panel.` + '\n' + `${err.message || err}`);
- });
- return content;
- }
- async function editScript(name, path = "", content = "") {
- let result = false;
- await http.put({
- url: `/api/scripts`,
- headers: {
- "content-type": "application/json"
- },
- body: {
- filename: name,
- path: path,
- content: content
- }
- }).then(resp => {
- if (resp.body.code === 200) {
- result = true;
- } else {
- logger.error(`Error reading data from QingLong Panel.` + '\n' + `${JSON.stringify(resp)}`);
- }
- }).catch(err => {
- logger.error(`Error reading data from QingLong Panel.` + '\n' + `${err.message || err}`);
- });
- return result;
- }
- async function delScript(name, path = "") {
- let result = false;
- await http.delete({
- url: `/api/scripts`,
- headers: {
- "content-type": "application/json"
- },
- body: {
- filename: name,
- path: path
- }
- }).then(resp => {
- if (resp.body.code === 200) {
- result = true;
- } else {
- logger.error(`Error reading data from QingLong Panel.` + '\n' + `${JSON.stringify(resp)}`);
- }
- }).catch(err => {
- logger.error(`Error reading data from QingLong Panel.` + '\n' + `${err.message || err}`);
- });
- return result;
- }
- async function write(key, val, session = "") {
- let qlContent = await getScript(magicJsonFileName, "");
- let qlData = data.convertToObject(qlContent);
- let writeResult = data.write(key, val, session, qlData);
- qlContent = JSON.stringify(qlData, null, 4);
- let editResult = await editScript(magicJsonFileName, "", qlContent);
- return editResult && writeResult;
- }
- async function batchWrite(...args) {
- let qlContent = await getScript(magicJsonFileName, "");
- let qlData = data.convertToObject(qlContent);
- for (let arg of args) {
- data.write(arg[0], arg[1], typeof arg[2] !== "undefined" ? arg[2] : "", qlData);
- }
- qlContent = JSON.stringify(qlData, null, 4);
- return await editScript(magicJsonFileName, "", qlContent);
- }
- async function update(key, val, session, comparator = data.defaultValueComparator) {
- let qlContent = await getScript(magicJsonFileName, "");
- let qlData = data.convertToObject(qlContent);
- const updateResult = data.update(key, val, session, comparator, qlData);
- let editScriptResult = false;
- if (updateResult === true) {
- qlContent = JSON.stringify(qlData, null, 4);
- editScriptResult = await editScript(magicJsonFileName, "", qlContent);
- }
- return updateResult && editScriptResult;
- }
- async function batchUpdate(...args) {
- let qlContent = await getScript(magicJsonFileName, "");
- let qlData = data.convertToObject(qlContent);
- for (let arg of args) {
- data.update(arg[0], arg[1], typeof arg[2] !== "undefined" ? arg[2] : "", typeof arg[3] !== "undefined" ? arg["comparator"] : data.defaultValueComparator, qlData);
- }
- qlContent = JSON.stringify(qlData, null, 4);
- return await editScript(magicJsonFileName, "", qlContent);
- }
- async function read(key, val, session = "", read_no_session = false) {
- let qlContent = await getScript(magicJsonFileName, "");
- let qlData = data.convertToObject(qlContent);
- return data.read(key, val, session, read_no_session, qlData);
- }
- async function batchRead(...args) {
- let qlContent = await getScript(magicJsonFileName, "");
- let qlData = data.convertToObject(qlContent);
- let results = [];
- for (let arg of args) {
- const result = data.read(arg[0], arg[1], typeof arg[2] !== "undefined" ? arg[2] : "", typeof arg[3] === "boolean" ? arg[3] : false, qlData);
- results.push(result);
- }
- return results;
- }
- async function del(key, session = "") {
- let qlContent = await getScript(magicJsonFileName, "");
- let qlData = data.convertToObject(qlContent);
- const delResult = data.del(key, session, qlData);
- qlContent = JSON.stringify(qlData, null, 4);
- const editResult = await editScript(magicJsonFileName, "", qlContent);
- return delResult && editResult;
- }
- async function batchDel(...args) {
- let qlContent = await getScript(magicJsonFileName, "");
- let qlData = data.convertToObject(qlContent);
- for (let arg of args) {
- data.del(arg[0], typeof arg[1] !== "undefined" ? arg[1] : "", qlData);
- }
- qlContent = JSON.stringify(qlData, null, 4);
- return await editScript(magicJsonFileName, "", qlContent);
- }
- async function allSessionNames(key) {
- let qlContent = await getScript(magicJsonFileName, "");
- let qlData = data.convertToObject(qlContent);
- return data.allSessionNames(key, qlData);
- }
- async function allSessions(key) {
- let qlContent = await getScript(magicJsonFileName, "");
- let qlData = data.convertToObject(qlContent);
- return data.allSessions(key, qlData);
- }
- return {
- url: qlUrl || data.read("magic_qlurl"),
- init: init,
- getToken: getToken,
- setEnv: setEnv,
- setEnvs: setEnvs,
- getEnv: getEnv,
- getEnvs: getEnvs,
- delEnvs: delEnvs,
- disableEnvs: disableEnvs,
- enableEnvs: enableEnvs,
- addScript: addScript,
- getScript: getScript,
- editScript: editScript,
- delScript: delScript,
- write: write,
- read: read,
- del: del,
- update: update,
- batchWrite: batchWrite,
- batchRead: batchRead,
- batchUpdate: batchUpdate,
- batchDel: batchDel,
- allSessions: allSessions,
- allSessionNames: allSessionNames
- };
- }
|