├── 10010 └── 10010.js ├── 10086 └── 10086.js ├── Apple └── AppleRepair.js ├── Bilibili └── BilibiliMonitor.js ├── Checkin ├── Checkin.js ├── Dler Cloud.js └── checkin_example.json ├── Config.js ├── Config.scriptable ├── CountDown └── CountDown.js ├── Douban └── DoubanMonitor.js ├── Env.js ├── Env.scriptable ├── EnvExample.js ├── EnvExample.scriptable ├── Install Scripts.js ├── NodeQuery └── NodeQuery.js ├── README.md ├── READMEEN.md ├── RRShare └── RRShareMonitor.js ├── RSS └── RSSMonitor.js ├── SNKRS └── SNKRS.js ├── Weibo └── WeiboMonitor.js ├── Zhihu └── ZhihuMonitor.js ├── crypto-js.min.js └── v2ex ├── hot.js └── latest.js /10010/10010.js: -------------------------------------------------------------------------------- 1 | // Variables used by Scriptable. 2 | // These must be at the very top of the file. Do not edit. 3 | // icon-color: cyan; icon-glyph: mobile-alt; 4 | /** 5 | * Author: GideonSenku evilbutcher 6 | * Github: https://github.com/GideonSenku 7 | */ 8 | 9 | const $ = importModule("Env"); 10 | 11 | const prefix = "boxjs.net"; //修改成你用的域名 12 | 13 | const title = '联通5G' 14 | const preview = 'small' // 预览大小 可选:small,medium,large 15 | const spacing = 5 // 间隙大小 16 | // option1 manual 17 | 18 | const tel = `` // 填入你的电话号码 19 | 20 | const VAL_loginheader = `` // 填入来自BoxJs的数据 21 | 22 | // option2 auto getdata from BoxJS 23 | $.KEY_signheader = "chavy_signheader_10010"; 24 | $.KEY_loginheader = "chavy_tokenheader_10010"; 25 | 26 | $.Val_signheader = await getdata($.KEY_signheader); 27 | $.Val_loginheader = await getdata($.KEY_loginheader); 28 | 29 | const res = await getinfo() 30 | await render() 31 | 32 | async function render() { 33 | // create and show widget 34 | if (config.runsInWidget) { 35 | let widget = await createWidget(res) 36 | Script.setWidget(widget) 37 | Script.complete() 38 | } else { 39 | await createWidget(res) 40 | } 41 | } 42 | 43 | async function createWidget(res) { 44 | const signinfo = res; 45 | if (signinfo.code == "Y") { 46 | // 基本信息 47 | const traffic = signinfo.data.dataList[0]; 48 | const flow = signinfo.data.dataList[1]; 49 | const voice = signinfo.data.dataList[2]; 50 | const credit = signinfo.data.dataList[3]; 51 | const back = signinfo.data.dataList[4]; 52 | const money = signinfo.data.dataList[5]; 53 | 54 | 55 | $.traffic = `[${traffic.remainTitle}]${traffic.number}${traffic.unit}` 56 | $.flow = `[${flow.remainTitle}]${flow.number}${flow.unit}` 57 | $.voice = `[${voice.remainTitle}]${voice.number}${voice.unit}` 58 | $.credit = `[${credit.remainTitle}]${credit.number}${credit.unit}` 59 | $.back = `[${back.remainTitle}]${back.number}${back.unit}` 60 | const opts = { 61 | title, 62 | texts: { 63 | traffic: $.traffic, 64 | flow: $.flow, 65 | voice: $.voice, 66 | credit: $.credit, 67 | back: $.back, 68 | updateTime: 'true', 69 | battery: 'true' 70 | }, 71 | preview, 72 | spacing 73 | } 74 | let widget = await $.createWidget(opts); 75 | return widget 76 | 77 | } 78 | } 79 | 80 | async function getinfo() { 81 | const telNum = $.VAL_signheader ? gettel() : tel; 82 | const loginheader = $.Val_loginheader ? $.Val_loginheader : VAL_loginheader; 83 | const url = { 84 | url: `https://m.client.10010.com/mobileService/home/queryUserInfoSeven.htm?version=iphone_c@7.0403&desmobiel=${telNum}&showType=3`, 85 | headers: { 86 | Cookie: JSON.parse(loginheader)["Cookie"], 87 | }, 88 | }; 89 | const res = await $.get(url); 90 | return res; 91 | } 92 | 93 | function gettel() { 94 | const reqheaders = JSON.parse($.VAL_signheader); 95 | const reqreferer = reqheaders.Referer; 96 | const reqCookie = reqheaders.Cookie; 97 | let tel = ""; 98 | if (reqreferer.indexOf(`desmobile=`) >= 0) 99 | tel = reqreferer.match(/desmobile=(.*?)(&|$)/)[1]; 100 | if (tel == "" && reqCookie.indexOf(`u_account=`) >= 0) 101 | tel = reqCookie.match(/u_account=(.*?);/)[1]; 102 | return tel; 103 | } 104 | 105 | async function getdata(key) { 106 | const url = `http://${prefix}/query/boxdata`; 107 | const boxdata = await $.get({ url }); 108 | if (boxdata.datas[key]) { 109 | return boxdata.datas[key]; 110 | } else { 111 | return undefined; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /10086/10086.js: -------------------------------------------------------------------------------- 1 | // Variables used by Scriptable. 2 | // These must be at the very top of the file. Do not edit. 3 | // icon-color: deep-green icon-glyph: mobile 4 | 5 | /** 6 | * Author: GideonSenku,Chavyleung,wangfei021325 7 | * Github: https://github.com/GideonSenku 8 | */ 9 | 10 | const prefix = "boxjs.net" //修改成你用的域名 11 | const title = '移动5G' 12 | const preview = 'small' // 预览大小 可选:small,medium,large 13 | const spacing = 5 14 | const $ = importModule("Env") 15 | 16 | // 修改为BoxJS中的chavy_autologin_cmcc数据,或者抓包填入一个request对象 17 | const chavy_autologin_cmcc = `` 18 | 19 | // 修改为BoxJS中的chavy_getfee_cmcc数据,或者抓包填入一个request对象 20 | const chavy_getfee_cmcc = `` 21 | 22 | $.KEY_autologin = "chavy_autologin_cmcc" 23 | 24 | $.KEY_getfee = "chavy_getfee_cmcc" 25 | 26 | async function getdata(key) { 27 | const url = `http://${prefix}/query/boxdata` 28 | const boxdata = await $.get({ url }) 29 | if (boxdata.datas[key]) { 30 | return boxdata.datas[key] 31 | } else { 32 | return undefined 33 | } 34 | } 35 | 36 | const crypto = { 37 | moduleName: "crypto-js", 38 | url: 39 | "https://raw.githubusercontent.com/GideonSenku/Scriptable/master/crypto-js.min.js", 40 | } 41 | 42 | !(async () => { 43 | $.CryptoJS = $.require(crypto) 44 | $.autologin = await getdata($.KEY_autologin) 45 | $.getfee = await getdata($.KEY_getfee) 46 | await loginapp() 47 | await queryfee() 48 | await querymeal() 49 | await showmsg() 50 | await render() 51 | })().catch((e) => $.logErr(e)) 52 | 53 | function loginapp() { 54 | return new Promise((resolve) => { 55 | const url = $.autologin 56 | ? JSON.parse($.autologin) 57 | : JSON.parse(chavy_autologin_cmcc) 58 | $.post(url, (resp, data) => { 59 | try { 60 | $.setck = resp.headers["Set-Cookie"] 61 | console.warn("login") 62 | } catch (e) { 63 | $.logErr(e, resp) 64 | } finally { 65 | resolve() 66 | } 67 | }) 68 | }) 69 | } 70 | 71 | function queryfee() { 72 | return new Promise((resolve) => { 73 | const url = $.getfee ? JSON.parse($.getfee) : JSON.parse(chavy_getfee_cmcc) 74 | const body = JSON.parse(decrypt(url.body, "bAIgvwAuA4tbDr9d")) 75 | const cellNum = body.reqBody.cellNum 76 | const bodystr = `{"t":"${$.CryptoJS.MD5( 77 | $.setck 78 | ).toString()}","cv":"9.9.9","reqBody":{"cellNum":"${cellNum}"}}` 79 | url.body = encrypt(bodystr, "bAIgvwAuA4tbDr9d") 80 | url.headers["Cookie"] = $.setck 81 | url.headers["xs"] = $.CryptoJS.MD5( 82 | url.url + "_" + bodystr + "_Leadeon/SecurityOrganization" 83 | ).toString() 84 | 85 | $.post(url, (resp, data) => { 86 | try { 87 | $.fee = JSON.parse(decrypt(data, "GS7VelkJl5IT1uwQ")) 88 | console.warn("fee") 89 | } catch (e) { 90 | $.logErr(e, resp) 91 | } finally { 92 | resolve() 93 | } 94 | }) 95 | }) 96 | } 97 | 98 | function querymeal() { 99 | return new Promise((resolve) => { 100 | const url = $.getfee ? JSON.parse($.getfee) : JSON.parse(chavy_getfee_cmcc) 101 | url.url = 102 | "https://clientaccess.10086.cn/biz-orange/BN/newComboMealResouceUnite/getNewComboMealResource" 103 | const body = JSON.parse(decrypt(url.body, "bAIgvwAuA4tbDr9d")) 104 | const cellNum = body.reqBody.cellNum 105 | const bodystr = `{"t":"${$.CryptoJS.MD5( 106 | $.setck 107 | ).toString()}","cv":"9.9.9","reqBody":{"cellNum":"${cellNum}","tag":"3"}}` 108 | url.body = encrypt(bodystr, "bAIgvwAuA4tbDr9d") 109 | url.headers["Cookie"] = $.setck 110 | url.headers["xs"] = $.CryptoJS.MD5( 111 | url.url + "_" + bodystr + "_Leadeon/SecurityOrganization" 112 | ).toString() 113 | $.post(url, (resp, data) => { 114 | try { 115 | $.meal = JSON.parse(decrypt(data, "GS7VelkJl5IT1uwQ")) 116 | console.warn('meal') 117 | } catch (e) { 118 | $.logErr(e, resp) 119 | } finally { 120 | resolve() 121 | } 122 | }) 123 | }) 124 | } 125 | 126 | function encrypt(str, key) { 127 | return $.CryptoJS.AES.encrypt( 128 | $.CryptoJS.enc.Utf8.parse(str), 129 | $.CryptoJS.enc.Utf8.parse(key), 130 | { 131 | iv: $.CryptoJS.enc.Utf8.parse("9791027341711819"), 132 | mode: $.CryptoJS.mode.CBC, 133 | padding: $.CryptoJS.pad.Pkcs7, 134 | } 135 | ).toString() 136 | } 137 | 138 | function decrypt(str, key) { 139 | return $.CryptoJS.AES.decrypt(str, $.CryptoJS.enc.Utf8.parse(key), { 140 | iv: $.CryptoJS.enc.Utf8.parse("9791027341711819"), 141 | mode: $.CryptoJS.mode.CBC, 142 | padding: $.CryptoJS.pad.Pkcs7, 143 | }).toString($.CryptoJS.enc.Utf8) 144 | } 145 | 146 | function showmsg() { 147 | return new Promise((resolve) => { 148 | $.subt = `[话费] ${$.fee.rspBody.curFee}元` 149 | const res = $.meal.rspBody.qryInfoRsp[0].resourcesTotal 150 | const flowRes = res.find((r) => r.resourcesCode === "04") 151 | const voiceRes = res.find((r) => r.resourcesCode === "01") 152 | if (flowRes) { 153 | const remUnit = flowRes.remUnit === "05" ? "GB" : "MB" 154 | const usedUnit = flowRes.usedUnit === "05" ? "GB" : "MB" 155 | const unit = flowRes.allUnit === "05" ? "GB" : "MB" 156 | $.flowRes = `[流量] ${flowRes.allRemainRes}${remUnit}` 157 | } 158 | if (voiceRes) { 159 | const remUnit = flowRes.remUnit === "01" ? "分钟" : "" 160 | const usedUnit = flowRes.usedUnit === "01" ? "分钟" : "" 161 | const allUnit = "分钟" 162 | $.voiceRes = `[语音] ${voiceRes.allRemainRes}${allUnit}` 163 | } 164 | resolve() 165 | }) 166 | } 167 | 168 | async function render() { 169 | // create and show widget 170 | if (config.runsInWidget) { 171 | let widget = await getWidget() 172 | Script.setWidget(widget) 173 | Script.complete() 174 | } else { 175 | await getWidget() 176 | } 177 | } 178 | 179 | async function getWidget() { 180 | const texts = { 181 | subt: $.subt, 182 | flowRes: $.flowRes, 183 | voiceRes: $.voiceRes, 184 | updateTime: 'true', 185 | battery: 'true' 186 | } 187 | const opts = { 188 | title, 189 | texts, 190 | preview, 191 | spacing 192 | } 193 | let widget = await $.createWidget(opts) 194 | return widget 195 | } -------------------------------------------------------------------------------- /Apple/AppleRepair.js: -------------------------------------------------------------------------------- 1 | // Variables used by Scriptable. 2 | // These must be at the very top of the file. Do not edit. 3 | // icon-color: deep-blue; icon-glyph: wrench; 4 | /** 5 | * Author: GideonSenku 6 | * Github: https://github.com/GideonSenku 7 | */ 8 | 9 | const $ = importModule("Env") 10 | 11 | const title = 'AppleRepair' 12 | const preview = 'medium' // 预览大小 可选:small,medium,large 13 | const spacing = 5 // 间隙大小 14 | 15 | const repairId = 'xxxx' 16 | const serialNumber = 'xxxxx' 17 | 18 | 19 | const repairMetaData = await getinfo() 20 | await render() 21 | 22 | async function render() { 23 | // create and show widget 24 | if (config.runsInWidget) { 25 | let widget = await createWidget(repairMetaData) 26 | Script.setWidget(widget) 27 | Script.complete() 28 | } else { 29 | await createWidget(repairMetaData) 30 | } 31 | } 32 | 33 | async function createWidget(repairMetaData) { 34 | const texts = {} 35 | 36 | repairMetaData.repairDetails.forEach((detail, idx) => { 37 | const date = $.time('MM-dd HH:mm', detail?.time) 38 | const labelName = detail?.status 39 | const Line = `• ${date} ${labelName}` 40 | texts[`text${idx}`] = Line 41 | }) 42 | 43 | texts.battery = 'true' 44 | 45 | const opts = { 46 | title, 47 | texts, 48 | preview, 49 | spacing 50 | } 51 | let widget = await $.createWidget(opts) 52 | return widget 53 | } 54 | 55 | async function getinfo() { 56 | const url = { 57 | url: `https://mysupport.apple.com/api/v1/supportaccount/getRepairStatus?repairId=${repairId}&serialNumber=${serialNumber}`, 58 | headers: { 59 | 'Cookie': 'SA-Locale=zh_CN;' 60 | }, 61 | } 62 | const { data } = await $.get(url) 63 | return data?.repairMetaData 64 | } -------------------------------------------------------------------------------- /Bilibili/BilibiliMonitor.js: -------------------------------------------------------------------------------- 1 | // Variables used by Scriptable. 2 | // These must be at the very top of the file. Do not edit. 3 | // icon-color: pink; icon-glyph: heartbeat; 4 | /* 5 | * Author: evilbutcher 6 | * Github: https://github.com/evilbutcher 7 | * 本脚本使用了@Gideon_Senku的Env.scriptable,感谢! 8 | */ 9 | const goupdate = true; 10 | const $ = importModule("Env"); 11 | var rid = 0; //rid对应不同的B站榜单:0全站,1动画,3音乐,4游戏,5娱乐,36科技,119鬼畜,129舞蹈。 12 | var num = 6; //自定义显示数量 13 | var rancolor = true; //true为开启随机颜色 14 | 15 | try { 16 | var { bilibili, blnum, blrancolor } = importModule("Config"); 17 | rid = bilibili(); 18 | num = blnum(); 19 | rancolor = blrancolor(); 20 | console.log("将使用配置文件内B站配置"); 21 | } catch (e) { 22 | console.log("将使用脚本内B站配置"); 23 | } 24 | 25 | const res = await getinfo(); 26 | 27 | let widget = createWidget(res); 28 | Script.setWidget(widget); 29 | Script.complete(); 30 | 31 | function createWidget(res) { 32 | var group = res.data; 33 | items = []; 34 | for (var i = 0; i < num; i++) { 35 | var item = group[i].title; 36 | items.push(item); 37 | } 38 | console.log(items); 39 | 40 | const w = new ListWidget(); 41 | const bgColor = new LinearGradient(); 42 | bgColor.colors = [new Color("#1c1c1c"), new Color("#29323c")]; 43 | bgColor.locations = [0.0, 1.0]; 44 | w.backgroundGradient = bgColor; 45 | w.addSpacer(); 46 | w.spacing = 5; 47 | 48 | const firstLine = w.addText(`💗B站榜单`); 49 | firstLine.textSize = 15; 50 | firstLine.textColor = Color.white(); 51 | firstLine.textOpacity = 0.7; 52 | 53 | for (var i = 0; i < items.length; i++) { 54 | addTextToListWidget(`• ${items[i]}`, w); 55 | } 56 | 57 | w.addSpacer(); 58 | w.spacing = 5; 59 | w.presentSmall(); 60 | return w; 61 | } 62 | 63 | async function getinfo() { 64 | const blRequest = { 65 | url: `https://app.bilibili.com/x/v2/rank/region?rid=${rid}`, 66 | }; 67 | const res = await $.get(blRequest); 68 | log(res); 69 | return res; 70 | } 71 | 72 | function addTextToListWidget(text, listWidget) { 73 | let item = listWidget.addText(text); 74 | if (rancolor == true) { 75 | item.textColor = new Color(color16()); 76 | } else { 77 | item.textColor = Color.white(); 78 | } 79 | item.textSize = 12; 80 | } 81 | 82 | function color16() { 83 | var r = Math.floor(Math.random() * 256); 84 | if (r + 50 < 255) { 85 | r = r + 50; 86 | } 87 | if (r > 230 && r < 255) { 88 | r = r - 50; 89 | } 90 | var g = Math.floor(Math.random() * 256); 91 | if (g + 50 < 255) { 92 | g = g + 50; 93 | } 94 | if (g > 230 && g < 255) { 95 | g = g - 50; 96 | } 97 | var b = Math.floor(Math.random() * 256); 98 | if (b + 50 < 255) { 99 | b = b + 50; 100 | } 101 | if (b > 230 && b < 255) { 102 | b = b - 50; 103 | } 104 | var color = "#" + r.toString(16) + g.toString(16) + b.toString(16); 105 | return color; 106 | } 107 | 108 | //更新代码 109 | function update() { 110 | log("🔔更新脚本开始!"); 111 | scripts.forEach(async (script) => { 112 | await $.getFile(script); 113 | }); 114 | log("🔔更新脚本结束!"); 115 | } 116 | 117 | const scripts = [ 118 | { 119 | moduleName: "BilibiliMonitor", 120 | url: 121 | "https://raw.githubusercontent.com/evilbutcher/Scriptables/master/BilibiliMonitor.js", 122 | }, 123 | ]; 124 | if (goupdate == true) update(); 125 | -------------------------------------------------------------------------------- /Checkin/Checkin.js: -------------------------------------------------------------------------------- 1 | // Variables used by Scriptable. 2 | // These must be at the very top of the file. Do not edit. 3 | // icon-color: purple; icon-glyph: plane-departure; 4 | /* 5 | * Author: evilbutcher Neurogram 6 | * Github: https://github.com/evilbutcher 7 | * 本脚本使用了@Gideon_Senku的Env.scriptable,感谢! 8 | * 感谢@MuTu88帮忙测试! 9 | * 自动更新打开后会运行覆盖脚本内已有修改,多种解决方案: 10 | * 一、配置Config文件,请参考https://github.com/evilbutcher/Scriptables/blob/master/Config.js,下载后导入Scriptable,脚本运行会❗️优先❗️调取Config文件中信息,此方法只能显示❗️一个❗️机场。 11 | * 二、【推荐】Scriptable的iCloud文件夹内,配置checkin.json文件(注意文件名),具体格式参考https://github.com/evilbutcher/Scriptables/blob/master/checkin_example.json,可以通过创建桌面小组件时填入不同参数如“c1”、“c2”等实现读取多个机场信息。 12 | * 三、脚本内配置,在下方注释写有填写签到标题的引号内,填写对应的签到信息,注意,此方法一旦更新脚本,所做的更改就会被远程文件覆盖。 13 | * 脚本运行后,会在iCloud/Scriptable文件夹内写入一个recordcheckintime.txt,用于记录签到时间,脚本逻辑每天签到一次。 14 | */ 15 | const goupdate = false; //默认关闭,需要时打开,更新后会覆盖脚本已有的签到信息,建议使用Config或Scriptable的iCloud文件夹存入checkin.json文件的方式 16 | const $ = importModule("Env"); 17 | $.autoLogout = false; //退出登录后再签到 18 | try { 19 | const para = args.widgetParameter || "c1"; 20 | const fileName = "checkin.json"; 21 | const res = JSON.parse($.read(fileName)); 22 | var checkintitle = res[para].title || ""; //填写签到标题 23 | var checkinloginurl = res[para].url || ""; //填写签到登陆链接 24 | var checkinemail = res[para].email || ""; //填写签到邮箱 25 | var checkinpwd = res[para].password || ""; //填写签到密码 26 | } catch (e) { 27 | log("获取JSON文件失败"); 28 | } 29 | const size = 12; //字体大小 30 | const isDark = Device.isUsingDarkAppearance(); 31 | const bgColor = new LinearGradient(); 32 | bgColor.colors = isDark 33 | ? [new Color("#030079"), new Color("#000000")] 34 | : [new Color("#a18cd1"), new Color("#fbc2eb")]; 35 | bgColor.locations = [0.0, 1.0]; 36 | function addTextToListWidget(text, listWidget) { 37 | let item = listWidget.addText(text); 38 | item.textColor = isDark ? Color.white() : Color.black(); 39 | item.textSize = size; 40 | } 41 | function addTitleTextToListWidget(text, listWidget) { 42 | let item = listWidget.addText(text); 43 | item.textColor = isDark ? Color.white() : Color.black(); 44 | item.applyHeadlineTextStyling(); 45 | } 46 | 47 | const scripts = [ 48 | { 49 | moduleName: "Checkin", 50 | url: 51 | "https://raw.githubusercontent.com/evilbutcher/Scriptables/master/Checkin.js", 52 | }, 53 | ]; 54 | 55 | !(async () => { 56 | init(); 57 | getinfo(); 58 | await launch(); 59 | log($.checkintitle); 60 | log($.checkinMsg); 61 | log($.todayUsed); 62 | log($.usedData); 63 | log($.restData); 64 | let widget = createWidget( 65 | $.checkintitle, 66 | $.checkinMsg, 67 | $.todayUsed, 68 | $.usedData, 69 | $.restData 70 | ); 71 | Script.setWidget(widget); 72 | Script.complete(); 73 | })() 74 | .catch((err) => { 75 | $.msg("Checkin运行出现错误❌\n" + err); 76 | }) 77 | .finally(update()); 78 | 79 | function getinfo() { 80 | try { 81 | const con = importModule("Config"); 82 | $.checkintitle = con.checkintitle(); 83 | $.checkinloginurl = con.checkinloginurl(); 84 | $.checkinemail = con.checkinemail(); 85 | $.checkinpwd = con.checkinpwd(); 86 | if ( 87 | $.checkintitle == "" || 88 | $.checkinloginurl == "" || 89 | $.checkinemail == "" || 90 | $.checkinpwd == "" 91 | ) { 92 | log("配置文件内签到信息不完整"); 93 | throw new Error(err); 94 | } 95 | log("将使用配置文件内签到信息"); 96 | } catch (err) { 97 | $.checkintitle = checkintitle; 98 | $.checkinloginurl = checkinloginurl; 99 | $.checkinemail = checkinemail; 100 | $.checkinpwd = checkinpwd; 101 | log("将使用脚本内签到信息"); 102 | if ( 103 | $.checkintitle == "" || 104 | $.checkinloginurl == "" || 105 | $.checkinemail == "" || 106 | $.checkinpwd == "" 107 | ) { 108 | $.msg("请检查填入的签到信息是否完整"); 109 | } 110 | } 111 | } 112 | 113 | function init() { 114 | $.nowtime = new Date().getTime(); 115 | log($.nowtime); 116 | if ($.isFileExists("recordcheckintime.txt") == true) { 117 | var recordtime = $.read("recordcheckintime.txt"); 118 | log(recordtime); 119 | if ($.nowtime - recordtime > 86400000) { 120 | $.cancheckin = true; 121 | $.write("recordcheckintime.txt", JSON.stringify($.nowtime)); 122 | } else { 123 | $.cancheckin = false; 124 | } 125 | } else { 126 | $.write("recordcheckintime.txt", JSON.stringify($.nowtime)); 127 | log("初始时间已写入"); 128 | $.cancheckin = true; 129 | } 130 | } 131 | 132 | async function launch() { 133 | let title = $.checkintitle; 134 | let url = $.checkinloginurl; 135 | let email = $.checkinemail; 136 | let password = $.checkinpwd; 137 | if ($.autoLogout == true) { 138 | let logoutPath = 139 | url.indexOf("auth/login") != -1 ? "user/logout" : "user/logout.php"; 140 | var logouturl = { 141 | url: url.replace(/(auth|user)\/login(.php)*/g, "") + logoutPath, 142 | }; 143 | log(logouturl); 144 | await $.getStr(logouturl); 145 | await login(url, email, password, title); 146 | if ($.loginok == true) { 147 | if ($.cancheckin == true) { 148 | await checkin(url, email, password, title); 149 | if ($.checkinok == true) { 150 | await dataResults(url, $.checkindatamsg, title); 151 | } 152 | } else { 153 | await dataResults(url, "签到完成🎉", title); 154 | } 155 | } 156 | } else { 157 | if ($.cancheckin == true) { 158 | await checkin(url, email, password, title); 159 | if ($.checkinok == true) { 160 | await dataResults(url, $.checkindatamsg, title); 161 | } else { 162 | await login(url, email, password, title); 163 | if ($.loginok == true) { 164 | await checkin(url, email, password, title); 165 | await dataResults(url, "签到完成🎉", title); 166 | } 167 | } 168 | } else { 169 | await dataResults(url, "签到完成🎉", title); 170 | if ($.getdata == false) { 171 | await login(url, email, password, title); 172 | if ($.loginok == true) { 173 | await dataResults(url, "签到完成🎉", title); 174 | } 175 | } 176 | } 177 | } 178 | } 179 | 180 | async function login(url, email, password, title) { 181 | let loginPath = 182 | url.indexOf("auth/login") != -1 ? "auth/login" : "user/_login.php"; 183 | let table = { 184 | url: 185 | url.replace(/(auth|user)\/login(.php)*/g, "") + 186 | loginPath + 187 | `?email=${email}&passwd=${password}&rumber-me=week`, 188 | }; 189 | log(table); 190 | await $.post(table, async (response, data) => { 191 | if ( 192 | JSON.parse(data).msg.match( 193 | /邮箱不存在|邮箱或者密码错误|Mail or password is incorrect/ 194 | ) 195 | ) { 196 | $.msg(title + "邮箱或者密码错误"); 197 | $.loginok = false; 198 | log("登陆失败"); 199 | } else { 200 | $.loginok = true; 201 | log("登陆成功"); 202 | } 203 | }); 204 | } 205 | 206 | async function checkin(url, email, password, title) { 207 | let checkinPath = 208 | url.indexOf("auth/login") != -1 ? "user/checkin" : "user/_checkin.php"; 209 | var checkinreqest = { 210 | url: url.replace(/(auth|user)\/login(.php)*/g, "") + checkinPath, 211 | }; 212 | log(checkinreqest); 213 | await $.post(checkinreqest, async (response, data) => { 214 | if (data.match(/\"msg\"\:/)) { 215 | $.checkinok = true; 216 | $.checkindatamsg = JSON.parse(data).msg; 217 | log("签到成功"); 218 | } else { 219 | $.checkinok = false; 220 | log("签到失败"); 221 | } 222 | }); 223 | } 224 | 225 | async function dataResults(url, checkinMsg, title) { 226 | let userPath = url.indexOf("auth/login") != -1 ? "user" : "user/index.php"; 227 | var datarequest = { 228 | url: url.replace(/(auth|user)\/login(.php)*/g, "") + userPath, 229 | }; 230 | log(datarequest); 231 | await $.getStr(datarequest, async (response, data) => { 232 | if (data.match(/login|请填写邮箱|登陆/)) { 233 | $.getdata = false; 234 | } else { 235 | let resultData = ""; 236 | let result = []; 237 | if (data.match(/theme\/malio/)) { 238 | let flowInfo = data.match(/trafficDountChat\s*\(([^\)]+)/); 239 | if (flowInfo) { 240 | let flowData = flowInfo[1].match(/\d[^\']+/g); 241 | let usedData = flowData[0]; 242 | let todatUsed = flowData[1]; 243 | let restData = flowData[2]; 244 | $.todayUsed = `今日已用:${flowData[1]}`; 245 | $.usedData = `累计使用:${flowData[0]}`; 246 | $.restData = `剩余流量:${flowData[2]}`; 247 | result.push( 248 | `今日:${todatUsed}\n已用:${usedData}\n剩余:${restData}` 249 | ); 250 | } 251 | let userInfo = data.match(/ChatraIntegration\s*=\s*({[^}]+)/); 252 | if (userInfo) { 253 | let user_name = userInfo[1].match(/name.+'(.+)'/)[1]; 254 | let user_class = userInfo[1].match(/Class.+'(.+)'/)[1]; 255 | let class_expire = userInfo[1].match(/Class_Expire.+'(.+)'/)[1]; 256 | let money = userInfo[1].match(/Money.+'(.+)'/)[1]; 257 | result.push( 258 | `用户名:${user_name}\n用户等级:lv${user_class}\n余额:${money}\n到期时间:${class_expire}` 259 | ); 260 | } 261 | if (result.length != 0) { 262 | resultData = result.join("\n\n"); 263 | } 264 | } else { 265 | let todayUsed = data.match(/>*\s*今日(已用|使用)*[^B]+/); 266 | if (todayUsed) { 267 | todayUsed = flowFormat(todayUsed[0]); 268 | result.push(`今日:${todayUsed}`); 269 | $.todayUsed = `今日已用:${todayUsed}`; 270 | } else { 271 | $.todayUsed = `今日已用获取失败`; 272 | result.push(`今日已用获取失败`); 273 | } 274 | let usedData = data.match( 275 | /(Used Transfer|>过去已用|>已用|>总已用|\"已用)[^B]+/ 276 | ); 277 | if (usedData) { 278 | usedData = flowFormat(usedData[0]); 279 | result.push(`已用:${usedData}`); 280 | $.usedData = `累计使用:${usedData}`; 281 | } else { 282 | $.usedData = `累计使用获取失败`; 283 | result.push(`累计使用获取失败`); 284 | } 285 | let restData = data.match( 286 | /(Remaining Transfer|>剩余流量|>流量剩余|>可用|\"剩余)[^B]+/ 287 | ); 288 | if (restData) { 289 | restData = flowFormat(restData[0]); 290 | result.push(`剩余:${restData}`); 291 | $.restData = `剩余流量:${restData}`; 292 | } else { 293 | $.restData = `剩余流量获取失败`; 294 | result.push(`剩余流量获取失败`); 295 | } 296 | resultData = result.join("\n"); 297 | } 298 | $.checkinMsg = checkinMsg; 299 | log(title + "\n" + checkinMsg + "\n" + resultData); 300 | } 301 | }); 302 | } 303 | 304 | function flowFormat(data) { 305 | data = data.replace(/\d+(\.\d+)*%/, ""); 306 | let flow = data.match(/\d+(\.\d+)*\w*/); 307 | return flow[0] + "B"; 308 | } 309 | 310 | function createWidget(checkintitle, checkinMsg, todayUsed, usedData, restData) { 311 | const w = new ListWidget(); 312 | w.backgroundGradient = bgColor; 313 | w.addSpacer(); 314 | w.spacing = 5; 315 | 316 | const emoji = w.addText(`🪐`); 317 | emoji.textSize = 30; 318 | 319 | addTitleTextToListWidget(checkintitle, w); 320 | addTextToListWidget(checkinMsg, w); 321 | addTextToListWidget(todayUsed, w); 322 | addTextToListWidget(usedData, w); 323 | addTextToListWidget(restData, w); 324 | 325 | w.addSpacer(); 326 | w.spacing = 5; 327 | w.presentSmall(); 328 | return w; 329 | } 330 | 331 | //更新代码 332 | function update() { 333 | if (goupdate == true) { 334 | log("🔔更新脚本开始!"); 335 | scripts.forEach(async (script) => { 336 | await $.getFile(script); 337 | }); 338 | log("🔔更新脚本结束!"); 339 | } 340 | } 341 | -------------------------------------------------------------------------------- /Checkin/Dler Cloud.js: -------------------------------------------------------------------------------- 1 | // Variables used by Scriptable. 2 | // These must be at the very top of the file. Do not edit. 3 | // icon-color: purple; icon-glyph: plane-departure; 4 | /* 5 | * Author: evilbutcher Neurogram 6 | * Github: https://github.com/evilbutcher 7 | * 本脚本使用了@Gideon_Senku的Env.scriptable,感谢! 8 | * 感谢@MuTu88帮忙测试! 9 | * 自动更新打开后会运行覆盖脚本内已有修改,多种解决方案: 10 | * 一、配置Config文件,请参考https://github.com/evilbutcher/Scriptables/blob/master/Config.js,下载后导入Scriptable,脚本运行会❗️优先❗️调取Config文件中信息,此方法只能显示❗️一个❗️机场。 11 | * 二、【推荐】Scriptable的iCloud文件夹内,配置checkin.json文件(注意文件名),具体格式参考https://github.com/evilbutcher/Scriptables/blob/master/checkin_example.json,可以通过创建桌面小组件时填入不同参数如“c1”、“c2”等实现读取多个机场信息。 12 | * 三、脚本内配置,在下方注释写有填写签到标题的引号内,填写对应的签到信息,注意,此方法一旦更新脚本,所做的更改就会被远程文件覆盖。 13 | * 脚本运行后,会在iCloud/Scriptable文件夹内写入一个recordcheckintime.txt,用于记录签到时间,脚本逻辑每天签到一次。 14 | */ 15 | const goupdate = false; //默认关闭,需要时打开,更新后会覆盖脚本已有的签到信息,建议使用Config或Scriptable的iCloud文件夹存入checkin.json文件的方式 16 | const $ = importModule("Env"); 17 | $.autoLogout = false; //退出登录后再签到 18 | try { 19 | const para = args.widgetParameter || "c1"; 20 | const fileName = "checkin.json"; 21 | const res = JSON.parse($.read(fileName)); 22 | var checkintitle = res[para].title || ""; //填写签到标题 23 | var checkinloginurl = res[para].url || ""; //填写签到登陆链接 24 | var checkinemail = res[para].email || ""; //填写签到邮箱 25 | var checkinpwd = res[para].password || ""; //填写签到密码 26 | } catch (e) { 27 | log("获取JSON文件失败"); 28 | } 29 | const size = 12; //字体大小 30 | const isDark = Device.isUsingDarkAppearance(); 31 | const bgColor = new LinearGradient(); 32 | bgColor.colors = isDark 33 | ? [new Color("#030079"), new Color("#000000")] 34 | : [new Color("#a18cd1"), new Color("#fbc2eb")]; 35 | bgColor.locations = [0.0, 1.0]; 36 | function addTextToListWidget(text, listWidget) { 37 | let item = listWidget.addText(text); 38 | item.textColor = isDark ? Color.white() : Color.black(); 39 | item.textSize = size; 40 | } 41 | function addTitleTextToListWidget(text, listWidget) { 42 | let item = listWidget.addText(text); 43 | item.textColor = isDark ? Color.white() : Color.black(); 44 | item.applyHeadlineTextStyling(); 45 | } 46 | 47 | const scripts = [ 48 | { 49 | moduleName: "Checkin", 50 | url: 51 | "https://raw.githubusercontent.com/evilbutcher/Scriptables/master/Dler%20Cloud.js", 52 | }, 53 | ]; 54 | 55 | !(async () => { 56 | init(); 57 | getinfo(); 58 | await launch(); 59 | log($.checkintitle); 60 | log($.checkinMsg); 61 | log($.todayUsed); 62 | log($.usedData); 63 | log($.restData); 64 | let widget = createWidget( 65 | $.checkintitle, 66 | $.checkinMsg, 67 | $.todayUsed, 68 | $.usedData, 69 | $.restData 70 | ); 71 | Script.setWidget(widget); 72 | Script.complete(); 73 | })() 74 | .catch((err) => { 75 | $.msg("Checkin运行出现错误❌\n" + err); 76 | }) 77 | .finally(update()); 78 | 79 | function getinfo() { 80 | try { 81 | const con = importModule("Config"); 82 | $.checkintitle = con.checkintitle(); 83 | $.checkinloginurl = con.checkinloginurl(); 84 | $.checkinemail = con.checkinemail(); 85 | $.checkinpwd = con.checkinpwd(); 86 | if ( 87 | $.checkintitle == "" || 88 | $.checkinloginurl == "" || 89 | $.checkinemail == "" || 90 | $.checkinpwd == "" 91 | ) { 92 | log("配置文件内签到信息不完整"); 93 | throw new Error(err); 94 | } 95 | log("将使用配置文件内签到信息"); 96 | } catch (err) { 97 | $.checkintitle = checkintitle; 98 | $.checkinloginurl = checkinloginurl; 99 | $.checkinemail = checkinemail; 100 | $.checkinpwd = checkinpwd; 101 | log("将使用脚本内签到信息"); 102 | if ( 103 | $.checkintitle == "" || 104 | $.checkinloginurl == "" || 105 | $.checkinemail == "" || 106 | $.checkinpwd == "" 107 | ) { 108 | $.msg("请检查填入的签到信息是否完整"); 109 | } 110 | } 111 | } 112 | 113 | function init() { 114 | $.nowtime = new Date().getTime(); 115 | log($.nowtime); 116 | if ($.isFileExists("recordcheckintime.txt") == true) { 117 | var recordtime = $.read("recordcheckintime.txt"); 118 | log(recordtime); 119 | if ($.nowtime - recordtime > 86400000) { 120 | $.cancheckin = true; 121 | $.write("recordcheckintime.txt", JSON.stringify($.nowtime)); 122 | } else { 123 | $.cancheckin = false; 124 | } 125 | } else { 126 | $.write("recordcheckintime.txt", JSON.stringify($.nowtime)); 127 | log("初始时间已写入"); 128 | $.cancheckin = true; 129 | } 130 | } 131 | 132 | async function launch() { 133 | let title = $.checkintitle; 134 | let url = $.checkinloginurl; 135 | let email = $.checkinemail; 136 | let password = $.checkinpwd; 137 | if ($.autoLogout == true) { 138 | let logoutPath = 139 | url.indexOf("auth/login") != -1 ? "user/logout" : "user/logout.php"; 140 | var logouturl = { 141 | url: url.replace(/(auth|user)\/login(.php)*/g, "") + logoutPath, 142 | }; 143 | log(logouturl); 144 | await $.getStr(logouturl); 145 | await login(url, email, password, title); 146 | if ($.loginok == true) { 147 | if ($.cancheckin == true) { 148 | await checkin(url, email, password, title); 149 | if ($.checkinok == true) { 150 | await dataResults(url, $.checkindatamsg, title); 151 | } 152 | } else { 153 | await dataResults(url, "签到完成🎉", title); 154 | } 155 | } 156 | } else { 157 | if ($.cancheckin == true) { 158 | await checkin(url, email, password, title); 159 | if ($.checkinok == true) { 160 | await dataResults(url, $.checkindatamsg, title); 161 | } else { 162 | await login(url, email, password, title); 163 | if ($.loginok == true) { 164 | await checkin(url, email, password, title); 165 | await dataResults(url, "签到完成🎉", title); 166 | } 167 | } 168 | } else { 169 | await dataResults(url, "签到完成🎉", title); 170 | if ($.getdata == false) { 171 | await login(url, email, password, title); 172 | if ($.loginok == true) { 173 | await dataResults(url, "签到完成🎉", title); 174 | } 175 | } 176 | } 177 | } 178 | } 179 | 180 | async function login(url, email, password, title) { 181 | let loginPath = 182 | url.indexOf("auth/login") != -1 ? "auth/login" : "user/_login.php"; 183 | let table = { 184 | url: 185 | url.replace(/(auth|user)\/login(.php)*/g, "") + 186 | loginPath + 187 | `?email=${email}&passwd=${password}&rumber-me=week`, 188 | }; 189 | log(table); 190 | await $.post(table, async (response, data) => { 191 | if ( 192 | JSON.parse(data).msg.match( 193 | /邮箱不存在|邮箱或者密码错误|Mail or password is incorrect/ 194 | ) 195 | ) { 196 | $.msg(title + "邮箱或者密码错误"); 197 | $.loginok = false; 198 | log("登陆失败"); 199 | } else { 200 | $.loginok = true; 201 | log("登陆成功"); 202 | } 203 | }); 204 | } 205 | 206 | async function checkin(url, email, password, title) { 207 | let checkinPath = 208 | url.indexOf("auth/login") != -1 ? "user/checkin" : "user/_checkin.php"; 209 | var checkinreqest = { 210 | url: url.replace(/(auth|user)\/login(.php)*/g, "") + checkinPath, 211 | }; 212 | log(checkinreqest); 213 | await $.post(checkinreqest, async (response, data) => { 214 | if (data.match(/\"msg\"\:/)) { 215 | $.checkinok = true; 216 | $.checkindatamsg = JSON.parse(data).msg; 217 | log("签到成功"); 218 | } else { 219 | $.checkinok = false; 220 | log("签到失败"); 221 | } 222 | }); 223 | } 224 | 225 | async function dataResults(url, checkinMsg, title) { 226 | let userPath = url.indexOf("auth/login") != -1 ? "user" : "user/index.php"; 227 | var datarequest = { 228 | url: url.replace(/(auth|user)\/login(.php)*/g, "") + userPath, 229 | }; 230 | log(datarequest); 231 | await $.getStr(datarequest, async (response, data) => { 232 | if (data.match(/login|请填写邮箱|登陆/)) { 233 | $.getdata = false; 234 | } else { 235 | let resultData = ""; 236 | let result = []; 237 | if (data.match(/theme\/malio/)) { 238 | let flowInfo = data.match(/trafficDountChat\s*\(([^\)]+)/); 239 | if (flowInfo) { 240 | let flowData = flowInfo[1].match(/\d[^\']+/g); 241 | let usedData = flowData[0]; 242 | let todatUsed = flowData[1]; 243 | let restData = flowData[2]; 244 | $.todayUsed = `今日已用:${flowData[1]}`; 245 | $.usedData = `累计使用:${flowData[0]}`; 246 | $.restData = `剩余流量:${flowData[2]}`; 247 | result.push( 248 | `今日:${todatUsed}\n已用:${usedData}\n剩余:${restData}` 249 | ); 250 | } 251 | let userInfo = data.match(/ChatraIntegration\s*=\s*({[^}]+)/); 252 | if (userInfo) { 253 | let user_name = userInfo[1].match(/name.+'(.+)'/)[1]; 254 | let user_class = userInfo[1].match(/Class.+'(.+)'/)[1]; 255 | let class_expire = userInfo[1].match(/Class_Expire.+'(.+)'/)[1]; 256 | let money = userInfo[1].match(/Money.+'(.+)'/)[1]; 257 | result.push( 258 | `用户名:${user_name}\n用户等级:lv${user_class}\n余额:${money}\n到期时间:${class_expire}` 259 | ); 260 | } 261 | if (result.length != 0) { 262 | resultData = result.join("\n\n"); 263 | } 264 | } else { 265 | let todayUsed = data.match(/expire\"\,\s\".*?\"/); 266 | if (todayUsed) { 267 | var day = JSON.stringify(todayUsed).slice(14, -4); 268 | var time = day.replace(/-/g, "/"); 269 | var expire = new Date(time).getTime(); 270 | var left = ((expire - $.nowtime) / 86400000).toFixed(0); 271 | result.push(`剩余天数:${left}天`); 272 | $.todayUsed = `剩余天数:${left}天`; 273 | } else { 274 | $.todayUsed = `剩余天数获取失败`; 275 | result.push(`剩余天数获取失败`); 276 | } 277 | let usedData = data.match( 278 | /(Used Transfer|>过去已用|>已用|>总已用|\"已用)[^B]+/ 279 | ); 280 | if (usedData) { 281 | usedData = flowFormat(usedData[0]); 282 | result.push(`已用:${usedData}`); 283 | $.usedData = `累计使用:${usedData}`; 284 | } else { 285 | $.usedData = `累计使用获取失败`; 286 | result.push(`累计使用获取失败`); 287 | } 288 | let restData = data.match( 289 | /(Remaining Transfer|>剩余流量|>流量剩余|>可用|\"剩余)[^B]+/ 290 | ); 291 | if (restData) { 292 | restData = flowFormat(restData[0]); 293 | result.push(`剩余:${restData}`); 294 | $.restData = `剩余流量:${restData}`; 295 | } else { 296 | $.restData = `剩余流量获取失败`; 297 | result.push(`剩余流量获取失败`); 298 | } 299 | resultData = result.join("\n"); 300 | } 301 | $.checkinMsg = checkinMsg; 302 | log(title + "\n" + checkinMsg + "\n" + resultData); 303 | } 304 | }); 305 | } 306 | 307 | function flowFormat(data) { 308 | data = data.replace(/\d+(\.\d+)*%/, ""); 309 | let flow = data.match(/\d+(\.\d+)*\w*/); 310 | return flow[0] + "B"; 311 | } 312 | 313 | function createWidget(checkintitle, checkinMsg, todayUsed, usedData, restData) { 314 | const w = new ListWidget(); 315 | w.backgroundGradient = bgColor; 316 | w.addSpacer(); 317 | w.spacing = 5; 318 | 319 | const emoji = w.addText(`🪐`); 320 | emoji.textSize = 30; 321 | 322 | addTitleTextToListWidget(checkintitle, w); 323 | addTextToListWidget(checkinMsg, w); 324 | addTextToListWidget(todayUsed, w); 325 | addTextToListWidget(usedData, w); 326 | addTextToListWidget(restData, w); 327 | 328 | w.addSpacer(); 329 | w.spacing = 5; 330 | w.presentSmall(); 331 | return w; 332 | } 333 | 334 | //更新代码 335 | function update() { 336 | if (goupdate == true) { 337 | log("🔔更新脚本开始!"); 338 | scripts.forEach(async (script) => { 339 | await $.getFile(script); 340 | }); 341 | log("🔔更新脚本结束!"); 342 | } 343 | } 344 | -------------------------------------------------------------------------------- /Checkin/checkin_example.json: -------------------------------------------------------------------------------- 1 | { 2 | "c1": { 3 | "title": "name", 4 | "url": "https://your.loginurl.com/auth/login", 5 | "email": "example@email.com", 6 | "password": "password" 7 | }, 8 | "c2": { 9 | "title": "name", 10 | "url": "https://your.loginurl.com/auth/login", 11 | "email": "example@email.com", 12 | "password": "password" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Config.js: -------------------------------------------------------------------------------- 1 | // Variables used by Scriptable. 2 | // These must be at the very top of the file. Do not edit. 3 | // icon-color: deep-blue; icon-glyph: plus; 4 | /* 5 | * Author: evilbutcher 6 | * Github: https://github.com/evilbutcher 7 | */ 8 | 9 | module.exports = { 10 | bilibili: () => 0, //👈就改这个数字。B站榜单对应关系:0全站,1动画,3音乐,4游戏,5娱乐,36科技,119鬼畜,129舞蹈。 11 | blnum: () => 6, //自定义B站显示数量 12 | blrancolor: () => true, //是否开启B站随机颜色 13 | dbnum: () => 6, //自定义豆瓣显示数量 14 | dbrancolor: () => true, //是否开启豆瓣随机颜色 15 | rrnum: () => 6, //自定义人人影视显示数量 16 | rrrancolor: () => true, //是否开启人人影视随机颜色 17 | rsslink: () => "https://github.com/GideonSenku/Scriptable/commits/master.atom", //👈就改引号里的链接。 18 | rssnum: () => 6, //自定义RSS显示数量 19 | rssrancolor: () => true, //是否开启RSS随机颜色 20 | wbnum: () => 6, //自定义微博显示数量 21 | wbrancolor: () => true, //是否开启微博随机颜色 22 | zhnum: () => 6, //自定义知乎显示数量 23 | zhrancolor: () => true, //是否开启知乎随机颜色 24 | nasaapi: () => "", //填写NASA API Key 25 | imglink: () => "http://api.btstu.cn/sjbz/zsy.php", //NASA备用图片地址,可自定义 26 | checkintitle: () => "", //填写签到标题 27 | checkinloginurl: () => "", //填写签到登陆链接 28 | checkinemail: () => "", //填写签到邮箱 29 | checkinpwd: () => "", //填写签到密码 30 | }; 31 | -------------------------------------------------------------------------------- /Config.scriptable: -------------------------------------------------------------------------------- 1 | { 2 | "always_run_in_app" : false, 3 | "icon" : { 4 | "color" : "deep-blue", 5 | "glyph" : "plus" 6 | }, 7 | "name" : "Config", 8 | "script" : "\/*\n * Author: evilbutcher\n * Github: https:\/\/github.com\/evilbutcher\n *\/\nmodule.exports = () => {\n return new(class {\n bilibili() {\n return 4 \/\/👈就改这个数字。B站榜单对应关系:0全站,1动画,3音乐,4游戏,5娱乐,36科技,119鬼畜,129舞蹈。\n }\n rsslink() {\n return \"https:\/\/github.com\/GideonSenku\/Scriptable\/commits\/master.atom\" \/\/👈就改引号里的链接。\n }\n })\n}", 9 | "share_sheet_inputs" : [ 10 | 11 | ] 12 | } -------------------------------------------------------------------------------- /CountDown/CountDown.js: -------------------------------------------------------------------------------- 1 | // Variables used by Scriptable. 2 | // These must be at the very top of the file. Do not edit. 3 | // icon-color: light-gray; icon-glyph: magic; 4 | const $ = importModule("Env") 5 | 6 | // 更改inputValue会重新写入目标时间 7 | // 目标时间 = '年 月 日 时 分 秒' 用空格隔开, 8 | let inputValue = "0 0 0 0 0 0" 9 | 10 | const leftTime = await leftTimer(inputValue) 11 | 12 | if (config.runsInWidget) { 13 | let widget = createWidget(leftTime) 14 | Script.setWidget(widget) 15 | Script.complete() 16 | } 17 | 18 | // 倒计时到天 19 | function createWidget(leftTime) { 20 | let w = new ListWidget() 21 | const bgColor = new LinearGradient() 22 | bgColor.colors = [new Color("#1c1c1c"), new Color("#29323c")] 23 | bgColor.locations = [0.0, 1.0] 24 | w.backgroundGradient = bgColor 25 | w.presentSmall() 26 | w.spacing = 5 27 | 28 | let line0 = w.addText(`距离`) 29 | line0.textColor = Color.white() 30 | line0.textSize = 12 31 | line0.textOpacity = 0.7 32 | 33 | let line1 = w.addText(`重要的日子`) 34 | line1.textColor = Color.white() 35 | line1.textSize = 15 36 | 37 | let line2 = w.addText(`还有`) 38 | line2.textColor = Color.white() 39 | line2.textSize = 12 40 | line2.textOpacity = 0.7 41 | 42 | let line3 = w.addText(`${leftTime[0]}天`) 43 | line3.textColor = Color.white() 44 | line3.textSize = 28 45 | 46 | return w 47 | } 48 | 49 | 50 | async function leftTimer(inputValue){ 51 | if ( inputValue != "0 0 0 0 0 0" ) { 52 | if( $.setdata('Time', inputValue) ){ 53 | log('clear:' + inputValue) 54 | } 55 | } else if ( $.hasdata('Time') ) { 56 | inputValue = $.getdata('Time') 57 | log('get:' + inputValue) 58 | } else { 59 | inputValue = await $.input('目标时间', '年 月 日 时 分 秒,用空格隔开', '例如:2020 12 31 0 0 0') 60 | if($.setdata('Time', inputValue)) { 61 | log('success:' + inputValue) 62 | } 63 | } 64 | 65 | let targetTime = inputValue.split(" "); 66 | var leftTime = (new Date(targetTime[0], targetTime[1]-1, targetTime[2], targetTime[3], targetTime[4], targetTime[5])) - (new Date()); //计算剩余的毫秒数 67 | var days = parseInt(leftTime / 1000 / 60 / 60 / 24 , 10); //计算剩余的天数 68 | var hours = parseInt(leftTime / 1000 / 60 / 60 % 24 , 10); //计算剩余的小时 69 | var minutes = parseInt(leftTime / 1000 / 60 % 60, 10);//计算剩余的分钟 70 | var seconds = parseInt(leftTime / 1000 % 60, 10);//计算剩余的秒数 71 | 72 | var leftTime=new Array(); 73 | leftTime[0] = checkTime(days); 74 | leftTime[1] = checkTime(hours); 75 | leftTime[2] = checkTime(minutes); 76 | leftTime[3] = checkTime(seconds); 77 | 78 | log(leftTime) 79 | return leftTime 80 | } 81 | 82 | function checkTime(i) { //将0-9的数字前面加上0,例1变为01 83 | if(i<10) { 84 | i = "0" + i; 85 | } 86 | return i; 87 | } 88 | 89 | -------------------------------------------------------------------------------- /Douban/DoubanMonitor.js: -------------------------------------------------------------------------------- 1 | // Variables used by Scriptable. 2 | // These must be at the very top of the file. Do not edit. 3 | // icon-color: green; icon-glyph: film; 4 | /* 5 | * Author: evilbutcher 6 | * Github: https://github.com/evilbutcher 7 | * 本脚本使用了@Gideon_Senku的Env.scriptable,感谢! 8 | */ 9 | const goupdate = true; 10 | const $ = importModule("Env"); 11 | var num = 6; //自定义显示数量 12 | var rancolor = true; //true为开启随机颜色 13 | 14 | try { 15 | var { dbnum, dbrancolor } = importModule("Config"); 16 | num = dbnum(); 17 | rancolor = dbrancolor(); 18 | console.log("将使用配置文件内B站配置"); 19 | } catch (e) { 20 | console.log("将使用脚本内B站配置"); 21 | } 22 | 23 | const res = await getinfo(); 24 | 25 | let widget = createWidget(res); 26 | Script.setWidget(widget); 27 | Script.complete(); 28 | 29 | function createWidget(res) { 30 | var group = res["subject_collection_items"]; 31 | items = []; 32 | for (var i = 0; i < num; i++) { 33 | var title = group[i].title; 34 | var rating = group[i].rating; 35 | if (rating == null) { 36 | var star = "暂无"; 37 | } else { 38 | star = rating["star_count"]; 39 | } 40 | var item = title + " " + star + "✨"; 41 | items.push(item); 42 | } 43 | console.log(items); 44 | 45 | const w = new ListWidget(); 46 | const bgColor = new LinearGradient(); 47 | bgColor.colors = [new Color("#1c1c1c"), new Color("#29323c")]; 48 | bgColor.locations = [0.0, 1.0]; 49 | w.backgroundGradient = bgColor; 50 | w.addSpacer(); 51 | w.spacing = 5; 52 | 53 | const firstLine = w.addText(`🎞豆瓣电影`); 54 | firstLine.textSize = 15; 55 | firstLine.textColor = Color.white(); 56 | firstLine.textOpacity = 0.7; 57 | 58 | for (var i = 0; i < items.length; i++) { 59 | addTextToListWidget(`• ${items[i]}`, w); 60 | } 61 | 62 | w.addSpacer(); 63 | w.spacing = 5; 64 | w.presentSmall(); 65 | return w; 66 | } 67 | 68 | async function getinfo() { 69 | const dbheader = { 70 | Referer: `https://m.douban.com/pwa/cache_worker`, 71 | }; 72 | const dbRequest = { 73 | url: 74 | "https://m.douban.com/rexxar/api/v2/subject_collection/movie_real_time_hotest/items?start=0&count=50&items_only=1&for_mobile=1", 75 | headers: dbheader, 76 | }; 77 | const res = await $.get(dbRequest); 78 | log(res); 79 | return res; 80 | } 81 | 82 | function addTextToListWidget(text, listWidget) { 83 | let item = listWidget.addText(text); 84 | if (rancolor == true) { 85 | item.textColor = new Color(color16()); 86 | } else { 87 | item.textColor = Color.white(); 88 | } 89 | item.textSize = 12; 90 | } 91 | 92 | function color16() { 93 | var r = Math.floor(Math.random() * 256); 94 | if (r + 50 < 255) { 95 | r = r + 50; 96 | } 97 | if (r > 230 && r < 255) { 98 | r = r - 50; 99 | } 100 | var g = Math.floor(Math.random() * 256); 101 | if (g + 50 < 255) { 102 | g = g + 50; 103 | } 104 | if (g > 230 && g < 255) { 105 | g = g - 50; 106 | } 107 | var b = Math.floor(Math.random() * 256); 108 | if (b + 50 < 255) { 109 | b = b + 50; 110 | } 111 | if (b > 230 && b < 255) { 112 | b = b - 50; 113 | } 114 | var color = "#" + r.toString(16) + g.toString(16) + b.toString(16); 115 | return color; 116 | } 117 | 118 | //更新代码 119 | function update() { 120 | log("🔔更新脚本开始!"); 121 | scripts.forEach(async (script) => { 122 | await $.getFile(script); 123 | }); 124 | log("🔔更新脚本结束!"); 125 | } 126 | 127 | const scripts = [ 128 | { 129 | moduleName: "DoubanMonitor", 130 | url: 131 | "https://raw.githubusercontent.com/evilbutcher/Scriptables/master/DoubanMonitor.js", 132 | }, 133 | ]; 134 | if (goupdate == true) update(); 135 | -------------------------------------------------------------------------------- /Env.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: GideonSenku 3 | * Github: https://github.com/GideonSenku 4 | */ 5 | 6 | var locationData, sunData 7 | const currentDate = new Date() 8 | const request = new Request('') 9 | const files = FileManager.iCloud() 10 | const dict = files.documentsDirectory() 11 | files.isDirectory(`${dict}/Env`) ? `` : files.createDirectory(`${dict}/Env`) 12 | const defaultHeaders = { 13 | "Accept": "*/*", 14 | "Content-Type": "application/json" 15 | } 16 | const textFormat = { 17 | defaultText: { size: 14, color: "ffffff", font: "regular" }, 18 | battery: { size: 10, color: "", font: "bold" }, 19 | title: { size: 16, color: "", font: "semibold" }, 20 | SFMono: { size: 12, color: "ffffff", font: "SF Mono" } 21 | } 22 | /** 23 | * @description GET,返回String数据 24 | * @param {*} param0 request信息 25 | * @param {*} callback 回调返回response和JSON对象 26 | */ 27 | const get = async ({ url, headers = {} }, callback = () => {} ) => { 28 | request.url = url 29 | request.method = 'GET' 30 | request.headers = { 31 | ...headers, 32 | ...defaultHeaders 33 | } 34 | const data = await request.loadJSON() 35 | callback(request.response, data) 36 | return data 37 | } 38 | 39 | /** 40 | * @description GET,返回String数据 41 | * @param {*} param0 request信息 42 | * @param {*} callback 回调返回response和String对象 43 | */ 44 | const getStr = async ({ url, headers = {} }, callback = () => {} ) => { 45 | request.url = url 46 | request.method = 'GET' 47 | request.headers = { 48 | ...headers, 49 | ...defaultHeaders 50 | } 51 | const data = await request.loadString() 52 | callback(request.response, data) 53 | return data 54 | } 55 | 56 | /** 57 | * @description POST,返回String数据 58 | * @param {*} param0 request信息 59 | * @param {*} callback 回调返回response和String 60 | */ 61 | const post = async ({ url, body, headers = {} }, callback = () => {} ) => { 62 | request.url = url 63 | request.body = body 64 | request.method = 'POST' 65 | request.headers = { 66 | ...defaultHeaders, 67 | ...headers 68 | } 69 | const data = await request.loadString() 70 | callback(request.response, data) 71 | return data 72 | } 73 | 74 | /** 75 | * @description POST,返回JSON数据 76 | * @param {*} param0 request信息 77 | * @param {*} callback 回调返回response和JSON 78 | */ 79 | const _post = async ({ url, body, headers = {} }, callback = () => {} ) => { 80 | request.url = url 81 | request.body = body 82 | request.method = 'POST' 83 | request.headers = { 84 | ...defaultHeaders, 85 | ...headers 86 | } 87 | const data = await request.loadJSON() 88 | callback(request.response, data) 89 | return data 90 | } 91 | 92 | /** 93 | * @description 下载文件 94 | * @param {*} param0 95 | */ 96 | const getFile = async ({moduleName, url}) => { 97 | log(`开始下载文件: 🌝 ${moduleName}`) 98 | const header = `// Variables used by Scriptable. 99 | // These must be at the very top of the file. Do not edit. 100 | // icon-color: deep-gray; icon-glyph: file-code;\n`; 101 | const content = await getStr({url}) 102 | const fileHeader = content.includes('icon-color') ? `` : header 103 | write(`${moduleName}`, `${fileHeader}${content}`) 104 | log(`文件下载完成: 🌚 ${moduleName}`) 105 | } 106 | 107 | /** 108 | * 109 | * @description 导入模块,不存在即下载模块,也可传入forceDownload: true 强制更新模块 110 | * @param {*} param0 111 | */ 112 | const require = ({ 113 | moduleName, 114 | url = '', 115 | forceDownload = false 116 | }) => { 117 | if (isFileExists(moduleName) && !forceDownload) { 118 | log(`导入模块: 🪐${moduleName}`) 119 | return importModule(moduleName) 120 | } else { 121 | getFile({ moduleName, url }) 122 | log(`导入模块: 🪐${moduleName}`) 123 | return importModule(moduleName) 124 | } 125 | } 126 | /** 127 | * 128 | * @description 将数据写入文件 129 | * @param {*} fileName 要写入的文件名,默认JS文件,可选其他,加上文件名后缀即可 130 | * @param {*} content 要写入的文件内容 131 | */ 132 | const write = (fileName, content) => { 133 | let file = initFile(fileName) 134 | const filePath = `${dict}/${file}` 135 | FileManager.iCloud().writeString(filePath, content) 136 | return true 137 | } 138 | 139 | /** 140 | * 141 | * @description 判断文件是否存在 142 | * @param {*} fileName 143 | */ 144 | const isFileExists = (fileName) => { 145 | let file = initFile(fileName) 146 | return FileManager.iCloud().fileExists(`${dict}/${file}`) 147 | } 148 | 149 | const initFile = (fileName) => { 150 | const hasSuffix = fileName.lastIndexOf('.') + 1 151 | return !hasSuffix ? `${fileName}.js` : fileName 152 | } 153 | 154 | /** 155 | * 156 | * @description 读取文件内容 157 | * @param {*} fileName 要读取的文件名,默认JS文件,可选其他,加上文件名后缀即可 158 | * @return 返回文件内容,字符串形式 159 | */ 160 | const read = (fileName) => { 161 | const file = initFile(fileName) 162 | return FileManager.iCloud().readString(`${dict}/${file}`) 163 | } 164 | 165 | /** 166 | * 167 | * @description 提示框 168 | * @param {*} title 提示框标题 169 | * @param {*} message 提示框内容 170 | * @param {*} btnMes 提示框按钮标题,默认Cancel 171 | */ 172 | const msg = (title, message, btnMes = 'Cancel') => { 173 | if (!config.runsInWidget) { 174 | const alert = new Alert() 175 | alert.title = title 176 | alert.message = message 177 | alert.addAction(btnMes) 178 | alert.present() 179 | } 180 | } 181 | 182 | const setdata = (Val, Key) => { 183 | Keychain.set(Val, Key) 184 | return true 185 | } 186 | 187 | const getdata = (Key) => { 188 | return Keychain.get(Key) 189 | } 190 | 191 | const hasdata = (Key) => { 192 | return Keychain.contains(Key) 193 | } 194 | 195 | const rmdata = (Key) => { 196 | Keychain.remove(Key) 197 | return true 198 | } 199 | 200 | // Presents an alert where the user can enter a value in a text field. 201 | // Returns the entered value. 202 | const input = async(title, message, placeholder, value = null) => { 203 | if (!config.runsInWidget) { 204 | let alert = new Alert() 205 | alert.title = title 206 | alert.message = message 207 | alert.addTextField(placeholder, value) 208 | alert.addAction("OK") 209 | alert.addCancelAction("Cancel") 210 | let idx = await alert.present() 211 | if (idx != -1) { 212 | return alert.textFieldValue(0) 213 | } else { 214 | throw new Error("Cancelled entering value") 215 | } 216 | } 217 | } 218 | 219 | /** 220 | * 221 | * 示例:$.time('yyyy-MM-dd qq HH:mm:ss.S') 222 | * :$.time('yyyyMMddHHmmssS') 223 | * y:年 M:月 d:日 q:季 H:时 m:分 s:秒 S:毫秒 224 | * 其中y可选0-4位占位符、S可选0-1位占位符,其余可选0-2位占位符 225 | * @param {*} fmt 格式化参数 226 | * @param {*} ts 时间戳 13位 227 | */ 228 | const time = (fmt, ts = null) => { 229 | const date = ts ? new Date(ts) : new Date() 230 | let o = { 231 | 'M+': date.getMonth() + 1, 232 | 'd+': date.getDate(), 233 | 'H+': date.getHours(), 234 | 'm+': date.getMinutes(), 235 | 's+': date.getSeconds(), 236 | 'q+': Math.floor((date.getMonth() + 3) / 3), 237 | 'S': date.getMilliseconds() 238 | } 239 | if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)) 240 | for (let k in o) 241 | if (new RegExp('(' + k + ')').test(fmt)) 242 | fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)) 243 | return fmt 244 | } 245 | 246 | /** 247 | * @description create wiget 248 | * @param {*} title required 249 | * @param {*} texts required 250 | * @param {*} preview option 251 | */ 252 | const createWidget = async({ title, texts = { },spacing = 5, preview = '' }) => { 253 | let w = new ListWidget() 254 | w.spacing = spacing 255 | 256 | let gradient = new LinearGradient() 257 | let gradientSettings = await setupGradient() 258 | 259 | gradient.colors = gradientSettings.color() 260 | gradient.locations = gradientSettings.position() 261 | 262 | w.backgroundGradient = gradient 263 | texts['battery'] ? battery(w, title) : provideText(title, w, textFormat.title) 264 | for (const text in texts) { 265 | if (text != 'battery' && text != 'updateTime' && texts.hasOwnProperty(text) && texts[text]) { 266 | const element = texts[text] 267 | provideText(element, w, textFormat.SFMono) 268 | } 269 | } 270 | texts['updateTime'] ? provideText(`[更新] ${time('MM-dd HH:mm')}`, w, textFormat.SFMono) : `` 271 | 272 | widgetPreview = preview ? preview: 'small' 273 | 274 | if(widgetPreview == "small") { w.presentSmall() } 275 | else if (widgetPreview == "medium") { w.presentMedium() } 276 | else if (widgetPreview == "large") { w.presentLarge() } 277 | return w 278 | } 279 | 280 | 281 | /** 282 | * @description Provide a font based on the input. 283 | * @param {*} fontName 284 | * @param {*} fontSize 285 | */ 286 | const provideFont = (fontName, fontSize) => { 287 | const fontGenerator = { 288 | "ultralight": function() { return Font.ultraLightSystemFont(fontSize) }, 289 | "light": function() { return Font.lightSystemFont(fontSize) }, 290 | "regular": function() { return Font.regularSystemFont(fontSize) }, 291 | "medium": function() { return Font.mediumSystemFont(fontSize) }, 292 | "semibold": function() { return Font.semiboldSystemFont(fontSize) }, 293 | "bold": function() { return Font.boldSystemFont(fontSize) }, 294 | "heavy": function() { return Font.heavySystemFont(fontSize) }, 295 | "black": function() { return Font.blackSystemFont(fontSize) }, 296 | "italic": function() { return Font.italicSystemFont(fontSize) } 297 | } 298 | 299 | const systemFont = fontGenerator[fontName] 300 | if (systemFont) { return systemFont() } 301 | return new Font(fontName, fontSize) 302 | } 303 | 304 | 305 | /** 306 | * @description Add formatted text to a container. 307 | * @param {*} string 308 | * @param {*} container widget container 309 | * @param {*} format Object: size, color, font 310 | */ 311 | 312 | const provideText = (string, container, format) => { 313 | let url 314 | if (typeof string !== 'string') { 315 | url = string.url 316 | string = string.text 317 | } 318 | const stackItem = container.addStack() 319 | 320 | if (url) { 321 | stackItem.url = url 322 | } 323 | 324 | const textItem = stackItem.addText(string) 325 | const textFont = format.font || textFormat.defaultText.font 326 | const textSize = format.size || textFormat.defaultText.size 327 | const textColor = format.color || textFormat.defaultText.color 328 | 329 | textItem.font = provideFont(textFont, textSize) 330 | textItem.textColor = new Color(textColor) 331 | return stackItem 332 | } 333 | 334 | // Set up the gradient for the widget background. 335 | const setupGradient = async() => { 336 | 337 | // Requirements: sunrise 338 | if (!sunData) { await setupSunrise() } 339 | 340 | let gradient = { 341 | dawn: { 342 | color() { return [new Color("142C52"), new Color("1B416F"), new Color("62668B")] }, 343 | position() { return [0, 0.5, 1] }, 344 | }, 345 | 346 | sunrise: { 347 | color() { return [new Color("274875"), new Color("766f8d"), new Color("f0b35e")] }, 348 | position() { return [0, 0.8, 1.5] }, 349 | }, 350 | 351 | midday: { 352 | color() { return [new Color("3a8cc1"), new Color("90c0df")] }, 353 | position() { return [0, 1] }, 354 | }, 355 | 356 | noon: { 357 | color() { return [new Color("b2d0e1"), new Color("80B5DB"), new Color("3a8cc1")] }, 358 | position() { return [-0.2, 0.2, 1.5] }, 359 | }, 360 | 361 | sunset: { 362 | color() { return [new Color("32327A"), new Color("662E55"), new Color("7C2F43")] }, 363 | position() { return [0.1, 0.9, 1.2] }, 364 | }, 365 | 366 | twilight: { 367 | color() { return [new Color("021033"), new Color("16296b"), new Color("414791")] }, 368 | position() { return [0, 0.5, 1] }, 369 | }, 370 | 371 | night: { 372 | color() { return [new Color("16296b"), new Color("021033"), new Color("021033"), new Color("113245")] }, 373 | position() { return [-0.5, 0.2, 0.5, 1] }, 374 | }, 375 | } 376 | 377 | const sunrise = sunData.sunrise 378 | const sunset = sunData.sunset 379 | const utcTime = currentDate.getTime() 380 | 381 | function closeTo(time,mins) { 382 | return Math.abs(utcTime - time) < (mins * 60000) 383 | } 384 | 385 | // Use sunrise or sunset if we're within 30min of it. 386 | if (closeTo(sunrise,15)) { return gradient.sunrise } 387 | if (closeTo(sunset,15)) { return gradient.sunset } 388 | 389 | // In the 30min before/after, use dawn/twilight. 390 | if (closeTo(sunrise,45) && utcTime < sunrise) { return gradient.dawn } 391 | if (closeTo(sunset,45) && utcTime > sunset) { return gradient.twilight } 392 | 393 | // Otherwise, if it's night, return night. 394 | if (isNight(currentDate)) { return gradient.night } 395 | 396 | // If it's around noon, the sun is high in the sky. 397 | if (currentDate.getHours() == 12) { return gradient.noon } 398 | // Otherwise, return the "typical" theme. 399 | return gradient.midday 400 | } 401 | 402 | // Set up the sunData object. 403 | const setupSunrise = async () => { 404 | 405 | // Requirements: location 406 | if (!locationData) { await setupLocation() } 407 | 408 | // Set up the sunrise/sunset cache. 409 | const sunCachePath = files.joinPath(dict, "Env/Env-sun") 410 | const sunCacheExists = files.fileExists(sunCachePath) 411 | const sunCacheDate = sunCacheExists ? files.modificationDate(sunCachePath) : 0 412 | var sunDataRaw 413 | 414 | // If cache exists and it was created today, use cached data. 415 | if (sunCacheExists && sameDay(currentDate, sunCacheDate)) { 416 | const sunCache = files.readString(sunCachePath) 417 | sunDataRaw = JSON.parse(sunCache) 418 | 419 | // Otherwise, use the API to get sunrise and sunset times. 420 | } else { 421 | const sunReq = "https://api.sunrise-sunset.org/json?lat=" + locationData.latitude + "&lng=" + locationData.longitude + "&formatted=0&date=" + currentDate.getFullYear() + "-" + (currentDate.getMonth()+1) + "-" + currentDate.getDate() 422 | sunDataRaw = await new Request(sunReq).loadJSON() 423 | files.writeString(sunCachePath, JSON.stringify(sunDataRaw)) 424 | } 425 | 426 | // Store the timing values. 427 | sunData = {} 428 | sunData.sunrise = new Date(sunDataRaw.results.sunrise).getTime() 429 | sunData.sunset = new Date(sunDataRaw.results.sunset).getTime() 430 | } 431 | 432 | const setupLocation = async (lockLocation = true) => { 433 | 434 | locationData = {} 435 | const locationPath = files.joinPath(dict, "Env/Env-location") 436 | 437 | // If our location is unlocked or cache doesn't exist, ask iOS for location. 438 | var readLocationFromFile = false 439 | if (!lockLocation || !files.fileExists(locationPath)) { 440 | try { 441 | const location = await Location.current() 442 | locationData.latitude = location.latitude 443 | locationData.longitude = location.longitude 444 | files.writeString(locationPath, location.latitude + "," + location.longitude) 445 | 446 | } catch(e) { 447 | // If we fail in unlocked mode, read it from the cache. 448 | if (!lockLocation) { readLocationFromFile = true } 449 | 450 | // We can't recover if we fail on first run in locked mode. 451 | else { return } 452 | } 453 | } 454 | 455 | // If our location is locked or we need to read from file, do it. 456 | if (lockLocation || readLocationFromFile) { 457 | const locationStr = files.readString(locationPath).split(",") 458 | locationData.latitude = locationStr[0] 459 | locationData.longitude = locationStr[1] 460 | } 461 | return locationData 462 | } 463 | 464 | // Determines if the provided date is at night. 465 | const isNight = (dateInput) => { 466 | const timeValue = dateInput.getTime() 467 | return (timeValue < sunData.sunrise) || (timeValue > sunData.sunset) 468 | } 469 | // Determines if two dates occur on the same day 470 | const sameDay = (d1, d2) => { 471 | return d1.getFullYear() === d2.getFullYear() && 472 | d1.getMonth() === d2.getMonth() && 473 | d1.getDate() === d2.getDate() 474 | } 475 | /** 476 | * @description 返回电池百分比 477 | */ 478 | const renderBattery = () => { 479 | const batteryLevel = Device.batteryLevel() 480 | const batteryAscii = `${Math.round(batteryLevel * 100)}%` 481 | return batteryAscii 482 | } 483 | 484 | 485 | // Add a battery element to the widget; consisting of a battery icon and percentage. 486 | function battery(column,title) { 487 | const batteryLevel = Device.batteryLevel() 488 | // Set up the battery level item 489 | let batteryStack = column.addStack() 490 | provideText(title, batteryStack, textFormat.title) 491 | 492 | batteryStack.centerAlignContent() 493 | 494 | batteryStack.addSpacer() 495 | 496 | let batteryIcon = batteryStack.addImage(provideBatteryIcon()) 497 | batteryIcon.imageSize = new Size(20,20) 498 | 499 | 500 | // Change the battery icon to red if battery level is <= 20 to match system behavior 501 | if ( Math.round(batteryLevel * 100) > 20 || Device.isCharging() ) { 502 | 503 | batteryIcon.tintColor = Color.white() 504 | 505 | } else { 506 | 507 | batteryIcon.tintColor = Color.red() 508 | 509 | } 510 | 511 | // Display the battery status 512 | let batteryInfo = provideText(' '+renderBattery(), batteryStack, textFormat.battery) 513 | 514 | 515 | } 516 | 517 | 518 | // Provide a battery SFSymbol with accurate level drawn on top of it. 519 | function provideBatteryIcon() { 520 | 521 | if (Device.isCharging()) { return SFSymbol.named("battery.100.bolt").image } 522 | 523 | // Set the size of the battery icon. 524 | const batteryWidth = 87 525 | const batteryHeight = 41 526 | 527 | // Start our draw context. 528 | let draw = new DrawContext() 529 | draw.opaque = false 530 | draw.respectScreenScale = true 531 | draw.size = new Size(batteryWidth, batteryHeight) 532 | 533 | // Draw the battery. 534 | draw.drawImageInRect(SFSymbol.named("battery.0").image, new Rect(0, 0, batteryWidth, batteryHeight)) 535 | 536 | // Match the battery level values to the SFSymbol. 537 | const x = batteryWidth*0.1525 538 | const y = batteryHeight*0.247 539 | const width = batteryWidth*0.602 540 | const height = batteryHeight*0.505 541 | 542 | // Prevent unreadable icons. 543 | let level = Device.batteryLevel() 544 | if (level < 0.05) { level = 0.05 } 545 | 546 | // Determine the width and radius of the battery level. 547 | const current = width * level 548 | let radius = height/6.5 549 | 550 | // When it gets low, adjust the radius to match. 551 | if (current < (radius * 2)) { radius = current / 2 } 552 | 553 | // Make the path for the battery level. 554 | let barPath = new Path() 555 | barPath.addRoundedRect(new Rect(x, y, current, height), radius, radius) 556 | draw.addPath(barPath) 557 | draw.setFillColor(Color.black()) 558 | draw.fillPath() 559 | return draw.getImage() 560 | } 561 | 562 | const logErr = (e, messsage) => { 563 | console.error(e) 564 | } 565 | 566 | 567 | module.exports = { 568 | dict, 569 | get, 570 | getStr, 571 | post, 572 | _post, 573 | getFile, 574 | require, 575 | write, 576 | isFileExists, 577 | initFile, 578 | read, 579 | setdata, 580 | getdata, 581 | hasdata, 582 | rmdata, 583 | msg, 584 | input, 585 | time, 586 | createWidget, 587 | provideText, 588 | setupLocation, 589 | renderBattery, 590 | logErr 591 | } 592 | -------------------------------------------------------------------------------- /Env.scriptable: -------------------------------------------------------------------------------- 1 | { 2 | "always_run_in_app" : false, 3 | "icon" : { 4 | "color" : "brown", 5 | "glyph" : "terminal" 6 | }, 7 | "name" : "Env", 8 | "script" : "\/**\n * Author: GideonSenku\n * Github: https:\/\/github.com\/GideonSenku\n *\/\nmodule.exports = () => {\n return new(class {\n constructor() {\n this.request = new Request('')\n this.documentDirectory = FileManager.iCloud().documentsDirectory()\n this.defaultHeaders = {\n \"Accept\": \"application\/json\",\n \"Content-Type\": \"application\/json\"\n }\n }\n\n async get({ url, headers = {} }) {\n this.request.url = url\n this.request.method = 'GET'\n this.request.headers = {\n ...headers,\n ...this.defaultHeaders\n }\n return await this.request.loadJSON()\n }\n\n async getStr({ url, headers = {} }, callback = () => {}) {\n this.request.url = url\n this.request.method = 'GET'\n this.request.headers = {\n ...headers,\n ...this.defaultHeaders\n }\n const res = await this.request.loadString()\n callback(this.request.response)\n return res\n }\n\n async post({ url, body, headers = {} }) {\n this.request.url = url\n this.request.body = body ? JSON.stringify(body) : `{}`\n this.request.method = 'POST'\n this.request.headers = {\n ...headers,\n ...this.defaultHeaders\n }\n return await this.request.loadJSON()\n }\n \n async getFile({moduleName, url}) {\n const header = `\/\/ Variables used by Scriptable.\n\/\/ These must be at the very top of the file. Do not edit.\n\/\/ icon-color: deep-gray; icon-glyph: file-code;\\n`;\n const content = await this.getStr({ url })\n const fileHeader = content.includes('icon-color') ? `` : header\n this.writeFile(`${moduleName}`, `${fileHeader}${content}`)\n }\n \n async require({ moduleName, url = '', forceDownload = false }) {\n if (this.isFileExists(moduleName) && !forceDownload) {\n return importModule(moduleName)\n } else {\n await this.getFile({moduleName, url})\n return importModule(moduleName)\n }\n }\n\n writeFile(fileName, content) {\n let file = this.initFile(fileName)\n const filePath = `${this.documentDirectory}\/${file}`\n FileManager.iCloud().writeString(filePath, content)\n return true\n }\n \n isFileExists(fileName) {\n let file = this.initFile(fileName)\n return FileManager.iCloud().fileExists(`${this.documentDirectory}\/${file}`)\n }\n\n initFile(fileName) {\n const hasSuffix = fileName.lastIndexOf('.') + 1\n return !hasSuffix ? `${fileName}.js` : fileName\n }\n readFile(fileName) {\n const file = this.initFile(fileName)\n return FileManager.iCloud().readString(`${this.documentDirectory}\/${file}`)\n }\n\n })()\n}", 9 | "share_sheet_inputs" : [ 10 | 11 | ] 12 | } -------------------------------------------------------------------------------- /EnvExample.js: -------------------------------------------------------------------------------- 1 | // Variables used by Scriptable. 2 | // These must be at the very top of the file. Do not edit. 3 | // icon-color: pink; icon-glyph: keyboard; 4 | /** 5 | * Author: GideonSenku 6 | * Github: https://github.com/GideonSenku 7 | */ 8 | 9 | const { createWidget } = require("./Env") 10 | 11 | // init 12 | // importModule all of Env 13 | const $ = importModule('Env') 14 | /** 15 | * importModule part of Env 16 | * example: 17 | * get(opts) for HTTP GET Methods 18 | */ 19 | const { get, post, msg } = importModule('Env') 20 | 21 | msg('title','message','option') 22 | 23 | // require some file,if file is JS and support module you can use it dirtctly 24 | const opts = { 25 | moduleName: "vue", 26 | url: "https://cdn.jsdelivr.net/npm/vue@2.6.11" 27 | /** option:foreceDownload type:bool 28 | */ 29 | } 30 | 31 | const Vue = await $.require(opts) 32 | 33 | 34 | const fileName = $.initFile('Env') 35 | log(fileName) 36 | // wirteFile 37 | $.writeFile('nihao.txt',` 38 | const name = Senku, 39 | const age = 18 40 | const height = 1.88 41 | `) 42 | // readFile 43 | const filedata = $.readFile('nihao.txt') 44 | log(filedata) 45 | 46 | // getStr and callback headers 47 | const url = `https://github.com/GideonSenku/Scriptable/blob/master/READMEEN.md` 48 | const res = $.getStr({url},(headers) => { 49 | log(headers) 50 | }) 51 | 52 | log(res) 53 | 54 | 55 | // input, value为input的默认值,可选,默认为null 56 | 57 | const inputValue = await $.input('title', 'message', 'placehoder','value') 58 | const inputValue1 = await $.input('title', 'message', 'placehoder') 59 | 60 | 61 | /** 62 | * 63 | * 示例:$.time('yyyy-MM-dd qq HH:mm:ss.S') 64 | * :$.time('yyyyMMddHHmmssS') 65 | * y:年 M:月 d:日 q:季 H:时 m:分 s:秒 S:毫秒 66 | * 其中y可选0-4位占位符、S可选0-1位占位符,其余可选0-2位占位符 67 | * @param {*} fmt 格式化参数 68 | * @param {*} ts 时间戳 13位 69 | */ 70 | const time = $.time('yyyy-MM-dd HH:mm:ss') 71 | const time = $.time('MMdd HH:mm:ss',1599124137000) 72 | console.log(time) 73 | 74 | // 模版创建小组件 75 | await $.createWidget({ 76 | title: 'demo', // 必须 77 | texts: { // 可选 78 | one: '1', 79 | one0: '2', 80 | one1: '3', 81 | one2: '4', 82 | one3: '5', 83 | one4: '5', 84 | updateTime: 'true' // 可选参数,提供则添加更新时间线 85 | }, 86 | spacing: 1, // 可选参数,设置每行的间隙 87 | preview: 'large' // 可选参数,默认small,预览显小组件大小 88 | }) -------------------------------------------------------------------------------- /EnvExample.scriptable: -------------------------------------------------------------------------------- 1 | { 2 | "always_run_in_app" : false, 3 | "icon" : { 4 | "color" : "pink", 5 | "glyph" : "keyboard" 6 | }, 7 | "name" : "EnvExample", 8 | "script" : "\/**\n * Author: GideonSenku\n * Github: https:\/\/github.com\/GideonSenku\n *\/\n\n\/\/ init\nconst $ = new importModule('Env')()\n\/\/ require some file,if file is JS and support module you can use it dirtctly\nconst opts = {\n moduleName: \"vue\",\n url: \"https:\/\/cdn.jsdelivr.net\/npm\/vue@2.6.11\"\n \/** option:foreceDownload type:bool\n *\/\n}\nconst Vue = await $.require(opts)\nnew Vue({\n template:`\n

Hello,Vue<\/h1>\n `,\n data() {\n return {\n name: 'Senku',\n age: 18,\n height: '1.88'\n }\n },\n methods: {\n \n },\n computed: {\n \n },\n beforeCreate() {\n console.log(\"Vue beforeCreated\")\n }\n})\n\nconst fileName = $.initFile('Env')\nlog(fileName)\n\/\/ wirteFile\n$.writeFile('nihao.txt',`\nconst name = Senku,\nconst age = 18\nconst height = 1.88\n`)\n\/\/ readFile\nconst filedata = $.readFile('nihao.txt')\nlog(filedata)\n\n\/\/ getStr and callback headers\nconst url = `https:\/\/github.com\/GideonSenku\/Scriptable\/blob\/master\/READMEEN.md`\nconst res = $.getStr({url},(headers) => {\n log(headers)\n})\n\nlog(res)\n\n", 9 | "share_sheet_inputs" : [ 10 | 11 | ] 12 | } -------------------------------------------------------------------------------- /Install Scripts.js: -------------------------------------------------------------------------------- 1 | // Variables used by Scriptable. 2 | // These must be at the very top of the file. Do not edit. 3 | // icon-color: brown; icon-glyph: download; 4 | /** 5 | * Author: GideonSenku 6 | * Github: https://github.com/GideonSenku 7 | */ 8 | const scripts = [ 9 | { 10 | moduleName: "10010", 11 | url: 12 | "https://raw.githubusercontent.com/GideonSenku/Scriptable/master/10010/10010.js", 13 | }, 14 | { 15 | moduleName: "10086", 16 | url: 17 | "https://raw.githubusercontent.com/GideonSenku/Scriptable/master/10086/10086.js", 18 | }, 19 | { 20 | moduleName: "BilibiliMonitor", 21 | url: 22 | "https://raw.githubusercontent.com/evilbutcher/Scriptables/master/BilibiliMonitor.js", 23 | }, 24 | { 25 | moduleName: "RRShareMonitor", 26 | url: 27 | "https://raw.githubusercontent.com/evilbutcher/Scriptables/master/RRShareMonitor.js", 28 | }, 29 | { 30 | moduleName: "RSSMonitor", 31 | url: 32 | "https://raw.githubusercontent.com/evilbutcher/Scriptables/master/RSSMonitor.js", 33 | }, 34 | { 35 | moduleName: "WeiboMonitor", 36 | url: 37 | "https://raw.githubusercontent.com/evilbutcher/Scriptables/master/WeiboMonitor.js", 38 | }, 39 | { 40 | moduleName: "ZhihuMonitor", 41 | url: 42 | "https://raw.githubusercontent.com/evilbutcher/Scriptables/master/ZhihuMonitor.js", 43 | }, 44 | { 45 | moduleName: "DoubanMonitor", 46 | url: 47 | "https://raw.githubusercontent.com/evilbutcher/Scriptables/master/DoubanMonitor.js", 48 | }, 49 | { 50 | moduleName: "Env", 51 | url: 52 | "https://raw.githubusercontent.com/GideonSenku/Scriptable/master/Env.js", 53 | }, 54 | { 55 | moduleName: "Install Scripts", 56 | url: 57 | "https://raw.githubusercontent.com/GideonSenku/Scriptable/master/Install%20Scripts.js", 58 | }, 59 | { 60 | moduleName: "Checkin", 61 | url: 62 | "https://raw.githubusercontent.com/evilbutcher/Scriptables/master/Checkin.js", 63 | }, 64 | { 65 | moduleName: "Dler Cloud", 66 | url: 67 | "https://raw.githubusercontent.com/evilbutcher/Scriptables/master/Dler%20Cloud.js", 68 | }, 69 | { 70 | moduleName: "AppPriceMonitor", 71 | url: 72 | "https://raw.githubusercontent.com/evilbutcher/Scriptables/master/AppPriceMonitor.js", 73 | }, 74 | { 75 | moduleName: "北京尾号限行", 76 | url: 77 | "https://raw.githubusercontent.com/evilbutcher/Scriptables/master/%E5%8C%97%E4%BA%AC%E5%B0%BE%E5%8F%B7%E9%99%90%E8%A1%8C.js", 78 | }, 79 | ]; 80 | // Install Scripts.js 81 | const $ = importModule("Env"); 82 | function update() { 83 | log("🔔更新脚本开始!"); 84 | scripts.forEach((script) => { 85 | $.getFile(script); 86 | }); 87 | log("🔔更新脚本结束!"); 88 | } 89 | update(); 90 | -------------------------------------------------------------------------------- /NodeQuery/NodeQuery.js: -------------------------------------------------------------------------------- 1 | const $ = importModule("Env") 2 | 3 | let title = 'NodeQuery' 4 | const preview = 'small' // 预览大小 可选:small,medium,large 5 | const spacing = 3 // 间隙大小 6 | // 填入你自己NodeQuery的API 7 | const api = "" 8 | 9 | const res = await getinfo() 10 | await render() 11 | 12 | async function render() { 13 | // create and show widget 14 | if (config.runsInWidget) { 15 | let widget = await createWidget(res) 16 | Script.setWidget(widget) 17 | Script.complete() 18 | } else { 19 | await createWidget(res) 20 | } 21 | } 22 | 23 | async function createWidget(server) { 24 | title = server.name 25 | const infoLine = [] 26 | const load = server.load_percent 27 | const processes_array = server.processes_array 28 | const ram_total = Math.round(server.ram_total / Math.pow(1024, 2)) 29 | const ram_usage = Math.round(server.ram_usage / Math.pow(1024, 2)) 30 | const disk_total = Math.round(server.disk_total / Math.pow(1024, 3)) 31 | const disk_usage = Math.round(server.disk_usage / Math.pow(1024, 3)) 32 | const swap_total = Math.round(server.swap_total / Math.pow(1024, 2)) 33 | const swap_usage = Math.round(server.swap_usage / Math.pow(1024, 2)) 34 | infoLine[0] = `Load: ${load}%` 35 | infoLine[1] = `Swap: ${swap_usage}M of ${swap_total}M` 36 | infoLine[2] = `RAM: ${ram_usage}M of ${ram_total}M` 37 | infoLine[3] = `DISK: ${disk_usage}G of ${disk_total}G` 38 | processes_array.forEach(ele => { 39 | const command = ele.command.substr(0, 6) 40 | const count = ele.count 41 | const cpu = ele.cpu 42 | const memory = Math.round(ele.memory / Math.pow(1024, 2)) 43 | infoLine.push(`${command} ${count} ${cpu}% ${memory}M`) 44 | }) 45 | const opts = { 46 | title, 47 | texts: { 48 | Line0: infoLine[0], 49 | Line1: infoLine[1], 50 | Line2: infoLine[2], 51 | Line3: infoLine[3], 52 | Line4: infoLine[4], 53 | Line5: infoLine[5], 54 | Line6: infoLine[6] 55 | }, 56 | preview, 57 | spacing 58 | } 59 | let widget = await $.createWidget(opts) 60 | return widget 61 | } 62 | 63 | async function getid() { 64 | const url = "https://nodequery.com/api/servers?api_key=" + api 65 | const res = await $.get({ url }) 66 | const id = res?.data[0][0]?.id 67 | return id 68 | } 69 | 70 | async function getinfo() { 71 | const id = await getid() 72 | const url = `https://nodequery.com/api/servers/${id}?api_key=` + api 73 | const res = await $.get({ url }) 74 | return res?.data[0] 75 | } 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Scriptable 2 | 3 | [English](https://github.com/GideonSenku/Scriptable/blob/master/READMEEN.md) 4 | 5 | ## China Unicom Info && China Mobile Info 6 | 7 | > 2020.08.23 实现联通信息脚本 8 | > 2020.08.24 添加作者信息 9 | > 2020.08.26 实现移动信息脚本 10 | ### 食用方式 11 | 0. 前提你需要一个`Scriptable` [TestFlight地址](https://testflight.apple.com/join/uN1vTqxk) 12 | 1. 文件问题 13 | - 下载本仓库的`Env.js`和`Install Script.js`保存到`Scriptable`(记得将脚本命名为Env和Install Script) 14 | - `Install Script.js`可用作脚本的更新,不再需要手动复制本仓库代码 15 | 2. 修改`10010`脚本的个人数据 16 | - tel: 你的联通电话号码 17 | - VAL_loginheader: 来自BoxJs的数据`chavy_tokenheader_10010` 18 | 如果需要自动获取来自BoxJS的数据,请确保使用tf版本的BoxJS的重写 19 | 3. 添加小组件并选取`10010`脚本即可,效果图如下 20 | 4. 10086操作类似 21 | 5. [样式参考@mzeryck](https://github.com/mzeryck/Weather-Cal) 22 | 23 | 24 | 25 | ## 热门监控 26 | #### 知乎热榜、微博热搜、B站榜单、RSS、豆瓣、人人影视资源 27 | 作者[@evilbutcher](https://github.com/evilbutcher) 28 | ### 食用方式 29 | 0. 直接导入即可 30 | 1.部分脚本需要Config,点击[这里(模块)](https://github.com/evilbutcher/Scriptables/blob/master/Config.scriptable)或[这里(JS)](https://github.com/evilbutcher/Scriptables/blob/master/Config.js)安装。 31 | 32 | B站榜单[地址](https://github.com/GideonSenku/Scriptable/tree/master/Bilibili) 最好使用Config 33 | 豆瓣电影监控[地址](https://github.com/GideonSenku/Scriptable/tree/master/Douban) 34 | 人人影视资源[地址](https://github.com/GideonSenku/Scriptable/tree/master/RRShare) 35 | RSS监控[地址](https://github.com/GideonSenku/Scriptable/tree/master/RSS) 最好使用Config 36 | 微博热搜[地址](https://github.com/GideonSenku/Scriptable/tree/master/Weibo) 37 | 知乎热榜[地址](https://github.com/GideonSenku/Scriptable/tree/master/Zhihu) 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /READMEEN.md: -------------------------------------------------------------------------------- 1 | # Scriptable 2 | 3 | [English Version](https://github.com/GideonSenku/Scriptable/blob/master/READMEEN.md) 4 | 5 | ## China Unicom Info && China Mobile Info 6 | 7 | > 2020.08.23 First realization of China Unicom information script 8 | > 2020.08.24 Add author information 9 | ### How to Use 10 | 0. Prerequisite you need `Scriptable` [TestFlight地址](https://testflight.apple.com/join/uN1vTqxk) 11 | 1. About Files (choose any one as the solution) 12 | - Download `Env.js` and `10010.js` and save to `Scriptable`(Remember to name the script to "Env" and "10010") 13 | - Download `Env.scriptable` and `10010.scriptable`, import to `Scriptable` 14 | - The difference between the above two is whether the icon and file name need to be manually changed 15 | 2. Modify `10010`'s data 16 | - tel: Your China Unicom phone number 17 | - VAL_loginheader: Data from BoxJs `chavy_tokenheader_10010` 18 | 19 | 3. 10010 Widget style reference[@spencerwooo](https://gist.github.com/spencerwooo/7955aefc4ffa5bc8ae7c83d85d05e7a4) 20 | 4. Add widget and select the `10010` script, the rendering is as follows 21 | 22 | 23 | 24 | 25 | 26 | ## Hotlist Monitor 27 | #### Zhihu Weibo Bilibili RSS Douban RRShare 28 | Author [@evilbutcher](https://github.com/evilbutcher) 29 | ### How to Use 30 | 0. Import directly 31 | 1.Some script need Config,Click [here(Module)](https://github.com/evilbutcher/Scriptables/blob/master/Config.scriptable)or[here(JS)](https://github.com/evilbutcher/Scriptables/blob/master/Config.js) to install. 32 | 33 | Bilibili[link](https://github.com/GideonSenku/Scriptable/tree/master/Bilibili) Use Config would be beter. 34 | Douban[link](https://github.com/GideonSenku/Scriptable/tree/master/Douban) 35 | RRShare[link](https://github.com/GideonSenku/Scriptable/tree/master/RRShare) 36 | RSS[link](https://github.com/GideonSenku/Scriptable/tree/master/RSS) Use Config would be beter. 37 | Weibo[link](https://github.com/GideonSenku/Scriptable/tree/master/Weibo) 38 | Zhihu[link](https://github.com/GideonSenku/Scriptable/tree/master/Zhihu) 39 | 40 | -------------------------------------------------------------------------------- /RRShare/RRShareMonitor.js: -------------------------------------------------------------------------------- 1 | // Variables used by Scriptable. 2 | // These must be at the very top of the file. Do not edit. 3 | // icon-color: blue; icon-glyph: film; 4 | /* 5 | * Author: evilbutcher 6 | * Github: https://github.com/evilbutcher 7 | * 本脚本使用了@Gideon_Senku的Env.scriptable,感谢! 8 | */ 9 | const goupdate = true; 10 | const $ = importModule("Env"); 11 | var num = 6; //自定义显示数量 12 | var rancolor = true; //true为开启随机颜色 13 | 14 | try { 15 | var { rrnum, rrrancolor } = importModule("Config"); 16 | num = rrnum(); 17 | rancolor = rrrancolor(); 18 | console.log("将使用配置文件内人人影视配置"); 19 | } catch (e) { 20 | console.log("将使用脚本内人人影视配置"); 21 | } 22 | 23 | const res = await getinfo(); 24 | 25 | let widget = createWidget(res); 26 | Script.setWidget(widget); 27 | Script.complete(); 28 | 29 | function createWidget(res) { 30 | items = []; 31 | for (var i = 0; i < num; i++) { 32 | var item = res[i]["file_name"]; 33 | items.push(item); 34 | } 35 | console.log(items); 36 | 37 | const w = new ListWidget(); 38 | const bgColor = new LinearGradient(); 39 | bgColor.colors = [new Color("#1c1c1c"), new Color("#29323c")]; 40 | bgColor.locations = [0.0, 1.0]; 41 | w.backgroundGradient = bgColor; 42 | w.addSpacer(); 43 | w.spacing = 5; 44 | 45 | const firstLine = w.addText(`🎬人人影视`); 46 | firstLine.textSize = 15; 47 | firstLine.textColor = Color.white(); 48 | firstLine.textOpacity = 0.7; 49 | 50 | for (var i = 0; i < items.length; i++) { 51 | addTextToListWidget(`• ${items[i]}`, w); 52 | } 53 | 54 | w.addSpacer(); 55 | w.spacing = 5; 56 | w.presentSmall(); 57 | return w; 58 | } 59 | 60 | async function getinfo() { 61 | const zmzRequest = { 62 | url: `http://file.apicvn.com/file/list?page=1&order=create_time&sort=desc`, 63 | headers: { 64 | Host: "file.apicvn.com", 65 | "Content-Type": "application/x-www-form-urlencoded", 66 | "User-Agent": "Mozilla/5.0", 67 | }, 68 | }; 69 | const res = await $.get(zmzRequest); 70 | log(res); 71 | return res; 72 | } 73 | 74 | function addTextToListWidget(text, listWidget) { 75 | let item = listWidget.addText(text); 76 | if (rancolor == true) { 77 | item.textColor = new Color(color16()); 78 | } else { 79 | item.textColor = Color.white(); 80 | } 81 | item.textSize = 12; 82 | } 83 | 84 | function color16() { 85 | var r = Math.floor(Math.random() * 256); 86 | if (r + 50 < 255) { 87 | r = r + 50; 88 | } 89 | if (r > 230 && r < 255) { 90 | r = r - 50; 91 | } 92 | var g = Math.floor(Math.random() * 256); 93 | if (g + 50 < 255) { 94 | g = g + 50; 95 | } 96 | if (g > 230 && g < 255) { 97 | g = g - 50; 98 | } 99 | var b = Math.floor(Math.random() * 256); 100 | if (b + 50 < 255) { 101 | b = b + 50; 102 | } 103 | if (b > 230 && b < 255) { 104 | b = b - 50; 105 | } 106 | var color = "#" + r.toString(16) + g.toString(16) + b.toString(16); 107 | return color; 108 | } 109 | 110 | //更新代码 111 | function update() { 112 | log("🔔更新脚本开始!"); 113 | scripts.forEach(async (script) => { 114 | await $.getFile(script); 115 | }); 116 | log("🔔更新脚本结束!"); 117 | } 118 | 119 | const scripts = [ 120 | { 121 | moduleName: "RRShareMonitor", 122 | url: 123 | "https://raw.githubusercontent.com/evilbutcher/Scriptables/master/RRShareMonitor.js", 124 | }, 125 | ]; 126 | if (goupdate == true) update(); 127 | -------------------------------------------------------------------------------- /RSS/RSSMonitor.js: -------------------------------------------------------------------------------- 1 | // Variables used by Scriptable. 2 | // These must be at the very top of the file. Do not edit. 3 | // icon-color: deep-green; icon-glyph: rss; 4 | /* 5 | * Author: evilbutcher 6 | * Github: https://github.com/evilbutcher 7 | * 本脚本使用了@Gideon_Senku的Env.scriptable,感谢! 8 | */ 9 | const goupdate = true; //默认关闭,需要更新时请手动打开 10 | const $ = importModule("Env"); 11 | var num = 6; //自定义显示数量 12 | var rancolor = true; //true为开启随机颜色 13 | // 填写RSS订阅链接,默认为仓库的最近Commit 14 | // Fill in the RSS subscription link, the default is the latest Commit of the Repo 15 | var rsslink = "https://github.com/GideonSenku/Scriptable/commits/master.atom"; 16 | try { 17 | const con = importModule("Config"); 18 | num = con.rssnum(); 19 | rancolor = con.rssrancolor(); 20 | rsslink = con.rsslink(); 21 | console.log("将使用配置文件内RSS配置"); 22 | } catch (e) { 23 | console.log("将使用脚本内RSS配置"); 24 | } 25 | 26 | const res = await getinfo(); 27 | 28 | let widget = createWidget(res); 29 | Script.setWidget(widget); 30 | Script.complete(); 31 | 32 | function createWidget(res) { 33 | if (res.status == "ok") { 34 | var titlerss = res.feed.title; 35 | var group = res.items; 36 | items = []; 37 | for (var i = 0; i < num; i++) { 38 | var item = group[i].title; 39 | items.push(item); 40 | } 41 | console.log(items); 42 | 43 | const w = new ListWidget(); 44 | const bgColor = new LinearGradient(); 45 | bgColor.colors = [new Color("#1c1c1c"), new Color("#29323c")]; 46 | bgColor.locations = [0.0, 1.0]; 47 | w.backgroundGradient = bgColor; 48 | w.addSpacer(); 49 | w.spacing = 5; 50 | 51 | const firstLine = w.addText(`📻${titlerss}`); 52 | firstLine.textSize = 15; 53 | firstLine.textColor = Color.white(); 54 | firstLine.textOpacity = 0.7; 55 | 56 | for (var i = 0; i < items.length; i++) { 57 | addTextToListWidget(`• ${items[i]}`, w); 58 | } 59 | 60 | w.addSpacer(); 61 | w.spacing = 5; 62 | w.presentSmall(); 63 | return w; 64 | } 65 | } 66 | 67 | async function getinfo() { 68 | const rssRequest = { 69 | url: 70 | "https://api.rss2json.com/v1/api.json?rss_url=" + 71 | encodeURIComponent(rsslink), 72 | }; 73 | const res = await $.get(rssRequest); 74 | log(res); 75 | return res; 76 | } 77 | 78 | function addTextToListWidget(text, listWidget) { 79 | let item = listWidget.addText(text); 80 | if (rancolor == true) { 81 | item.textColor = new Color(color16()); 82 | } else { 83 | item.textColor = Color.white(); 84 | } 85 | item.textSize = 12; 86 | } 87 | 88 | function color16() { 89 | var r = Math.floor(Math.random() * 256); 90 | if (r + 50 < 255) { 91 | r = r + 50; 92 | } 93 | if (r > 230 && r < 255) { 94 | r = r - 50; 95 | } 96 | var g = Math.floor(Math.random() * 256); 97 | if (g + 50 < 255) { 98 | g = g + 50; 99 | } 100 | if (g > 230 && g < 255) { 101 | g = g - 50; 102 | } 103 | var b = Math.floor(Math.random() * 256); 104 | if (b + 50 < 255) { 105 | b = b + 50; 106 | } 107 | if (b > 230 && b < 255) { 108 | b = b - 50; 109 | } 110 | var color = "#" + r.toString(16) + g.toString(16) + b.toString(16); 111 | return color; 112 | } 113 | 114 | //更新代码 115 | function update() { 116 | log("🔔更新脚本开始!"); 117 | scripts.forEach(async (script) => { 118 | await $.getFile(script); 119 | }); 120 | log("🔔更新脚本结束!"); 121 | } 122 | 123 | const scripts = [ 124 | { 125 | moduleName: "RSSMonitor", 126 | url: 127 | "https://raw.githubusercontent.com/evilbutcher/Scriptables/master/RSSMonitor.js", 128 | }, 129 | ]; 130 | if (goupdate == true) update(); 131 | -------------------------------------------------------------------------------- /SNKRS/SNKRS.js: -------------------------------------------------------------------------------- 1 | // Variables used by Scriptable. 2 | // These must be at the very top of the file. Do not edit. 3 | // icon-color: red; icon-glyph: shoe-prints; 4 | /** 5 | * Author: GideonSenku evilbutcher 6 | * Github: https://github.com/GideonSenku 7 | */ 8 | 9 | const $ = importModule("Env") 10 | 11 | const title = 'SNKRS' 12 | const preview = 'medium' // 预览大小 可选:small,medium,large 13 | const spacing = 5 // 间隙大小 14 | 15 | const res = await getinfo() 16 | await render() 17 | 18 | async function render() { 19 | // create and show widget 20 | if (config.runsInWidget) { 21 | let widget = await createWidget(res) 22 | Script.setWidget(widget) 23 | Script.complete() 24 | } else { 25 | await createWidget(res) 26 | } 27 | } 28 | 29 | async function createWidget(res) { 30 | // 标签: res[0].productInfo[0].merchProduct.labelName 31 | // 价格: res[0].productInfo[0].merchPrice.currentPrice 32 | // 发布时间: res[0].productInfo[0].launchView.startEntryDate.substr(0, 10) 33 | const infoLine = [] 34 | for (const product of res) { 35 | const date = product?.productInfo[0]?.launchView.startEntryDate.slice(5, 10) 36 | const labelName = product.productInfo[0].merchProduct.labelName 37 | const price = product.productInfo[0].merchPrice.currentPrice 38 | const Line = `• ${date} ${labelName} ¥${price}` 39 | infoLine.push(Line) 40 | } 41 | const opts = { 42 | title, 43 | texts: { 44 | Line0: infoLine[0], 45 | Line1: infoLine[1], 46 | Line2: infoLine[2], 47 | Line3: infoLine[3], 48 | Line4: infoLine[4], 49 | Line5: infoLine[5], 50 | battery: 'true' 51 | }, 52 | preview, 53 | spacing 54 | } 55 | let widget = await $.createWidget(opts) 56 | return widget 57 | } 58 | 59 | async function getinfo() { 60 | const url = { 61 | url: `https://api.nike.com/product_feed/threads/v2/?anchor=0&count=36&filter=marketplace%28CN%29&filter=language%28zh-Hans%29&filter=upcoming%28true%29&filter=channelId%28010794e5-35fe-4e32-aaff-cd2c74f89d61%29&filter=exclusiveAccess%28true%2Cfalse%29&sort=effectiveStartSellDateAsc&fields=active%2Cid%2ClastFetchTime%2CproductInfo%2CpublishedContent.nodes%2CpublishedContent.subType%2CpublishedContent.properties.coverCard%2CpublishedContent.properties.productCard%2CpublishedContent.properties.products%2CpublishedContent.properties.publish.collections%2CpublishedContent.properties.relatedThreads%2CpublishedContent.properties.seo%2CpublishedContent.properties.threadType%2CpublishedContent.properties.custom%2CpublishedContent.properties.title`, 62 | } 63 | const res = await $.get(url) 64 | return res.objects 65 | } -------------------------------------------------------------------------------- /Weibo/WeiboMonitor.js: -------------------------------------------------------------------------------- 1 | // Variables used by Scriptable. 2 | // These must be at the very top of the file. Do not edit. 3 | // icon-color: yellow; icon-glyph: fire; 4 | /* 5 | * Author: evilbutcher 6 | * Github: https://github.com/evilbutcher 7 | * 本脚本使用了@Gideon_Senku的Env.scriptable,感谢! 8 | */ 9 | const goupdate = true; 10 | const $ = importModule("Env"); 11 | var num = 6; //自定义显示数量 12 | var rancolor = true; //true为开启随机颜色 13 | 14 | try { 15 | var { wbnum, wbrancolor } = importModule("Config"); 16 | num = wbnum(); 17 | rancolor = wbrancolor(); 18 | console.log("将使用配置文件内微博配置"); 19 | } catch (e) { 20 | console.log("将使用脚本内微博配置"); 21 | } 22 | 23 | const res = await getinfo(); 24 | 25 | let widget = createWidget(res); 26 | Script.setWidget(widget); 27 | Script.complete(); 28 | 29 | function createWidget(res) { 30 | if (res.data.cards[0].title == "实时热点,每分钟更新一次") { 31 | var group = res.data.cards[0]["card_group"]; 32 | items = []; 33 | for (var i = 0; i < num; i++) { 34 | var item = group[i].desc; 35 | items.push(item); 36 | } 37 | console.log(items); 38 | 39 | const w = new ListWidget(); 40 | const bgColor = new LinearGradient(); 41 | bgColor.colors = [new Color("#1c1c1c"), new Color("#29323c")]; 42 | bgColor.locations = [0.0, 1.0]; 43 | w.backgroundGradient = bgColor; 44 | w.addSpacer(); 45 | w.spacing = 5; 46 | 47 | const firstLine = w.addText(`🔥微博热搜`); 48 | firstLine.textSize = 15; 49 | firstLine.textColor = Color.white(); 50 | firstLine.textOpacity = 0.7; 51 | 52 | const top1Line = w.addText(`📌 ${items[0]}`); 53 | top1Line.textSize = 12; 54 | top1Line.textColor = Color.white(); 55 | 56 | for (var i = 1; i < items.length; i++) { 57 | addTextToListWidget(`• ${items[i]}`, w); 58 | } 59 | 60 | w.addSpacer(); 61 | w.spacing = 5; 62 | w.presentSmall(); 63 | return w; 64 | } 65 | } 66 | 67 | async function getinfo() { 68 | const url = { 69 | url: 70 | "https://m.weibo.cn/api/container/getIndex?containerid=106003%26filter_type%3Drealtimehot", 71 | }; 72 | const res = await $.get(url); 73 | log(res); 74 | return res; 75 | } 76 | 77 | function addTextToListWidget(text, listWidget) { 78 | let item = listWidget.addText(text); 79 | if (rancolor == true) { 80 | item.textColor = new Color(color16()); 81 | } else { 82 | item.textColor = Color.white(); 83 | } 84 | item.textSize = 12; 85 | } 86 | 87 | function color16() { 88 | var r = Math.floor(Math.random() * 256); 89 | if (r + 50 < 255) { 90 | r = r + 50; 91 | } 92 | if (r > 230 && r < 255) { 93 | r = r - 50; 94 | } 95 | var g = Math.floor(Math.random() * 256); 96 | if (g + 50 < 255) { 97 | g = g + 50; 98 | } 99 | if (g > 230 && g < 255) { 100 | g = g - 50; 101 | } 102 | var b = Math.floor(Math.random() * 256); 103 | if (b + 50 < 255) { 104 | b = b + 50; 105 | } 106 | if (b > 230 && b < 255) { 107 | b = b - 50; 108 | } 109 | var color = "#" + r.toString(16) + g.toString(16) + b.toString(16); 110 | return color; 111 | } 112 | 113 | //更新代码 114 | function update() { 115 | log("🔔更新脚本开始!"); 116 | scripts.forEach(async (script) => { 117 | await $.getFile(script); 118 | }); 119 | log("🔔更新脚本结束!"); 120 | } 121 | 122 | const scripts = [ 123 | { 124 | moduleName: "WeiboMonitor", 125 | url: 126 | "https://raw.githubusercontent.com/evilbutcher/Scriptables/master/WeiboMonitor.js", 127 | }, 128 | ]; 129 | if (goupdate == true) update(); 130 | -------------------------------------------------------------------------------- /Zhihu/ZhihuMonitor.js: -------------------------------------------------------------------------------- 1 | // Variables used by Scriptable. 2 | // These must be at the very top of the file. Do not edit. 3 | // icon-color: deep-blue; icon-glyph: book-open; 4 | /* 5 | * Author: evilbutcher 6 | * Github: https://github.com/evilbutcher 7 | * 本脚本使用了@Gideon_Senku的Env.scriptable,感谢! 8 | */ 9 | const goupdate = true; 10 | const $ = importModule("Env"); 11 | var num = 6; //自定义显示数量 12 | var rancolor = true; //true为开启随机颜色 13 | 14 | try { 15 | var { zhnum, zhrancolor } = importModule("Config"); 16 | num = zhnum(); 17 | rancolor = zhrancolor(); 18 | console.log("将使用配置文件内知乎配置"); 19 | } catch (e) { 20 | console.log("将使用脚本内知乎配置"); 21 | } 22 | 23 | const res = await getinfo(); 24 | 25 | let widget = createWidget(res); 26 | Script.setWidget(widget); 27 | Script.complete(); 28 | 29 | function createWidget(res) { 30 | if (res.fresh_text == "热榜已更新") { 31 | var group = res.data; 32 | items = []; 33 | for (var i = 0; i < num; i++) { 34 | var item = group[i].target.title; 35 | items.push(item); 36 | } 37 | console.log(items); 38 | 39 | const w = new ListWidget(); 40 | const bgColor = new LinearGradient(); 41 | bgColor.colors = [new Color("#1c1c1c"), new Color("#29323c")]; 42 | bgColor.locations = [0.0, 1.0]; 43 | w.backgroundGradient = bgColor; 44 | w.addSpacer(); 45 | w.spacing = 5; 46 | 47 | const firstLine = w.addText(`📖知乎热榜`); 48 | firstLine.textSize = 15; 49 | firstLine.textColor = Color.white(); 50 | firstLine.textOpacity = 0.7; 51 | 52 | for (var i = 0; i < items.length; i++) { 53 | addTextToListWidget(`• ${items[i]}`, w); 54 | } 55 | 56 | w.addSpacer(); 57 | w.spacing = 5; 58 | w.presentSmall(); 59 | return w; 60 | } 61 | } 62 | 63 | async function getinfo() { 64 | const url = { 65 | url: `https://api.zhihu.com/topstory/hot-lists/total?limit=10&reverse_order=0`, 66 | }; 67 | const res = await $.get(url); 68 | log(res); 69 | return res; 70 | } 71 | 72 | function addTextToListWidget(text, listWidget) { 73 | let item = listWidget.addText(text); 74 | if (rancolor == true) { 75 | item.textColor = new Color(color16()); 76 | } else { 77 | item.textColor = Color.white(); 78 | } 79 | item.textSize = 12; 80 | } 81 | 82 | function color16() { 83 | var r = Math.floor(Math.random() * 256); 84 | if (r + 50 < 255) { 85 | r = r + 50; 86 | } 87 | if (r > 230 && r < 255) { 88 | r = r - 50; 89 | } 90 | var g = Math.floor(Math.random() * 256); 91 | if (g + 50 < 255) { 92 | g = g + 50; 93 | } 94 | if (g > 230 && g < 255) { 95 | g = g - 50; 96 | } 97 | var b = Math.floor(Math.random() * 256); 98 | if (b + 50 < 255) { 99 | b = b + 50; 100 | } 101 | if (b > 230 && b < 255) { 102 | b = b - 50; 103 | } 104 | var color = "#" + r.toString(16) + g.toString(16) + b.toString(16); 105 | return color; 106 | } 107 | 108 | //更新代码 109 | function update() { 110 | log("🔔更新脚本开始!"); 111 | scripts.forEach(async (script) => { 112 | await $.getFile(script); 113 | }); 114 | log("🔔更新脚本结束!"); 115 | } 116 | 117 | const scripts = [ 118 | { 119 | moduleName: "ZhihuMonitor", 120 | url: 121 | "https://raw.githubusercontent.com/evilbutcher/Scriptables/master/ZhihuMonitor.js", 122 | }, 123 | ]; 124 | if (goupdate == true) update(); 125 | -------------------------------------------------------------------------------- /crypto-js.min.js: -------------------------------------------------------------------------------- 1 | (function(t,e){"object"==typeof exports?module.exports=exports=e():"function"==typeof define&&define.amd?define([],e):t.CryptoJS=e()})(this,function(){var t,e,r,i,n,o,s,c,a,h,l=l||function(t,e){var r;if("undefined"!=typeof window&&window.crypto&&(r=window.crypto),!r&&"undefined"!=typeof window&&window.msCrypto&&(r=window.msCrypto),!r&&"undefined"!=typeof global&&global.crypto&&(r=global.crypto),!r&&"function"==typeof require)try{r=require("crypto")}catch(t){}var i=function(){if(r){if("function"==typeof r.getRandomValues)try{return r.getRandomValues(new Uint32Array(1))[0]}catch(t){}if("function"==typeof r.randomBytes)try{return r.randomBytes(4).readInt32LE()}catch(t){}}throw new Error("Native crypto module could not be used to get secure random number.")},n=Object.create||function(){function t(){}return function(e){var r;return t.prototype=e,r=new t,t.prototype=null,r}}(),o={},s=o.lib={},c=s.Base={extend:function(t){var e=n(this);return t&&e.mixIn(t),e.hasOwnProperty("init")&&this.init!==e.init||(e.init=function(){e.$super.init.apply(this,arguments)}),e.init.prototype=e,e.$super=this,e},create:function(){var t=this.extend();return t.init.apply(t,arguments),t},init:function(){},mixIn:function(t){for(var e in t)t.hasOwnProperty(e)&&(this[e]=t[e]);t.hasOwnProperty("toString")&&(this.toString=t.toString)},clone:function(){return this.init.prototype.extend(this)}},a=s.WordArray=c.extend({init:function(t,r){t=this.words=t||[],this.sigBytes=r!=e?r:4*t.length},toString:function(t){return(t||l).stringify(this)},concat:function(t){var e=this.words,r=t.words,i=this.sigBytes,n=t.sigBytes;if(this.clamp(),i%4)for(var o=0;o>>2]>>>24-o%4*8&255;e[i+o>>>2]|=s<<24-(i+o)%4*8}else for(o=0;o>>2]=r[o>>>2];return this.sigBytes+=n,this},clamp:function(){var e=this.words,r=this.sigBytes;e[r>>>2]&=4294967295<<32-r%4*8,e.length=t.ceil(r/4)},clone:function(){var t=c.clone.call(this);return t.words=this.words.slice(0),t},random:function(t){for(var e=[],r=0;r>>2]>>>24-n%4*8&255;i.push((o>>>4).toString(16)),i.push((15&o).toString(16))}return i.join("")},parse:function(t){for(var e=t.length,r=[],i=0;i>>3]|=parseInt(t.substr(i,2),16)<<24-i%8*4;return new a.init(r,e/2)}},f=h.Latin1={stringify:function(t){for(var e=t.words,r=t.sigBytes,i=[],n=0;n>>2]>>>24-n%4*8&255;i.push(String.fromCharCode(o))}return i.join("")},parse:function(t){for(var e=t.length,r=[],i=0;i>>2]|=(255&t.charCodeAt(i))<<24-i%4*8;return new a.init(r,e)}},u=h.Utf8={stringify:function(t){try{return decodeURIComponent(escape(f.stringify(t)))}catch(t){throw new Error("Malformed UTF-8 data")}},parse:function(t){return f.parse(unescape(encodeURIComponent(t)))}},d=s.BufferedBlockAlgorithm=c.extend({reset:function(){this._data=new a.init,this._nDataBytes=0},_append:function(t){"string"==typeof t&&(t=u.parse(t)),this._data.concat(t),this._nDataBytes+=t.sigBytes},_process:function(e){var r,i=this._data,n=i.words,o=i.sigBytes,s=this.blockSize,c=4*s,h=o/c;h=e?t.ceil(h):t.max((0|h)-this._minBufferSize,0);var l=h*s,f=t.min(4*l,o);if(l){for(var u=0;u>>6-s%4*2,h=c|a;n[o>>>2]|=h<<24-o%4*8,o++}return i.create(n,o)}var e=l,r=e.lib,i=r.WordArray,n=e.enc;n.Base64={stringify:function(t){var e=t.words,r=t.sigBytes,i=this._map;t.clamp();for(var n=[],o=0;o>>2]>>>24-o%4*8&255,c=e[o+1>>>2]>>>24-(o+1)%4*8&255,a=e[o+2>>>2]>>>24-(o+2)%4*8&255,h=s<<16|c<<8|a,l=0;l<4&&o+.75*l>>6*(3-l)&63));var f=i.charAt(64);if(f)for(;n.length%4;)n.push(f);return n.join("")},parse:function(e){var r=e.length,i=this._map,n=this._reverseMap;if(!n){n=this._reverseMap=[];for(var o=0;o>>32-o)+e}function r(t,e,r,i,n,o,s){var c=t+(e&i|r&~i)+n+s;return(c<>>32-o)+e}function i(t,e,r,i,n,o,s){var c=t+(e^r^i)+n+s;return(c<>>32-o)+e}function n(t,e,r,i,n,o,s){var c=t+(r^(e|~i))+n+s;return(c<>>32-o)+e}var o=l,s=o.lib,c=s.WordArray,a=s.Hasher,h=o.algo,f=[];(function(){for(var e=0;e<64;e++)f[e]=4294967296*t.abs(t.sin(e+1))|0})();var u=h.MD5=a.extend({_doReset:function(){this._hash=new c.init([1732584193,4023233417,2562383102,271733878])},_doProcessBlock:function(t,o){for(var s=0;s<16;s++){var c=o+s,a=t[c];t[c]=16711935&(a<<8|a>>>24)|4278255360&(a<<24|a>>>8)}var h=this._hash.words,l=t[o+0],u=t[o+1],d=t[o+2],p=t[o+3],_=t[o+4],v=t[o+5],y=t[o+6],g=t[o+7],B=t[o+8],w=t[o+9],k=t[o+10],S=t[o+11],m=t[o+12],x=t[o+13],b=t[o+14],H=t[o+15],z=h[0],A=h[1],C=h[2],D=h[3];z=e(z,A,C,D,l,7,f[0]),D=e(D,z,A,C,u,12,f[1]),C=e(C,D,z,A,d,17,f[2]),A=e(A,C,D,z,p,22,f[3]),z=e(z,A,C,D,_,7,f[4]),D=e(D,z,A,C,v,12,f[5]),C=e(C,D,z,A,y,17,f[6]),A=e(A,C,D,z,g,22,f[7]),z=e(z,A,C,D,B,7,f[8]),D=e(D,z,A,C,w,12,f[9]),C=e(C,D,z,A,k,17,f[10]),A=e(A,C,D,z,S,22,f[11]),z=e(z,A,C,D,m,7,f[12]),D=e(D,z,A,C,x,12,f[13]),C=e(C,D,z,A,b,17,f[14]),A=e(A,C,D,z,H,22,f[15]),z=r(z,A,C,D,u,5,f[16]),D=r(D,z,A,C,y,9,f[17]),C=r(C,D,z,A,S,14,f[18]),A=r(A,C,D,z,l,20,f[19]),z=r(z,A,C,D,v,5,f[20]),D=r(D,z,A,C,k,9,f[21]),C=r(C,D,z,A,H,14,f[22]),A=r(A,C,D,z,_,20,f[23]),z=r(z,A,C,D,w,5,f[24]),D=r(D,z,A,C,b,9,f[25]),C=r(C,D,z,A,p,14,f[26]),A=r(A,C,D,z,B,20,f[27]),z=r(z,A,C,D,x,5,f[28]),D=r(D,z,A,C,d,9,f[29]),C=r(C,D,z,A,g,14,f[30]),A=r(A,C,D,z,m,20,f[31]),z=i(z,A,C,D,v,4,f[32]),D=i(D,z,A,C,B,11,f[33]),C=i(C,D,z,A,S,16,f[34]),A=i(A,C,D,z,b,23,f[35]),z=i(z,A,C,D,u,4,f[36]),D=i(D,z,A,C,_,11,f[37]),C=i(C,D,z,A,g,16,f[38]),A=i(A,C,D,z,k,23,f[39]),z=i(z,A,C,D,x,4,f[40]),D=i(D,z,A,C,l,11,f[41]),C=i(C,D,z,A,p,16,f[42]),A=i(A,C,D,z,y,23,f[43]),z=i(z,A,C,D,w,4,f[44]),D=i(D,z,A,C,m,11,f[45]),C=i(C,D,z,A,H,16,f[46]),A=i(A,C,D,z,d,23,f[47]),z=n(z,A,C,D,l,6,f[48]),D=n(D,z,A,C,g,10,f[49]),C=n(C,D,z,A,b,15,f[50]),A=n(A,C,D,z,v,21,f[51]),z=n(z,A,C,D,m,6,f[52]),D=n(D,z,A,C,p,10,f[53]),C=n(C,D,z,A,k,15,f[54]),A=n(A,C,D,z,u,21,f[55]),z=n(z,A,C,D,B,6,f[56]),D=n(D,z,A,C,H,10,f[57]),C=n(C,D,z,A,y,15,f[58]),A=n(A,C,D,z,x,21,f[59]),z=n(z,A,C,D,_,6,f[60]),D=n(D,z,A,C,S,10,f[61]),C=n(C,D,z,A,d,15,f[62]),A=n(A,C,D,z,w,21,f[63]),h[0]=h[0]+z|0,h[1]=h[1]+A|0,h[2]=h[2]+C|0,h[3]=h[3]+D|0},_doFinalize:function(){var e=this._data,r=e.words,i=8*this._nDataBytes,n=8*e.sigBytes;r[n>>>5]|=128<<24-n%32;var o=t.floor(i/4294967296),s=i;r[15+(n+64>>>9<<4)]=16711935&(o<<8|o>>>24)|4278255360&(o<<24|o>>>8),r[14+(n+64>>>9<<4)]=16711935&(s<<8|s>>>24)|4278255360&(s<<24|s>>>8),e.sigBytes=4*(r.length+1),this._process();for(var c=this._hash,a=c.words,h=0;h<4;h++){var l=a[h];a[h]=16711935&(l<<8|l>>>24)|4278255360&(l<<24|l>>>8)}return c},clone:function(){var t=a.clone.call(this);return t._hash=this._hash.clone(),t}});o.MD5=a._createHelper(u),o.HmacMD5=a._createHmacHelper(u)}(Math),t=l,e=t.lib,r=e.WordArray,i=e.Hasher,n=t.algo,o=[],s=n.SHA1=i.extend({_doReset:function(){this._hash=new r.init([1732584193,4023233417,2562383102,271733878,3285377520])},_doProcessBlock:function(t,e){for(var r=this._hash.words,i=r[0],n=r[1],s=r[2],c=r[3],a=r[4],h=0;h<80;h++){if(h<16)o[h]=0|t[e+h];else{var l=o[h-3]^o[h-8]^o[h-14]^o[h-16];o[h]=l<<1|l>>>31}var f=(i<<5|i>>>27)+a+o[h];f+=h<20?1518500249+(n&s|~n&c):h<40?1859775393+(n^s^c):h<60?(n&s|n&c|s&c)-1894007588:(n^s^c)-899497514,a=c,c=s,s=n<<30|n>>>2,n=i,i=f}r[0]=r[0]+i|0,r[1]=r[1]+n|0,r[2]=r[2]+s|0,r[3]=r[3]+c|0,r[4]=r[4]+a|0},_doFinalize:function(){var t=this._data,e=t.words,r=8*this._nDataBytes,i=8*t.sigBytes;return e[i>>>5]|=128<<24-i%32,e[14+(i+64>>>9<<4)]=Math.floor(r/4294967296),e[15+(i+64>>>9<<4)]=r,t.sigBytes=4*e.length,this._process(),this._hash},clone:function(){var t=i.clone.call(this);return t._hash=this._hash.clone(),t}}),t.SHA1=i._createHelper(s),t.HmacSHA1=i._createHmacHelper(s),function(t){var e=l,r=e.lib,i=r.WordArray,n=r.Hasher,o=e.algo,s=[],c=[];(function(){function e(e){for(var r=t.sqrt(e),i=2;i<=r;i++)if(!(e%i))return!1;return!0}function r(t){return 4294967296*(t-(0|t))|0}for(var i=2,n=0;n<64;)e(i)&&(n<8&&(s[n]=r(t.pow(i,.5))),c[n]=r(t.pow(i,1/3)),n++),i++})();var a=[],h=o.SHA256=n.extend({_doReset:function(){this._hash=new i.init(s.slice(0))},_doProcessBlock:function(t,e){for(var r=this._hash.words,i=r[0],n=r[1],o=r[2],s=r[3],h=r[4],l=r[5],f=r[6],u=r[7],d=0;d<64;d++){if(d<16)a[d]=0|t[e+d];else{var p=a[d-15],_=(p<<25|p>>>7)^(p<<14|p>>>18)^p>>>3,v=a[d-2],y=(v<<15|v>>>17)^(v<<13|v>>>19)^v>>>10;a[d]=_+a[d-7]+y+a[d-16]}var g=h&l^~h&f,B=i&n^i&o^n&o,w=(i<<30|i>>>2)^(i<<19|i>>>13)^(i<<10|i>>>22),k=(h<<26|h>>>6)^(h<<21|h>>>11)^(h<<7|h>>>25),S=u+k+g+c[d]+a[d],m=w+B;u=f,f=l,l=h,h=s+S|0,s=o,o=n,n=i,i=S+m|0}r[0]=r[0]+i|0,r[1]=r[1]+n|0,r[2]=r[2]+o|0,r[3]=r[3]+s|0,r[4]=r[4]+h|0,r[5]=r[5]+l|0,r[6]=r[6]+f|0,r[7]=r[7]+u|0},_doFinalize:function(){var e=this._data,r=e.words,i=8*this._nDataBytes,n=8*e.sigBytes;return r[n>>>5]|=128<<24-n%32,r[14+(n+64>>>9<<4)]=t.floor(i/4294967296),r[15+(n+64>>>9<<4)]=i,e.sigBytes=4*r.length,this._process(),this._hash},clone:function(){var t=n.clone.call(this);return t._hash=this._hash.clone(),t}});e.SHA256=n._createHelper(h),e.HmacSHA256=n._createHmacHelper(h)}(Math),function(){function t(t){return t<<8&4278255360|t>>>8&16711935}var e=l,r=e.lib,i=r.WordArray,n=e.enc;n.Utf16=n.Utf16BE={stringify:function(t){for(var e=t.words,r=t.sigBytes,i=[],n=0;n>>2]>>>16-n%4*8&65535;i.push(String.fromCharCode(o))}return i.join("")},parse:function(t){for(var e=t.length,r=[],n=0;n>>1]|=t.charCodeAt(n)<<16-n%2*16;return i.create(r,2*e)}};n.Utf16LE={stringify:function(e){for(var r=e.words,i=e.sigBytes,n=[],o=0;o>>2]>>>16-o%4*8&65535);n.push(String.fromCharCode(s))}return n.join("")},parse:function(e){for(var r=e.length,n=[],o=0;o>>1]|=t(e.charCodeAt(o)<<16-o%2*16);return i.create(n,2*r)}}}(),function(){if("function"==typeof ArrayBuffer){var t=l,e=t.lib,r=e.WordArray,i=r.init,n=r.init=function(t){if(t instanceof ArrayBuffer&&(t=new Uint8Array(t)),(t instanceof Int8Array||"undefined"!=typeof Uint8ClampedArray&&t instanceof Uint8ClampedArray||t instanceof Int16Array||t instanceof Uint16Array||t instanceof Int32Array||t instanceof Uint32Array||t instanceof Float32Array||t instanceof Float64Array)&&(t=new Uint8Array(t.buffer,t.byteOffset,t.byteLength)),t instanceof Uint8Array){for(var e=t.byteLength,r=[],n=0;n>>2]|=t[n]<<24-n%4*8;i.call(this,r,e)}else i.apply(this,arguments)};n.prototype=r}}(),function(t){function e(t,e,r){return t^e^r}function r(t,e,r){return t&e|~t&r}function i(t,e,r){return(t|~e)^r}function n(t,e,r){return t&r|e&~r}function o(t,e,r){return t^(e|~r)}function s(t,e){return t<>>32-e}var c=l,a=c.lib,h=a.WordArray,f=a.Hasher,u=c.algo,d=h.create([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,7,4,13,1,10,6,15,3,12,0,9,5,2,14,11,8,3,10,14,4,9,15,8,1,2,7,0,6,13,11,5,12,1,9,11,10,0,8,12,4,13,3,7,15,14,5,6,2,4,0,5,9,7,12,2,10,14,1,3,8,11,6,15,13]),p=h.create([5,14,7,0,9,2,11,4,13,6,15,8,1,10,3,12,6,11,3,7,0,13,5,10,14,15,8,12,4,9,1,2,15,5,1,3,7,14,6,9,11,8,12,2,10,0,4,13,8,6,4,1,3,11,15,0,5,12,2,13,9,7,10,14,12,15,10,4,1,5,8,7,6,2,13,14,0,3,9,11]),_=h.create([11,14,15,12,5,8,7,9,11,13,14,15,6,7,9,8,7,6,8,13,11,9,7,15,7,12,15,9,11,7,13,12,11,13,6,7,14,9,13,15,14,8,13,6,5,12,7,5,11,12,14,15,14,15,9,8,9,14,5,6,8,6,5,12,9,15,5,11,6,8,13,12,5,12,13,14,11,8,5,6]),v=h.create([8,9,9,11,13,15,15,5,7,7,8,11,14,14,12,6,9,13,15,7,12,8,9,11,7,7,12,7,6,15,13,11,9,7,15,11,8,6,6,14,12,13,5,14,13,13,7,5,15,5,8,11,14,14,6,14,6,9,12,9,12,5,15,8,8,5,12,9,12,5,14,6,8,13,6,5,15,13,11,11]),y=h.create([0,1518500249,1859775393,2400959708,2840853838]),g=h.create([1352829926,1548603684,1836072691,2053994217,0]),B=u.RIPEMD160=f.extend({_doReset:function(){this._hash=h.create([1732584193,4023233417,2562383102,271733878,3285377520])},_doProcessBlock:function(t,c){for(var a=0;a<16;a++){var h=c+a,l=t[h];t[h]=16711935&(l<<8|l>>>24)|4278255360&(l<<24|l>>>8)}var f,u,B,w,k,S,m,x,b,H,z,A=this._hash.words,C=y.words,D=g.words,E=d.words,R=p.words,M=_.words,F=v.words;S=f=A[0],m=u=A[1],x=B=A[2],b=w=A[3],H=k=A[4];for(a=0;a<80;a+=1)z=f+t[c+E[a]]|0,z+=a<16?e(u,B,w)+C[0]:a<32?r(u,B,w)+C[1]:a<48?i(u,B,w)+C[2]:a<64?n(u,B,w)+C[3]:o(u,B,w)+C[4],z|=0,z=s(z,M[a]),z=z+k|0,f=k,k=w,w=s(B,10),B=u,u=z,z=S+t[c+R[a]]|0,z+=a<16?o(m,x,b)+D[0]:a<32?n(m,x,b)+D[1]:a<48?i(m,x,b)+D[2]:a<64?r(m,x,b)+D[3]:e(m,x,b)+D[4],z|=0,z=s(z,F[a]),z=z+H|0,S=H,H=b,b=s(x,10),x=m,m=z;z=A[1]+B+b|0,A[1]=A[2]+w+H|0,A[2]=A[3]+k+S|0,A[3]=A[4]+f+m|0,A[4]=A[0]+u+x|0,A[0]=z},_doFinalize:function(){var t=this._data,e=t.words,r=8*this._nDataBytes,i=8*t.sigBytes;e[i>>>5]|=128<<24-i%32,e[14+(i+64>>>9<<4)]=16711935&(r<<8|r>>>24)|4278255360&(r<<24|r>>>8),t.sigBytes=4*(e.length+1),this._process();for(var n=this._hash,o=n.words,s=0;s<5;s++){var c=o[s];o[s]=16711935&(c<<8|c>>>24)|4278255360&(c<<24|c>>>8)}return n},clone:function(){var t=f.clone.call(this);return t._hash=this._hash.clone(),t}});c.RIPEMD160=f._createHelper(B),c.HmacRIPEMD160=f._createHmacHelper(B)}(Math),function(){var t=l,e=t.lib,r=e.Base,i=t.enc,n=i.Utf8,o=t.algo;o.HMAC=r.extend({init:function(t,e){t=this._hasher=new t.init,"string"==typeof e&&(e=n.parse(e));var r=t.blockSize,i=4*r;e.sigBytes>i&&(e=t.finalize(e)),e.clamp();for(var o=this._oKey=e.clone(),s=this._iKey=e.clone(),c=o.words,a=s.words,h=0;h>>24)|4278255360&(o<<24|o>>>8),s=16711935&(s<<8|s>>>24)|4278255360&(s<<24|s>>>8);var c=r[n];c.high^=s,c.low^=o}for(var l=0;l<24;l++){for(var d=0;d<5;d++){for(var p=0,_=0,v=0;v<5;v++){c=r[d+5*v];p^=c.high,_^=c.low}var y=u[d];y.high=p,y.low=_}for(d=0;d<5;d++){var g=u[(d+4)%5],B=u[(d+1)%5],w=B.high,k=B.low;for(p=g.high^(w<<1|k>>>31),_=g.low^(k<<1|w>>>31),v=0;v<5;v++){c=r[d+5*v];c.high^=p,c.low^=_}}for(var S=1;S<25;S++){c=r[S];var m=c.high,x=c.low,b=a[S];b<32?(p=m<>>32-b,_=x<>>32-b):(p=x<>>64-b,_=m<>>64-b);var H=u[h[S]];H.high=p,H.low=_}var z=u[0],A=r[0];z.high=A.high,z.low=A.low;for(d=0;d<5;d++)for(v=0;v<5;v++){S=d+5*v,c=r[S];var C=u[S],D=u[(d+1)%5+5*v],E=u[(d+2)%5+5*v];c.high=C.high^~D.high&E.high,c.low=C.low^~D.low&E.low}c=r[0];var R=f[l];c.high^=R.high,c.low^=R.low}},_doFinalize:function(){var e=this._data,r=e.words,n=(this._nDataBytes,8*e.sigBytes),o=32*this.blockSize;r[n>>>5]|=1<<24-n%32,r[(t.ceil((n+1)/o)*o>>>5)-1]|=128,e.sigBytes=4*r.length,this._process();for(var s=this._state,c=this.cfg.outputLength/8,a=c/8,h=[],l=0;l>>24)|4278255360&(u<<24|u>>>8),d=16711935&(d<<8|d>>>24)|4278255360&(d<<24|d>>>8),h.push(d),h.push(u)}return new i.init(h,c)},clone:function(){for(var t=n.clone.call(this),e=t._state=this._state.slice(0),r=0;r<25;r++)e[r]=e[r].clone();return t}});e.SHA3=n._createHelper(d),e.HmacSHA3=n._createHmacHelper(d)}(Math),function(){function t(){return o.create.apply(o,arguments)}var e=l,r=e.lib,i=r.Hasher,n=e.x64,o=n.Word,s=n.WordArray,c=e.algo,a=[t(1116352408,3609767458),t(1899447441,602891725),t(3049323471,3964484399),t(3921009573,2173295548),t(961987163,4081628472),t(1508970993,3053834265),t(2453635748,2937671579),t(2870763221,3664609560),t(3624381080,2734883394),t(310598401,1164996542),t(607225278,1323610764),t(1426881987,3590304994),t(1925078388,4068182383),t(2162078206,991336113),t(2614888103,633803317),t(3248222580,3479774868),t(3835390401,2666613458),t(4022224774,944711139),t(264347078,2341262773),t(604807628,2007800933),t(770255983,1495990901),t(1249150122,1856431235),t(1555081692,3175218132),t(1996064986,2198950837),t(2554220882,3999719339),t(2821834349,766784016),t(2952996808,2566594879),t(3210313671,3203337956),t(3336571891,1034457026),t(3584528711,2466948901),t(113926993,3758326383),t(338241895,168717936),t(666307205,1188179964),t(773529912,1546045734),t(1294757372,1522805485),t(1396182291,2643833823),t(1695183700,2343527390),t(1986661051,1014477480),t(2177026350,1206759142),t(2456956037,344077627),t(2730485921,1290863460),t(2820302411,3158454273),t(3259730800,3505952657),t(3345764771,106217008),t(3516065817,3606008344),t(3600352804,1432725776),t(4094571909,1467031594),t(275423344,851169720),t(430227734,3100823752),t(506948616,1363258195),t(659060556,3750685593),t(883997877,3785050280),t(958139571,3318307427),t(1322822218,3812723403),t(1537002063,2003034995),t(1747873779,3602036899),t(1955562222,1575990012),t(2024104815,1125592928),t(2227730452,2716904306),t(2361852424,442776044),t(2428436474,593698344),t(2756734187,3733110249),t(3204031479,2999351573),t(3329325298,3815920427),t(3391569614,3928383900),t(3515267271,566280711),t(3940187606,3454069534),t(4118630271,4000239992),t(116418474,1914138554),t(174292421,2731055270),t(289380356,3203993006),t(460393269,320620315),t(685471733,587496836),t(852142971,1086792851),t(1017036298,365543100),t(1126000580,2618297676),t(1288033470,3409855158),t(1501505948,4234509866),t(1607167915,987167468),t(1816402316,1246189591)],h=[];(function(){for(var e=0;e<80;e++)h[e]=t()})();var f=c.SHA512=i.extend({_doReset:function(){this._hash=new s.init([new o.init(1779033703,4089235720),new o.init(3144134277,2227873595),new o.init(1013904242,4271175723),new o.init(2773480762,1595750129),new o.init(1359893119,2917565137),new o.init(2600822924,725511199),new o.init(528734635,4215389547),new o.init(1541459225,327033209)])},_doProcessBlock:function(t,e){for(var r=this._hash.words,i=r[0],n=r[1],o=r[2],s=r[3],c=r[4],l=r[5],f=r[6],u=r[7],d=i.high,p=i.low,_=n.high,v=n.low,y=o.high,g=o.low,B=s.high,w=s.low,k=c.high,S=c.low,m=l.high,x=l.low,b=f.high,H=f.low,z=u.high,A=u.low,C=d,D=p,E=_,R=v,M=y,F=g,P=B,W=w,O=k,I=S,U=m,K=x,X=b,L=H,j=z,N=A,T=0;T<80;T++){var q,Z,V=h[T];if(T<16)Z=V.high=0|t[e+2*T],q=V.low=0|t[e+2*T+1];else{var G=h[T-15],J=G.high,$=G.low,Q=(J>>>1|$<<31)^(J>>>8|$<<24)^J>>>7,Y=($>>>1|J<<31)^($>>>8|J<<24)^($>>>7|J<<25),tt=h[T-2],et=tt.high,rt=tt.low,it=(et>>>19|rt<<13)^(et<<3|rt>>>29)^et>>>6,nt=(rt>>>19|et<<13)^(rt<<3|et>>>29)^(rt>>>6|et<<26),ot=h[T-7],st=ot.high,ct=ot.low,at=h[T-16],ht=at.high,lt=at.low;q=Y+ct,Z=Q+st+(q>>>0>>0?1:0),q+=nt,Z=Z+it+(q>>>0>>0?1:0),q+=lt,Z=Z+ht+(q>>>0>>0?1:0),V.high=Z,V.low=q}var ft=O&U^~O&X,ut=I&K^~I&L,dt=C&E^C&M^E&M,pt=D&R^D&F^R&F,_t=(C>>>28|D<<4)^(C<<30|D>>>2)^(C<<25|D>>>7),vt=(D>>>28|C<<4)^(D<<30|C>>>2)^(D<<25|C>>>7),yt=(O>>>14|I<<18)^(O>>>18|I<<14)^(O<<23|I>>>9),gt=(I>>>14|O<<18)^(I>>>18|O<<14)^(I<<23|O>>>9),Bt=a[T],wt=Bt.high,kt=Bt.low,St=N+gt,mt=j+yt+(St>>>0>>0?1:0),xt=(St=St+ut,mt=mt+ft+(St>>>0>>0?1:0),St=St+kt,mt=mt+wt+(St>>>0>>0?1:0),St=St+q,mt=mt+Z+(St>>>0>>0?1:0),vt+pt),bt=_t+dt+(xt>>>0>>0?1:0);j=X,N=L,X=U,L=K,U=O,K=I,I=W+St|0,O=P+mt+(I>>>0>>0?1:0)|0,P=M,W=F,M=E,F=R,E=C,R=D,D=St+xt|0,C=mt+bt+(D>>>0>>0?1:0)|0}p=i.low=p+D,i.high=d+C+(p>>>0>>0?1:0),v=n.low=v+R,n.high=_+E+(v>>>0>>0?1:0),g=o.low=g+F,o.high=y+M+(g>>>0>>0?1:0),w=s.low=w+W,s.high=B+P+(w>>>0>>0?1:0),S=c.low=S+I,c.high=k+O+(S>>>0>>0?1:0),x=l.low=x+K,l.high=m+U+(x>>>0>>0?1:0),H=f.low=H+L,f.high=b+X+(H>>>0>>0?1:0),A=u.low=A+N,u.high=z+j+(A>>>0>>0?1:0)},_doFinalize:function(){var t=this._data,e=t.words,r=8*this._nDataBytes,i=8*t.sigBytes;e[i>>>5]|=128<<24-i%32,e[30+(i+128>>>10<<5)]=Math.floor(r/4294967296),e[31+(i+128>>>10<<5)]=r,t.sigBytes=4*e.length,this._process();var n=this._hash.toX32();return n},clone:function(){var t=i.clone.call(this);return t._hash=this._hash.clone(),t},blockSize:32});e.SHA512=i._createHelper(f),e.HmacSHA512=i._createHmacHelper(f)}(),function(){var t=l,e=t.x64,r=e.Word,i=e.WordArray,n=t.algo,o=n.SHA512,s=n.SHA384=o.extend({_doReset:function(){this._hash=new i.init([new r.init(3418070365,3238371032),new r.init(1654270250,914150663),new r.init(2438529370,812702999),new r.init(355462360,4144912697),new r.init(1731405415,4290775857),new r.init(2394180231,1750603025),new r.init(3675008525,1694076839),new r.init(1203062813,3204075428)])},_doFinalize:function(){var t=o._doFinalize.call(this);return t.sigBytes-=16,t}});t.SHA384=o._createHelper(s),t.HmacSHA384=o._createHmacHelper(s)}(),l.lib.Cipher||function(t){var e=l,r=e.lib,i=r.Base,n=r.WordArray,o=r.BufferedBlockAlgorithm,s=e.enc,c=(s.Utf8,s.Base64),a=e.algo,h=a.EvpKDF,f=r.Cipher=o.extend({cfg:i.extend(),createEncryptor:function(t,e){return this.create(this._ENC_XFORM_MODE,t,e)},createDecryptor:function(t,e){return this.create(this._DEC_XFORM_MODE,t,e)},init:function(t,e,r){this.cfg=this.cfg.extend(r),this._xformMode=t,this._key=e,this.reset()},reset:function(){o.reset.call(this),this._doReset()},process:function(t){return this._append(t),this._process()},finalize:function(t){t&&this._append(t);var e=this._doFinalize();return e},keySize:4,ivSize:4,_ENC_XFORM_MODE:1,_DEC_XFORM_MODE:2,_createHelper:function(){function t(t){return"string"==typeof t?m:w}return function(e){return{encrypt:function(r,i,n){return t(i).encrypt(e,r,i,n)},decrypt:function(r,i,n){return t(i).decrypt(e,r,i,n)}}}}()}),u=(r.StreamCipher=f.extend({_doFinalize:function(){var t=this._process(!0);return t},blockSize:1}),e.mode={}),d=r.BlockCipherMode=i.extend({createEncryptor:function(t,e){return this.Encryptor.create(t,e)},createDecryptor:function(t,e){return this.Decryptor.create(t,e)},init:function(t,e){this._cipher=t,this._iv=e}}),p=u.CBC=function(){function e(e,r,i){var n,o=this._iv;o?(n=o,this._iv=t):n=this._prevBlock;for(var s=0;s>>2];t.sigBytes-=e}},y=(r.BlockCipher=f.extend({cfg:f.cfg.extend({mode:p,padding:v}),reset:function(){var t;f.reset.call(this);var e=this.cfg,r=e.iv,i=e.mode;this._xformMode==this._ENC_XFORM_MODE?t=i.createEncryptor:(t=i.createDecryptor,this._minBufferSize=1),this._mode&&this._mode.__creator==t?this._mode.init(this,r&&r.words):(this._mode=t.call(i,this,r&&r.words),this._mode.__creator=t)},_doProcessBlock:function(t,e){this._mode.processBlock(t,e)},_doFinalize:function(){var t,e=this.cfg.padding;return this._xformMode==this._ENC_XFORM_MODE?(e.pad(this._data,this.blockSize),t=this._process(!0)):(t=this._process(!0),e.unpad(t)),t},blockSize:4}),r.CipherParams=i.extend({init:function(t){this.mixIn(t)},toString:function(t){return(t||this.formatter).stringify(this)}})),g=e.format={},B=g.OpenSSL={stringify:function(t){var e,r=t.ciphertext,i=t.salt;return e=i?n.create([1398893684,1701076831]).concat(i).concat(r):r,e.toString(c)},parse:function(t){var e,r=c.parse(t),i=r.words;return 1398893684==i[0]&&1701076831==i[1]&&(e=n.create(i.slice(2,4)),i.splice(0,4),r.sigBytes-=16),y.create({ciphertext:r,salt:e})}},w=r.SerializableCipher=i.extend({cfg:i.extend({format:B}),encrypt:function(t,e,r,i){i=this.cfg.extend(i);var n=t.createEncryptor(r,i),o=n.finalize(e),s=n.cfg;return y.create({ciphertext:o,key:r,iv:s.iv,algorithm:t,mode:s.mode,padding:s.padding,blockSize:t.blockSize,formatter:i.format})},decrypt:function(t,e,r,i){i=this.cfg.extend(i),e=this._parse(e,i.format);var n=t.createDecryptor(r,i).finalize(e.ciphertext);return n},_parse:function(t,e){return"string"==typeof t?e.parse(t,this):t}}),k=e.kdf={},S=k.OpenSSL={execute:function(t,e,r,i){i||(i=n.random(8));var o=h.create({keySize:e+r}).compute(t,i),s=n.create(o.words.slice(e),4*r);return o.sigBytes=4*e,y.create({key:o,iv:s,salt:i})}},m=r.PasswordBasedCipher=w.extend({cfg:w.cfg.extend({kdf:S}),encrypt:function(t,e,r,i){i=this.cfg.extend(i);var n=i.kdf.execute(r,t.keySize,t.ivSize);i.iv=n.iv;var o=w.encrypt.call(this,t,e,n.key,i);return o.mixIn(n),o},decrypt:function(t,e,r,i){i=this.cfg.extend(i),e=this._parse(e,i.format);var n=i.kdf.execute(r,t.keySize,t.ivSize,e.salt);i.iv=n.iv;var o=w.decrypt.call(this,t,e,n.key,i);return o}})}(),l.mode.CFB=function(){function t(t,e,r,i){var n,o=this._iv;o?(n=o.slice(0),this._iv=void 0):n=this._prevBlock,i.encryptBlock(n,0);for(var s=0;s>>2]|=n<<24-o%4*8,t.sigBytes+=n},unpad:function(t){var e=255&t.words[t.sigBytes-1>>>2];t.sigBytes-=e}},l.pad.Iso10126={pad:function(t,e){var r=4*e,i=r-t.sigBytes%r;t.concat(l.lib.WordArray.random(i-1)).concat(l.lib.WordArray.create([i<<24],1))},unpad:function(t){var e=255&t.words[t.sigBytes-1>>>2];t.sigBytes-=e}},l.pad.Iso97971={pad:function(t,e){t.concat(l.lib.WordArray.create([2147483648],1)),l.pad.ZeroPadding.pad(t,e)},unpad:function(t){l.pad.ZeroPadding.unpad(t),t.sigBytes--}},l.mode.OFB=(a=l.lib.BlockCipherMode.extend(),h=a.Encryptor=a.extend({processBlock:function(t,e){var r=this._cipher,i=r.blockSize,n=this._iv,o=this._keystream;n&&(o=this._keystream=n.slice(0),this._iv=void 0),r.encryptBlock(o,0);for(var s=0;s>>8^255&l^99,n[r]=l,o[l]=r;var _=t[r],v=t[_],y=t[v],g=257*t[l]^16843008*l;s[r]=g<<24|g>>>8,c[r]=g<<16|g>>>16,a[r]=g<<8|g>>>24,h[r]=g;g=16843009*y^65537*v^257*_^16843008*r;f[l]=g<<24|g>>>8,u[l]=g<<16|g>>>16,d[l]=g<<8|g>>>24,p[l]=g,r?(r=_^t[t[t[y^_]]],i^=t[t[i]]):r=i=1}})();var _=[0,1,2,4,8,16,32,64,128,27,54],v=i.AES=r.extend({_doReset:function(){if(!this._nRounds||this._keyPriorReset!==this._key){for(var t=this._keyPriorReset=this._key,e=t.words,r=t.sigBytes/4,i=this._nRounds=r+6,o=4*(i+1),s=this._keySchedule=[],c=0;c6&&c%r==4&&(l=n[l>>>24]<<24|n[l>>>16&255]<<16|n[l>>>8&255]<<8|n[255&l]):(l=l<<8|l>>>24,l=n[l>>>24]<<24|n[l>>>16&255]<<16|n[l>>>8&255]<<8|n[255&l],l^=_[c/r|0]<<24),s[c]=s[c-r]^l);for(var a=this._invKeySchedule=[],h=0;h>>24]]^u[n[l>>>16&255]]^d[n[l>>>8&255]]^p[n[255&l]]}}},encryptBlock:function(t,e){this._doCryptBlock(t,e,this._keySchedule,s,c,a,h,n)},decryptBlock:function(t,e){var r=t[e+1];t[e+1]=t[e+3],t[e+3]=r,this._doCryptBlock(t,e,this._invKeySchedule,f,u,d,p,o);r=t[e+1];t[e+1]=t[e+3],t[e+3]=r},_doCryptBlock:function(t,e,r,i,n,o,s,c){for(var a=this._nRounds,h=t[e]^r[0],l=t[e+1]^r[1],f=t[e+2]^r[2],u=t[e+3]^r[3],d=4,p=1;p>>24]^n[l>>>16&255]^o[f>>>8&255]^s[255&u]^r[d++],v=i[l>>>24]^n[f>>>16&255]^o[u>>>8&255]^s[255&h]^r[d++],y=i[f>>>24]^n[u>>>16&255]^o[h>>>8&255]^s[255&l]^r[d++],g=i[u>>>24]^n[h>>>16&255]^o[l>>>8&255]^s[255&f]^r[d++];h=_,l=v,f=y,u=g}_=(c[h>>>24]<<24|c[l>>>16&255]<<16|c[f>>>8&255]<<8|c[255&u])^r[d++],v=(c[l>>>24]<<24|c[f>>>16&255]<<16|c[u>>>8&255]<<8|c[255&h])^r[d++],y=(c[f>>>24]<<24|c[u>>>16&255]<<16|c[h>>>8&255]<<8|c[255&l])^r[d++],g=(c[u>>>24]<<24|c[h>>>16&255]<<16|c[l>>>8&255]<<8|c[255&f])^r[d++];t[e]=_,t[e+1]=v,t[e+2]=y,t[e+3]=g},keySize:8});t.AES=r._createHelper(v)}(),function(){function t(t,e){var r=(this._lBlock>>>t^this._rBlock)&e;this._rBlock^=r,this._lBlock^=r<>>t^this._lBlock)&e;this._lBlock^=r,this._rBlock^=r<>>5]>>>31-n%32&1}for(var o=this._subKeys=[],s=0;s<16;s++){var l=o[s]=[],f=h[s];for(i=0;i<24;i++)l[i/6|0]|=r[(a[i]-1+f)%28]<<31-i%6,l[4+(i/6|0)]|=r[28+(a[i+24]-1+f)%28]<<31-i%6;l[0]=l[0]<<1|l[0]>>>31;for(i=1;i<7;i++)l[i]=l[i]>>>4*(i-1)+3;l[7]=l[7]<<5|l[7]>>>27}var u=this._invSubKeys=[];for(i=0;i<16;i++)u[i]=o[15-i]},encryptBlock:function(t,e){this._doCryptBlock(t,e,this._subKeys)},decryptBlock:function(t,e){this._doCryptBlock(t,e,this._invSubKeys)},_doCryptBlock:function(r,i,n){this._lBlock=r[i],this._rBlock=r[i+1],t.call(this,4,252645135),t.call(this,16,65535),e.call(this,2,858993459),e.call(this,8,16711935),t.call(this,1,1431655765);for(var o=0;o<16;o++){for(var s=n[o],c=this._lBlock,a=this._rBlock,h=0,l=0;l<8;l++)h|=f[l][((a^s[l])&u[l])>>>0];this._lBlock=a,this._rBlock=c^h}var d=this._lBlock;this._lBlock=this._rBlock,this._rBlock=d,t.call(this,1,1431655765),e.call(this,8,16711935),e.call(this,2,858993459),t.call(this,16,65535),t.call(this,4,252645135),r[i]=this._lBlock,r[i+1]=this._rBlock},keySize:2,ivSize:2,blockSize:2});r.DES=o._createHelper(d);var p=s.TripleDES=o.extend({_doReset:function(){var t=this._key,e=t.words;if(2!==e.length&&4!==e.length&&e.length<6)throw new Error("Invalid key length - 3DES requires the key length to be 64, 128, 192 or >192.");var r=e.slice(0,2),i=e.length<4?e.slice(0,2):e.slice(2,4),o=e.length<6?e.slice(0,2):e.slice(4,6);this._des1=d.createEncryptor(n.create(r)),this._des2=d.createEncryptor(n.create(i)),this._des3=d.createEncryptor(n.create(o))},encryptBlock:function(t,e){this._des1.encryptBlock(t,e),this._des2.decryptBlock(t,e),this._des3.encryptBlock(t,e)},decryptBlock:function(t,e){this._des3.decryptBlock(t,e),this._des2.encryptBlock(t,e),this._des1.decryptBlock(t,e)},keySize:6,ivSize:2,blockSize:2});r.TripleDES=o._createHelper(p)}(),function(){function t(){for(var t=this._S,e=this._i,r=this._j,i=0,n=0;n<4;n++){e=(e+1)%256,r=(r+t[e])%256;var o=t[e];t[e]=t[r],t[r]=o,i|=t[(t[e]+t[r])%256]<<24-8*n}return this._i=e,this._j=r,i}var e=l,r=e.lib,i=r.StreamCipher,n=e.algo,o=n.RC4=i.extend({_doReset:function(){for(var t=this._key,e=t.words,r=t.sigBytes,i=this._S=[],n=0;n<256;n++)i[n]=n;n=0;for(var o=0;n<256;n++){var s=n%r,c=e[s>>>2]>>>24-s%4*8&255;o=(o+i[n]+c)%256;var a=i[n];i[n]=i[o],i[o]=a}this._i=this._j=0},_doProcessBlock:function(e,r){e[r]^=t.call(this)},keySize:8,ivSize:0});e.RC4=i._createHelper(o);var s=n.RC4Drop=o.extend({cfg:o.cfg.extend({drop:192}),_doReset:function(){o._doReset.call(this);for(var e=this.cfg.drop;e>0;e--)t.call(this)}});e.RC4Drop=i._createHelper(s)}(),l.mode.CTRGladman=function(){function t(t){if(255==(t>>24&255)){var e=t>>16&255,r=t>>8&255,i=255&t;255===e?(e=0,255===r?(r=0,255===i?i=0:++i):++r):++e,t=0,t+=e<<16,t+=r<<8,t+=i}else t+=1<<24;return t}function e(e){return 0===(e[0]=t(e[0]))&&(e[1]=t(e[1])),e}var r=l.lib.BlockCipherMode.extend(),i=r.Encryptor=r.extend({processBlock:function(t,r){var i=this._cipher,n=i.blockSize,o=this._iv,s=this._counter;o&&(s=this._counter=o.slice(0),this._iv=void 0),e(s);var c=s.slice(0);i.encryptBlock(c,0);for(var a=0;a>>0>>0?1:0)|0,e[2]=e[2]+886263092+(e[1]>>>0>>0?1:0)|0,e[3]=e[3]+1295307597+(e[2]>>>0>>0?1:0)|0,e[4]=e[4]+3545052371+(e[3]>>>0>>0?1:0)|0,e[5]=e[5]+886263092+(e[4]>>>0>>0?1:0)|0,e[6]=e[6]+1295307597+(e[5]>>>0>>0?1:0)|0,e[7]=e[7]+3545052371+(e[6]>>>0>>0?1:0)|0,this._b=e[7]>>>0>>0?1:0;for(r=0;r<8;r++){var i=t[r]+e[r],n=65535&i,o=i>>>16,a=((n*n>>>17)+n*o>>>15)+o*o,h=((4294901760&i)*i|0)+((65535&i)*i|0);c[r]=a^h}t[0]=c[0]+(c[7]<<16|c[7]>>>16)+(c[6]<<16|c[6]>>>16)|0,t[1]=c[1]+(c[0]<<8|c[0]>>>24)+c[7]|0,t[2]=c[2]+(c[1]<<16|c[1]>>>16)+(c[0]<<16|c[0]>>>16)|0,t[3]=c[3]+(c[2]<<8|c[2]>>>24)+c[1]|0,t[4]=c[4]+(c[3]<<16|c[3]>>>16)+(c[2]<<16|c[2]>>>16)|0,t[5]=c[5]+(c[4]<<8|c[4]>>>24)+c[3]|0,t[6]=c[6]+(c[5]<<16|c[5]>>>16)+(c[4]<<16|c[4]>>>16)|0,t[7]=c[7]+(c[6]<<8|c[6]>>>24)+c[5]|0}var e=l,r=e.lib,i=r.StreamCipher,n=e.algo,o=[],s=[],c=[],a=n.Rabbit=i.extend({_doReset:function(){for(var e=this._key.words,r=this.cfg.iv,i=0;i<4;i++)e[i]=16711935&(e[i]<<8|e[i]>>>24)|4278255360&(e[i]<<24|e[i]>>>8);var n=this._X=[e[0],e[3]<<16|e[2]>>>16,e[1],e[0]<<16|e[3]>>>16,e[2],e[1]<<16|e[0]>>>16,e[3],e[2]<<16|e[1]>>>16],o=this._C=[e[2]<<16|e[2]>>>16,4294901760&e[0]|65535&e[1],e[3]<<16|e[3]>>>16,4294901760&e[1]|65535&e[2],e[0]<<16|e[0]>>>16,4294901760&e[2]|65535&e[3],e[1]<<16|e[1]>>>16,4294901760&e[3]|65535&e[0]];this._b=0;for(i=0;i<4;i++)t.call(this);for(i=0;i<8;i++)o[i]^=n[i+4&7];if(r){var s=r.words,c=s[0],a=s[1],h=16711935&(c<<8|c>>>24)|4278255360&(c<<24|c>>>8),l=16711935&(a<<8|a>>>24)|4278255360&(a<<24|a>>>8),f=h>>>16|4294901760&l,u=l<<16|65535&h;o[0]^=h,o[1]^=f,o[2]^=l,o[3]^=u,o[4]^=h,o[5]^=f,o[6]^=l,o[7]^=u;for(i=0;i<4;i++)t.call(this)}},_doProcessBlock:function(e,r){var i=this._X;t.call(this),o[0]=i[0]^i[5]>>>16^i[3]<<16,o[1]=i[2]^i[7]>>>16^i[5]<<16,o[2]=i[4]^i[1]>>>16^i[7]<<16,o[3]=i[6]^i[3]>>>16^i[1]<<16;for(var n=0;n<4;n++)o[n]=16711935&(o[n]<<8|o[n]>>>24)|4278255360&(o[n]<<24|o[n]>>>8),e[r+n]^=o[n]},blockSize:4,ivSize:2});e.Rabbit=i._createHelper(a)}(),l.mode.CTR=function(){var t=l.lib.BlockCipherMode.extend(),e=t.Encryptor=t.extend({processBlock:function(t,e){var r=this._cipher,i=r.blockSize,n=this._iv,o=this._counter;n&&(o=this._counter=n.slice(0),this._iv=void 0);var s=o.slice(0);r.encryptBlock(s,0),o[i-1]=o[i-1]+1|0;for(var c=0;c>>0>>0?1:0)|0,e[2]=e[2]+886263092+(e[1]>>>0>>0?1:0)|0,e[3]=e[3]+1295307597+(e[2]>>>0>>0?1:0)|0,e[4]=e[4]+3545052371+(e[3]>>>0>>0?1:0)|0,e[5]=e[5]+886263092+(e[4]>>>0>>0?1:0)|0,e[6]=e[6]+1295307597+(e[5]>>>0>>0?1:0)|0,e[7]=e[7]+3545052371+(e[6]>>>0>>0?1:0)|0,this._b=e[7]>>>0>>0?1:0;for(r=0;r<8;r++){var i=t[r]+e[r],n=65535&i,o=i>>>16,a=((n*n>>>17)+n*o>>>15)+o*o,h=((4294901760&i)*i|0)+((65535&i)*i|0);c[r]=a^h}t[0]=c[0]+(c[7]<<16|c[7]>>>16)+(c[6]<<16|c[6]>>>16)|0,t[1]=c[1]+(c[0]<<8|c[0]>>>24)+c[7]|0,t[2]=c[2]+(c[1]<<16|c[1]>>>16)+(c[0]<<16|c[0]>>>16)|0,t[3]=c[3]+(c[2]<<8|c[2]>>>24)+c[1]|0,t[4]=c[4]+(c[3]<<16|c[3]>>>16)+(c[2]<<16|c[2]>>>16)|0,t[5]=c[5]+(c[4]<<8|c[4]>>>24)+c[3]|0,t[6]=c[6]+(c[5]<<16|c[5]>>>16)+(c[4]<<16|c[4]>>>16)|0,t[7]=c[7]+(c[6]<<8|c[6]>>>24)+c[5]|0}var e=l,r=e.lib,i=r.StreamCipher,n=e.algo,o=[],s=[],c=[],a=n.RabbitLegacy=i.extend({_doReset:function(){var e=this._key.words,r=this.cfg.iv,i=this._X=[e[0],e[3]<<16|e[2]>>>16,e[1],e[0]<<16|e[3]>>>16,e[2],e[1]<<16|e[0]>>>16,e[3],e[2]<<16|e[1]>>>16],n=this._C=[e[2]<<16|e[2]>>>16,4294901760&e[0]|65535&e[1],e[3]<<16|e[3]>>>16,4294901760&e[1]|65535&e[2],e[0]<<16|e[0]>>>16,4294901760&e[2]|65535&e[3],e[1]<<16|e[1]>>>16,4294901760&e[3]|65535&e[0]];this._b=0;for(var o=0;o<4;o++)t.call(this);for(o=0;o<8;o++)n[o]^=i[o+4&7];if(r){var s=r.words,c=s[0],a=s[1],h=16711935&(c<<8|c>>>24)|4278255360&(c<<24|c>>>8),l=16711935&(a<<8|a>>>24)|4278255360&(a<<24|a>>>8),f=h>>>16|4294901760&l,u=l<<16|65535&h;n[0]^=h,n[1]^=f,n[2]^=l,n[3]^=u,n[4]^=h,n[5]^=f,n[6]^=l,n[7]^=u;for(o=0;o<4;o++)t.call(this)}},_doProcessBlock:function(e,r){var i=this._X;t.call(this),o[0]=i[0]^i[5]>>>16^i[3]<<16,o[1]=i[2]^i[7]>>>16^i[5]<<16,o[2]=i[4]^i[1]>>>16^i[7]<<16,o[3]=i[6]^i[3]>>>16^i[1]<<16;for(var n=0;n<4;n++)o[n]=16711935&(o[n]<<8|o[n]>>>24)|4278255360&(o[n]<<24|o[n]>>>8),e[r+n]^=o[n]},blockSize:4,ivSize:2});e.RabbitLegacy=i._createHelper(a)}(),l.pad.ZeroPadding={pad:function(t,e){var r=4*e;t.clamp(),t.sigBytes+=r-(t.sigBytes%r||r)},unpad:function(t){var e=t.words,r=t.sigBytes-1;for(r=t.sigBytes-1;r>=0;r--)if(e[r>>>2]>>>24-r%4*8&255){t.sigBytes=r+1;break}}},l}); -------------------------------------------------------------------------------- /v2ex/hot.js: -------------------------------------------------------------------------------- 1 | // Variables used by Scriptable. 2 | // These must be at the very top of the file. Do not edit. 3 | // icon-color: blue; icon-glyph: film; 4 | /* 5 | * Author: recall704 6 | * Github: https://github.com/recall704/Scriptable 7 | * 本脚本使用了@Gideon_Senku的Env.scriptable,感谢! 8 | */ 9 | const goupdate = false; 10 | const $ = importModule("Env"); 11 | const title = `📖 v2ex热榜`; 12 | const preview = "medium"; 13 | const spacing = 5; 14 | 15 | const res = await getinfo(); 16 | 17 | let widget = await createWidget(res); 18 | Script.setWidget(widget); 19 | Script.complete(); 20 | 21 | async function createWidget(res) { 22 | var group = res.data; 23 | items = []; 24 | urls = []; 25 | for (var i = 0; i < 6; i++) { 26 | var item = res[i].title; 27 | var v2exUrl = res[i].url; 28 | items.push(item); 29 | urls.push(v2exUrl); 30 | } 31 | console.log(items); 32 | 33 | const opts = { 34 | title, 35 | texts: { 36 | text1: { text : `• ${items[0]}`, url: urls[0] }, 37 | text2: { text : `• ${items[1]}`, url: urls[1] }, 38 | text3: { text : `• ${items[2]}`, url: urls[2] }, 39 | text4: { text : `• ${items[3]}`, url: urls[3] }, 40 | text5: { text : `• ${items[4]}`, url: urls[4] }, 41 | text6: { text : `• ${items[5]}`, url: urls[5] }, 42 | battery: "true" 43 | }, 44 | preview, 45 | spacing, 46 | }; 47 | 48 | let widget = await $.createWidget(opts); 49 | return widget; 50 | } 51 | 52 | async function getinfo() { 53 | const url = { 54 | url: `https://www.v2ex.com/api/topics/hot.json`, 55 | }; 56 | const res = await $.get(url); 57 | log(res); 58 | return res; 59 | } 60 | 61 | //更新代码 62 | function update() { 63 | log("🔔更新脚本开始!"); 64 | scripts.forEach(async (script) => { 65 | await $.getFile(script); 66 | }); 67 | log("🔔更新脚本结束!"); 68 | } 69 | 70 | const scripts = [ 71 | { 72 | moduleName: "v2ex_hot", 73 | url: 74 | "https://raw.githubusercontent.com/recall704/Scriptable/master/v2ex/hot.js", 75 | }, 76 | ]; 77 | if (goupdate == true) update(); 78 | -------------------------------------------------------------------------------- /v2ex/latest.js: -------------------------------------------------------------------------------- 1 | // Variables used by Scriptable. 2 | // These must be at the very top of the file. Do not edit. 3 | // icon-color: blue; icon-glyph: film; 4 | /* 5 | * Author: recall704 6 | * Github: https://github.com/recall704/Scriptable 7 | * 本脚本使用了@Gideon_Senku的Env.scriptable,感谢! 8 | */ 9 | const goupdate = false; 10 | const $ = importModule("Env"); 11 | const title = `📖 v2ex最新`; 12 | const preview = "medium"; 13 | const spacing = 5; 14 | 15 | const res = await getinfo(); 16 | 17 | let widget = await createWidget(res); 18 | Script.setWidget(widget); 19 | Script.complete(); 20 | 21 | async function createWidget(res) { 22 | var group = res.data; 23 | items = []; 24 | urls = []; 25 | for (var i = 0; i < 6; i++) { 26 | var item = res[i].title; 27 | var v2exUrl = res[i].url; 28 | items.push(item); 29 | urls.push(v2exUrl); 30 | } 31 | console.log(items); 32 | 33 | const opts = { 34 | title, 35 | texts: { 36 | text1: { text : `• ${items[0]}`, url: urls[0] }, 37 | text2: { text : `• ${items[1]}`, url: urls[1] }, 38 | text3: { text : `• ${items[2]}`, url: urls[2] }, 39 | text4: { text : `• ${items[3]}`, url: urls[3] }, 40 | text5: { text : `• ${items[4]}`, url: urls[4] }, 41 | text6: { text : `• ${items[5]}`, url: urls[5] }, 42 | battery: "true" 43 | }, 44 | preview, 45 | spacing, 46 | }; 47 | 48 | let widget = await $.createWidget(opts); 49 | return widget; 50 | } 51 | 52 | async function getinfo() { 53 | const url = { 54 | url: `https://www.v2ex.com/api/topics/latest.json`, 55 | }; 56 | const res = await $.get(url); 57 | log(res); 58 | return res; 59 | } 60 | 61 | //更新代码 62 | function update() { 63 | log("🔔更新脚本开始!"); 64 | scripts.forEach(async (script) => { 65 | await $.getFile(script); 66 | }); 67 | log("🔔更新脚本结束!"); 68 | } 69 | 70 | const scripts = [ 71 | { 72 | moduleName: "v2ex_latest", 73 | url: 74 | "https://raw.githubusercontent.com/recall704/Scriptable/master/v2ex/latest.js", 75 | }, 76 | ]; 77 | if (goupdate == true) update(); 78 | --------------------------------------------------------------------------------