├── Loon └── campusphere.js ├── Quantumult-X ├── EPIC_free_games.js ├── campusphere.js └── topsports.js ├── README.md ├── Shadowrocket └── campusphere.js └── Surge ├── Auto_join_TF.js ├── CMB_ID.js ├── CMB_piao.js ├── Capture.js ├── EPIC_free_games.js ├── Follow.js ├── IP-Geolocation.js ├── IP-Score-All-Info.js ├── IP.js ├── Nomo.js ├── PDDNS.js ├── Piao_Bak.js ├── Piao_No.js ├── TF_keys.js ├── TF_link.js ├── XiYou-Sign.js ├── XiYou-summary.js ├── campusphere-night.js ├── campusphere.js └── up_pddns.js /Loon/campusphere.js: -------------------------------------------------------------------------------- 1 | let cp = {}; 2 | cp.long = $persistentStore.read("经度"); 3 | cp.la = $persistentStore.read("纬度"); 4 | cp.location = $persistentStore.read("地区"); 5 | (async function() { 6 | if ($persistentStore.read("sign") == "SUCCESS") { 7 | $done(console.log("已签到")) 8 | } else { 9 | await login(); 10 | await wid(); 11 | await form(); 12 | await submit(); 13 | $done(); 14 | } 15 | })(); 16 | function login() { 17 | console.log("await login") 18 | const loginurl = { 19 | url: 'http://' + $persistentStore.read("ip") + ':8080/wisedu-unified-login-api-v1.0/api/login?login_url=http%3A%2F%2Fauthserver.' + $persistentStore.read("学校") + '.cn%2Fauthserver%2Flogin%3Fservice%3Dhttps%253A%252F%252F' + $persistentStore.read("学校") + '.campusphere.net%252Fiap%252FloginSuccess&password=' + $persistentStore.read("密码") + '&username=' + $persistentStore.read("账号"), 20 | timeout: 30 21 | }; 22 | return new Promise(function(resolve) { 23 | $httpClient.post(loginurl, function(error, resp, data) { 24 | if (typeof(resp) == "undefined") { 25 | console.log(resp) 26 | login() 27 | }else if (resp.status != 200) { 28 | console.log(resp.status) 29 | login() 30 | } else { 31 | let jsonData = JSON.parse(data); 32 | console.log(jsonData.msg) 33 | if (jsonData.msg != "login success!") { 34 | login() 35 | } else { 36 | let cookies = jsonData.cookies 37 | let regex = /route.*MOD_AUTH_CAS/ 38 | cp.cookie = cookies.replace(regex, "MOD_AUTH_CAS") 39 | console.log('\n' + cp.cookie) 40 | resolve(); //异步操作成功时调用, 将Promise对象的状态标记为"成功", 表示已完成 41 | } 42 | } 43 | }); 44 | }); 45 | } 46 | 47 | function wid() { 48 | console.log("await wid") 49 | const widurl = { 50 | url: 'https://' + $persistentStore.read("学校") + '.campusphere.net/wec-counselor-sign-apps/stu/sign/getStuSignInfosInOneDay', 51 | headers: { 52 | 'Cookie' : cp.cookie, 53 | 'Content-Type' : `application/json;charset=utf-8` 54 | }, 55 | body: '{}' 56 | }; 57 | return new Promise(function(resolve) { 58 | $httpClient.post(widurl, function(error, resp, data) { 59 | let jsonData = JSON.parse(data); 60 | console.log('\n' + data) 61 | cp.leave = jsonData["datas"].leaveTasks[0] 62 | cp.unsign = jsonData["datas"].unSignedTasks[0] 63 | if (typeof(cp.unsign) == "undefined" && typeof(cp.leave) == "undefined") { 64 | console.log("无签到") 65 | $persistentStore.write('SUCCESS', 'sign') 66 | $done($notification.post("无签到","","")) 67 | } else if (typeof(cp.unsign) == "undefined") { 68 | cp.wid = jsonData["datas"].leaveTasks[0].signInstanceWid 69 | cp.signWid = jsonData["datas"].leaveTasks[0].signWid 70 | resolve(); 71 | } else { 72 | cp.wid = jsonData["datas"].unSignedTasks[0].signInstanceWid 73 | cp.signWid = jsonData["datas"].unSignedTasks[0].signWid 74 | resolve(); 75 | } 76 | }); 77 | }); 78 | } 79 | 80 | function form() { 81 | console.log("await form") 82 | const formurl = { 83 | url: 'https://' + $persistentStore.read("学校") + '.campusphere.net/wec-counselor-sign-apps/stu/sign/detailSignInstance', 84 | headers: { 85 | 'Cookie' : cp.cookie, 86 | 'Content-Type' : 'application/json;charset=utf-8' 87 | }, 88 | body: `{ 89 | "signWid": ${cp.signWid}, 90 | "signInstanceWid": ${cp.wid} 91 | }`, 92 | }; 93 | return new Promise(function(resolve) { 94 | $httpClient.post(formurl, function(error, resp, data) { 95 | let jsonData = JSON.parse(data); 96 | cp.formWid = jsonData.datas.extraField[0].extraFieldItems[0].wid 97 | cp.formWid1 = jsonData.datas.extraField[1].extraFieldItems[0].wid 98 | cp.formWid2 = jsonData.datas.extraField[2].extraFieldItems[0].wid 99 | cp.formWid3 = jsonData.datas.extraField[3].extraFieldItems[0].wid 100 | cp.formWid4 = jsonData.datas.extraField[4].extraFieldItems[0].wid 101 | cp.formcontent = jsonData.datas.extraField[0].extraFieldItems[0].content 102 | cp.formcontent1 = jsonData.datas.extraField[1].extraFieldItems[0].content 103 | cp.formcontent2 = jsonData.datas.extraField[2].extraFieldItems[0].content 104 | cp.formcontent3 = jsonData.datas.extraField[3].extraFieldItems[0].content 105 | cp.formcontent4 = jsonData.datas.extraField[4].extraFieldItems[0].content 106 | resolve(); 107 | }) 108 | }) 109 | } 110 | function submit() { 111 | console.log("await submit") 112 | const bodys = { 113 | "abnormalReason": "", 114 | "position": `${cp.location}`, 115 | "longitude": `${cp.long}`, 116 | "isNeedExtra": 1, 117 | "latitude": `${cp.la}`, 118 | "isMalposition": 1, 119 | "extraFieldItems": [ 120 | { 121 | "extraFieldItemWid": `${cp.formWid}`, 122 | "extraFieldItemValue": `${cp.formcontent}` 123 | }, 124 | { 125 | "extraFieldItemWid": `${cp.formWid1}`, 126 | "extraFieldItemValue": `${cp.formcontent1}` 127 | }, 128 | { 129 | "extraFieldItemWid": `${cp.formWid2}`, 130 | "extraFieldItemValue": `${cp.formcontent2}` 131 | }, 132 | { 133 | "extraFieldItemWid": `${cp.formWid3}`, 134 | "extraFieldItemValue": `${cp.formcontent3}` 135 | }, 136 | { 137 | "extraFieldItemWid": `${cp.formWid4}`, 138 | "extraFieldItemValue": `${cp.formcontent4}` 139 | } 140 | ], 141 | "signPhotoUrl": "", 142 | "uaIsCpadaily": false, 143 | "signInstanceWid": `${cp.wid}` 144 | } 145 | const submiturl = { 146 | url: 'https://' + $persistentStore.read("学校") + '.campusphere.net/wec-counselor-sign-apps/stu/sign/submitSign', 147 | headers: { 148 | 'Cookie' : cp.cookie, 149 | 'Content-Type' : 'application/json;charset=utf-8' 150 | }, 151 | body: JSON.stringify(bodys) 152 | }; 153 | return new Promise(function(resolve) { 154 | $httpClient.post(submiturl, function(error, resp, data) { 155 | let jsonData = JSON.parse(data); 156 | cp.msg = jsonData.message 157 | console.log(cp.msg) 158 | $notification.post("今日校园", cp.msg, "") 159 | if (cp.msg == "SUCCESS") { 160 | $persistentStore.write(cp.msg, 'sign') 161 | resolve() 162 | } else { 163 | resolve(); 164 | } 165 | }); 166 | }); 167 | } -------------------------------------------------------------------------------- /Quantumult-X/EPIC_free_games.js: -------------------------------------------------------------------------------- 1 | /** 2 | 建议cron:1 0 * * * 3 | surge脚本请去surge文件夹路径寻找 4 | */ 5 | 6 | 7 | 8 | 9 | $task.fetch({url:"https://store-site-backend-static-ipv4.ak.epicgames.com/freeGamesPromotions?locale=en-US&country=US&allowCountries=US"}).then(response => { 10 | let jsonData = JSON.parse(response.body) 11 | let i = 0 12 | let games = jsonData.data.Catalog.searchStore.elements 13 | while (games) { 14 | if (jsonData.data.Catalog.searchStore.elements[i] == undefined) { 15 | break; 16 | } else if (jsonData.data.Catalog.searchStore.elements[i].title == "Mystery Game") { 17 | i++ 18 | } else { 19 | games = jsonData.data.Catalog.searchStore.elements[i] 20 | console.log(JSON.stringify(games)) 21 | if (games.promotions == null) { 22 | $notify('🎮EPIC: ' + games.title, '🕒UPCOMING: ' + 'UNKNOWN', '📜DESCRIPTION: ' + games.description, {"media-url":games.keyImages[1].url}) 23 | i++ 24 | } else if (games.promotions.upcomingPromotionalOffers == '') { 25 | $notify('🎮EPIC: ' + games.title, '🕒OPEN: ' + transFormTime(games.promotions.promotionalOffers[0].promotionalOffers[0].startDate) + '\n🕐END: ' + transFormTime(games.promotions.promotionalOffers[0].promotionalOffers[0].endDate), '📜DESCRIPTION: ' + games.description, {"media-url":games.keyImages[1].url}) 26 | i++ 27 | } else { 28 | $notify('🎮EPIC: ' + games.title, '🕒UPCOMING: ' + transFormTime(games.promotions.upcomingPromotionalOffers[0].promotionalOffers[0].startDate) + '\n🕐END: ' + transFormTime(games.promotions.upcomingPromotionalOffers[0].promotionalOffers[0].endDate), '📜DESCRIPTION: ' + games.description, {"media-url":games.keyImages[1].url}) 29 | i++ 30 | } 31 | } 32 | } 33 | $done() 34 | }, reason => { 35 | // reason.error 36 | $notify("EPIC FREE GAMES", "ERROR", reason.error); // Error! 37 | $done(); 38 | }); 39 | 40 | 41 | function transFormTime(times) { 42 | const date = new Date(times); 43 | return `${date.getFullYear()}Y-${ 44 | date.getMonth() + 1 45 | }M-${date.getDate()}D-${date.getHours()}H`; 46 | } 47 | -------------------------------------------------------------------------------- /Quantumult-X/campusphere.js: -------------------------------------------------------------------------------- 1 | let cp = {}; 2 | cp.long = $prefs.valueForKey("经度"); 3 | cp.la = $prefs.valueForKey("纬度"); 4 | cp.location = $prefs.valueForKey("地区"); 5 | (async function() { 6 | await login() 7 | await wid() 8 | await form() 9 | await submit() 10 | $done(); 11 | })(); 12 | 13 | function login() { 14 | console.log("await response") 15 | const Head = { 16 | url: 'http://' + $prefs.valueForKey("ip") + ':8080/wisedu-unified-login-api-v1.0/swagger-ui.html', 17 | method: "HEAD" 18 | }; 19 | const loginurl = { 20 | url: 'http://' + $prefs.valueForKey("ip") + ':8080/wisedu-unified-login-api-v1.0/api/login?login_url=http%3A%2F%2Fauthserver.' + $prefs.valueForKey("学校") + '.cn%2Fauthserver%2Flogin%3Fservice%3Dhttps%253A%252F%252F' + $prefs.valueForKey("学校") + '.campusphere.net%252Fiap%252FloginSuccess&password=' + $prefs.valueForKey("密码") + '&username=' + $prefs.valueForKey("账号") 21 | }; 22 | return new Promise(function(resolve) { 23 | $task.fetch(Head).then(response => { 24 | console.log(response.statusCode) 25 | if (response.statusCode != 200) { 26 | login() 27 | } else { 28 | console.log("await login") 29 | $task.fetch(loginurl).then(resp => { 30 | if (typeof(resp.body) == "undefined") { 31 | console.log(resp.body) 32 | login() 33 | } else { 34 | let jsonData = JSON.parse(resp.body); 35 | if (jsonData.msg != "login success!") { 36 | login() 37 | } else { 38 | let cookies = jsonData.cookies 39 | let regex = /route.*MOD_AUTH_CAS/ 40 | cp.cookie = cookies.replace(regex, "MOD_AUTH_CAS") 41 | console.log('\n' + cp.cookie) 42 | resolve() 43 | } 44 | } 45 | }, reason => { 46 | console.log(reason.error) 47 | login() 48 | }) 49 | } 50 | }, reason => { 51 | console.log(reason.error) 52 | login() 53 | }); 54 | }); 55 | } 56 | 57 | function wid() { 58 | console.log("await wid") 59 | const widurl = { 60 | url: 'https://' + $prefs.valueForKey("学校") + '.campusphere.net/wec-counselor-sign-apps/stu/sign/getStuSignInfosInOneDay', 61 | method: "POST", 62 | headers: { 63 | 'Cookie' : cp.cookie, 64 | 'Content-Type' : 'application/json;charset=utf-8' 65 | }, 66 | body: '{}' 67 | }; 68 | return new Promise(function(resolve) { 69 | $task.fetch(widurl).then(response => { 70 | let jsonData = JSON.parse(response.body); 71 | console.log('\n' + response.body) 72 | cp.leave = jsonData["datas"].leaveTasks[0] 73 | cp.unsign = jsonData["datas"].unSignedTasks[0] 74 | if (typeof(cp.unsign) == "undefined" && typeof(cp.leave) == "undefined") { 75 | console.log("无签到") 76 | $done($notify("无签到","","")) 77 | } else if (typeof(cp.unsign) == "undefined") { 78 | cp.wid = jsonData["datas"].leaveTasks[0].signInstanceWid 79 | cp.signWid = jsonData["datas"].leaveTasks[0].signWid 80 | resolve(); 81 | } else { 82 | cp.wid = jsonData["datas"].unSignedTasks[0].signInstanceWid 83 | cp.signWid = jsonData["datas"].unSignedTasks[0].signWid 84 | resolve(); 85 | } 86 | }, reason => { 87 | console.log(reason.error) 88 | wid() 89 | }) 90 | }); 91 | } 92 | 93 | function form() { 94 | console.log("await form") 95 | const formurl = { 96 | url: 'https://' + $prefs.valueForKey("学校") + '.campusphere.net/wec-counselor-sign-apps/stu/sign/detailSignInstance', 97 | method: "POST", 98 | headers: { 99 | 'Cookie' : cp.cookie, 100 | 'Content-Type' : 'application/json;charset=utf-8' 101 | }, 102 | body: `{ 103 | "signWid": ${cp.signWid}, 104 | "signInstanceWid": ${cp.wid} 105 | }` 106 | }; 107 | return new Promise(function(resolve) { 108 | $task.fetch(formurl).then(response => { 109 | let jsonData = JSON.parse(response.body); 110 | cp.formWid = jsonData.datas.extraField[0].extraFieldItems[0].wid 111 | cp.formWid1 = jsonData.datas.extraField[1].extraFieldItems[0].wid 112 | cp.formWid2 = jsonData.datas.extraField[2].extraFieldItems[0].wid 113 | cp.formWid3 = jsonData.datas.extraField[3].extraFieldItems[0].wid 114 | cp.formWid4 = jsonData.datas.extraField[4].extraFieldItems[0].wid 115 | cp.formcontent = jsonData.datas.extraField[0].extraFieldItems[0].content 116 | cp.formcontent1 = jsonData.datas.extraField[1].extraFieldItems[0].content 117 | cp.formcontent2 = jsonData.datas.extraField[2].extraFieldItems[0].content 118 | cp.formcontent3 = jsonData.datas.extraField[3].extraFieldItems[0].content 119 | cp.formcontent4 = jsonData.datas.extraField[4].extraFieldItems[0].content 120 | resolve(); 121 | }, reason => { 122 | console.log(reason.error) 123 | form() 124 | }) 125 | }) 126 | } 127 | function submit() { 128 | console.log("await submit") 129 | const bodys = { 130 | "abnormalReason": "", 131 | "position": `${cp.location}`, 132 | "longitude": `${cp.long}`, 133 | "isNeedExtra": 1, 134 | "latitude": `${cp.la}`, 135 | "isMalposition": 1, 136 | "extraFieldItems": [ 137 | { 138 | "extraFieldItemWid": `${cp.formWid}`, 139 | "extraFieldItemValue": `${cp.formcontent}` 140 | }, 141 | { 142 | "extraFieldItemWid": `${cp.formWid1}`, 143 | "extraFieldItemValue": `${cp.formcontent1}` 144 | }, 145 | { 146 | "extraFieldItemWid": `${cp.formWid2}`, 147 | "extraFieldItemValue": `${cp.formcontent2}` 148 | }, 149 | { 150 | "extraFieldItemWid": `${cp.formWid3}`, 151 | "extraFieldItemValue": `${cp.formcontent3}` 152 | }, 153 | { 154 | "extraFieldItemWid": `${cp.formWid4}`, 155 | "extraFieldItemValue": `${cp.formcontent4}` 156 | } 157 | ], 158 | "signPhotoUrl": "", 159 | "uaIsCpadaily": false, 160 | "signInstanceWid": `${cp.wid}` 161 | } 162 | const submiturl = { 163 | url: 'https://' + $prefs.valueForKey("学校") + '.campusphere.net/wec-counselor-sign-apps/stu/sign/submitSign', 164 | method: "POST", 165 | headers: { 166 | 'Cookie' : cp.cookie, 167 | 'Content-Type' : 'application/json;charset=utf-8' 168 | }, 169 | body: JSON.stringify(bodys) 170 | }; 171 | return new Promise(function(resolve) { 172 | $task.fetch(submiturl).then(response => { 173 | let jsonData = JSON.parse(response.body); 174 | cp.msg = jsonData.message 175 | console.log(cp.msg) 176 | $notify("今日校园", cp.msg, "") 177 | resolve(); 178 | }, reason => { 179 | console.log(reason.error) 180 | submit() 181 | }) 182 | }); 183 | } 184 | -------------------------------------------------------------------------------- /Quantumult-X/topsports.js: -------------------------------------------------------------------------------- 1 | //滔搏运动(TopSports)发售监控 2 | /*********** 3 | 暂不支持多城市监控,如需要请配置多个本地脚本或修改脚本本体(小白勿动) 4 | 5 | 已支持多双鞋发售通知 6 | 7 | 只支持Quantumult X / Loon(因名字不能清楚知道鞋子样子,所以需要图片通知来决定是否需要去抽奖,所以暂不支持surge,Loon未适配) 8 | 9 | qx脚本配置(cron按需自行修改): 10 | 11 | [task_local] 12 | 50 8,10,11,12,13,14 * * * https://github.com/DecoAri/JavaScript/blob/main/Quantumult-X/topsports.js?raw=true, tag=滔搏监控, enabled=true 13 | 14 | 15 | 城市代码请复制以下url在浏览器打开查看cityCode 16 | https://m-app.topsports.com.cn/app/location/cityList 17 | 18 | ⚠️⚠️⚠️使用前请先运行以下脚本 19 | 打开qx,点击右下角风车,下拉找到工具&分析,点击构造HTTP请求,再点击右下角的写脚本图标,进去之后删除里面全部内容,复制以下代码并替换里面的中文,然后运行即可。 20 | 21 | $done($prefs.setValueForKey("请修改此中文为城市代码", "cityCode")) 22 | 23 | ***********/ 24 | //以下为脚本本体 25 | 26 | 27 | 28 | const getShoes = { 29 | url: "https://m-app-cdn.topsports.com.cn/presale-api/activity/list?brandCode=TS&cityCode=" + $prefs.valueForKey("cityCode") + "¤t=1&pageSize=10", 30 | method: "GET" 31 | }; 32 | 33 | $task.fetch(getShoes).then(response => { 34 | let jsonData = JSON.parse(response.body) 35 | let i = 0 36 | let shoes = jsonData.data.extend 37 | if (shoes == null) { 38 | console.log("👟没有新鞋发售") 39 | } else { 40 | while (shoes) { 41 | if (jsonData.data.extend[i] == undefined) { 42 | break; 43 | } else { 44 | shoes = jsonData.data.extend[i] 45 | console.log(JSON.stringify(shoes)) 46 | let start = time(jsonData.data.extend[i].exchangeStartTime) 47 | let end = time(jsonData.data.extend[i].exchangeEndTime) 48 | $notify("👟有新鞋发售啦", jsonData.data.extend[i].productName, "发售时间:" + start +"\n" + "结束时间:" + end, {"media-url": jsonData.data.extend[i].indexPicUrl}); 49 | console.log("👟有新鞋发售啦" + "\n" + jsonData.data.extend[i].productName + "\n" + "发售时间:" + start +"\n" + "结束时间:" + end) 50 | i++ 51 | } 52 | } 53 | } 54 | $done() 55 | }, reason => { 56 | $notify("滔搏发售", "脚本运行出错", reason.error); 57 | $done(); 58 | }); 59 | 60 | 61 | function time(releaseDate) { 62 | var date = new Date(releaseDate); 63 | Y = date.getFullYear() + '-'; 64 | M = (date.getMonth()+1 < 10 ? '0'+(date.getMonth()+1) : date.getMonth()+1) + '-'; 65 | D = (date.getDate() < 10 ? '0'+(date.getDate()) : date.getDate()) + ' '; 66 | h = (date.getHours() < 10 ? '0'+(date.getHours()) : date.getHours()) + ':'; 67 | m = (date.getMinutes() < 10 ? '0'+(date.getMinutes()) : date.getMinutes()) + ':'; 68 | s = (date.getSeconds() < 10 ? '0'+(date.getSeconds()) : date.getSeconds()); 69 | return Y+M+D+h+m+s; 70 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | *JavaScript* 2 | 3 | 原创 4 | 5 | 仅供学习,若侵权请联系删除,忽做违法用途,若他人用此项目违反法律或其他规定,出现任何问题,与作者无关。可借鉴修改 6 | -------------------------------------------------------------------------------- /Shadowrocket/campusphere.js: -------------------------------------------------------------------------------- 1 | let cp = {}; 2 | cp.long = $persistentStore.read("经度"); 3 | cp.la = $persistentStore.read("纬度"); 4 | cp.location = $persistentStore.read("地区"); 5 | (async function() { 6 | await login(); 7 | await wid(); 8 | await form(); 9 | await submit(); 10 | $done(); 11 | })(); 12 | function login() { 13 | console.log("await login") 14 | const loginurl = { 15 | url: 'http://' + $persistentStore.read("ip") + ':8080/wisedu-unified-login-api-v1.0/api/login?login_url=http%3A%2F%2Fauthserver.' + $persistentStore.read("学校") + '.cn%2Fauthserver%2Flogin%3Fservice%3Dhttps%253A%252F%252F' + $persistentStore.read("学校") + '.campusphere.net%252Fiap%252FloginSuccess&password=' + $persistentStore.read("密码") + '&username=' + $persistentStore.read("账号") 16 | }; 17 | return new Promise(function(resolve) { 18 | $httpClient.post(loginurl, function(error, resp, data) { 19 | if (typeof(resp) == "undefined") { 20 | console.log(resp) 21 | login() 22 | }else if (resp.statusCode != 200) { 23 | console.log(resp.statusCode) 24 | login() 25 | } else { 26 | let jsonData = JSON.parse(data); 27 | console.log(jsonData.msg) 28 | if (jsonData.msg != "login success!") { 29 | login() 30 | } else { 31 | let cookies = jsonData.cookies 32 | let regex = /route.*MOD_AUTH_CAS/ 33 | cp.cookie = cookies.replace(regex, "MOD_AUTH_CAS") 34 | console.log('\n' + cp.cookie) 35 | resolve(); //异步操作成功时调用, 将Promise对象的状态标记为"成功", 表示已完成 36 | } 37 | } 38 | }); 39 | }); 40 | } 41 | 42 | function wid() { 43 | console.log("await wid") 44 | const widurl = { 45 | url: 'https://' + $persistentStore.read("学校") + '.campusphere.net/wec-counselor-sign-apps/stu/sign/getStuSignInfosInOneDay', 46 | headers: { 47 | 'Cookie' : cp.cookie, 48 | 'Content-Type' : `application/json;charset=utf-8` 49 | }, 50 | body: '{}' 51 | }; 52 | return new Promise(function(resolve) { 53 | $httpClient.post(widurl, function(error, resp, data) { 54 | let jsonData = JSON.parse(data); 55 | console.log('\n' + data) 56 | cp.leave = jsonData["datas"].leaveTasks[0] 57 | cp.unsign = jsonData["datas"].unSignedTasks[0] 58 | if (typeof(cp.unsign) == "undefined" && typeof(cp.leave) == "undefined") { 59 | console.log("无签到") 60 | $done($notification.post("无签到","","")) 61 | } else if (typeof(cp.unsign) == "undefined") { 62 | cp.wid = jsonData["datas"].leaveTasks[0].signInstanceWid 63 | cp.signWid = jsonData["datas"].leaveTasks[0].signWid 64 | resolve(); 65 | } else { 66 | cp.wid = jsonData["datas"].unSignedTasks[0].signInstanceWid 67 | cp.signWid = jsonData["datas"].unSignedTasks[0].signWid 68 | resolve(); 69 | } 70 | }); 71 | }); 72 | } 73 | 74 | function form() { 75 | console.log("await form") 76 | const formurl = { 77 | url: 'https://' + $persistentStore.read("学校") + '.campusphere.net/wec-counselor-sign-apps/stu/sign/detailSignInstance', 78 | headers: { 79 | 'Cookie' : cp.cookie, 80 | 'Content-Type' : 'application/json;charset=utf-8' 81 | }, 82 | body: `{ 83 | "signWid": ${cp.signWid}, 84 | "signInstanceWid": ${cp.wid} 85 | }`, 86 | }; 87 | return new Promise(function(resolve) { 88 | $httpClient.post(formurl, function(error, resp, data) { 89 | let jsonData = JSON.parse(data); 90 | cp.formWid = jsonData.datas.extraField[0].extraFieldItems[0].wid 91 | cp.formWid1 = jsonData.datas.extraField[1].extraFieldItems[0].wid 92 | cp.formWid2 = jsonData.datas.extraField[2].extraFieldItems[0].wid 93 | cp.formWid3 = jsonData.datas.extraField[3].extraFieldItems[0].wid 94 | cp.formWid4 = jsonData.datas.extraField[4].extraFieldItems[0].wid 95 | cp.formcontent = jsonData.datas.extraField[0].extraFieldItems[0].content 96 | cp.formcontent1 = jsonData.datas.extraField[1].extraFieldItems[0].content 97 | cp.formcontent2 = jsonData.datas.extraField[2].extraFieldItems[0].content 98 | cp.formcontent3 = jsonData.datas.extraField[3].extraFieldItems[0].content 99 | cp.formcontent4 = jsonData.datas.extraField[4].extraFieldItems[0].content 100 | resolve(); 101 | }) 102 | }) 103 | } 104 | function submit() { 105 | console.log("await submit") 106 | const bodys = { 107 | "abnormalReason": "", 108 | "position": `${cp.location}`, 109 | "longitude": `${cp.long}`, 110 | "isNeedExtra": 1, 111 | "latitude": `${cp.la}`, 112 | "isMalposition": 1, 113 | "extraFieldItems": [ 114 | { 115 | "extraFieldItemWid": `${cp.formWid}`, 116 | "extraFieldItemValue": `${cp.formcontent}` 117 | }, 118 | { 119 | "extraFieldItemWid": `${cp.formWid1}`, 120 | "extraFieldItemValue": `${cp.formcontent1}` 121 | }, 122 | { 123 | "extraFieldItemWid": `${cp.formWid2}`, 124 | "extraFieldItemValue": `${cp.formcontent2}` 125 | }, 126 | { 127 | "extraFieldItemWid": `${cp.formWid3}`, 128 | "extraFieldItemValue": `${cp.formcontent3}` 129 | }, 130 | { 131 | "extraFieldItemWid": `${cp.formWid4}`, 132 | "extraFieldItemValue": `${cp.formcontent4}` 133 | } 134 | ], 135 | "signPhotoUrl": "", 136 | "uaIsCpadaily": false, 137 | "signInstanceWid": `${cp.wid}` 138 | } 139 | const submiturl = { 140 | url: 'https://' + $persistentStore.read("学校") + '.campusphere.net/wec-counselor-sign-apps/stu/sign/submitSign', 141 | headers: { 142 | 'Cookie' : cp.cookie, 143 | 'Content-Type' : 'application/json;charset=utf-8' 144 | }, 145 | body: JSON.stringify(bodys) 146 | }; 147 | return new Promise(function(resolve) { 148 | $httpClient.post(submiturl, function(error, resp, data) { 149 | let jsonData = JSON.parse(data); 150 | cp.msg = jsonData.message 151 | console.log(cp.msg) 152 | $notification.post("今日校园", cp.msg, "") 153 | resolve(); 154 | }); 155 | }); 156 | } -------------------------------------------------------------------------------- /Surge/Auto_join_TF.js: -------------------------------------------------------------------------------- 1 | !(async () => { 2 | ids = $persistentStore.read('APP_ID') 3 | if (ids == '') { 4 | $notification.post('所有TF已加入完毕','模块已自动关闭','') 5 | $done($httpAPI('POST', '/v1/modules', {'Auto module for JavaScripts': 'false'})) 6 | } else { 7 | ids = ids.split(',') 8 | for await (const ID of ids) { 9 | await autoPost(ID) 10 | } 11 | } 12 | $done() 13 | })(); 14 | 15 | function autoPost(ID) { 16 | let Key = $persistentStore.read('key') 17 | let testurl = 'https://testflight.apple.com/v3/accounts/' + Key + '/ru/' 18 | let header = { 19 | 'X-Session-Id': `${$persistentStore.read('session_id')}`, 20 | 'X-Session-Digest': `${$persistentStore.read('session_digest')}`, 21 | 'X-Request-Id': `${$persistentStore.read('request_id')}`, 22 | 'X-Apple-AMD-X': `${$persistentStore.read('X-Apple-AMD-X')}`, 23 | 'User-Agent': `${$persistentStore.read('TFUA')}` 24 | } 25 | return new Promise(function(resolve) { 26 | $httpClient.get({url: testurl + ID,headers: header}, function(error, resp, data) { 27 | if (error === null) { 28 | if (resp.status == 404) { 29 | ids = $persistentStore.read('APP_ID').split(',') 30 | ids = ids.filter(ids => ids !== ID) 31 | $persistentStore.write(ids.toString(),'APP_ID') 32 | console.log(ID + ' ' + '不存在该TF,已自动删除该APP_ID') 33 | $notification.post(ID, '不存在该TF', '已自动删除该APP_ID') 34 | resolve() 35 | } else { 36 | let jsonData = JSON.parse(data) 37 | if (jsonData.data == null) { 38 | console.log(ID + ': ' + jsonData.messages[0].message) 39 | resolve(); 40 | } else if (jsonData.data.status == 'FULL') { 41 | var name = jsonData.data.app.name 42 | console.log(name + ' (' + ID + '): ' + jsonData.data.message) 43 | resolve(); 44 | } else { 45 | $httpClient.post({url: testurl + ID + '/accept',headers: header}, function(error, resp, body) { 46 | let appName = JSON.parse(body).data.name 47 | $notification.post('🎉' + appName, 'TestFlight加入成功', '') 48 | console.log('🎉' + appName + '🎉' + ' (' + ID + '): ' + ' TestFlight加入成功') 49 | ids = $persistentStore.read('APP_ID').split(',') 50 | ids = ids.filter(ids => ids !== ID) 51 | $persistentStore.write(ids.toString(),'APP_ID') 52 | resolve() 53 | }); 54 | } 55 | } 56 | } else { 57 | if (error =='The request timed out.') { 58 | resolve(); 59 | } else if (error.includes("error -1012")) { 60 | $notification.post('自动加入TF', error,'请获取TF账户信息,模块已自动关闭,获取成功后再自行打开模块') 61 | $done($httpAPI('POST', '/v1/modules', {'Auto module for JavaScripts': 'false'})) 62 | resolve(); 63 | } else { 64 | $notification.post('自动加入TF', error,'') 65 | console.log(ID + ': ' + error) 66 | resolve(); 67 | } 68 | } 69 | }) 70 | }) 71 | } -------------------------------------------------------------------------------- /Surge/CMB_ID.js: -------------------------------------------------------------------------------- 1 | let chnlUserId = JSON.parse($request.body).chnlUserId 2 | $persistentStore.write(chnlUserId, 'chnlUserId') 3 | console.log('若chnlUserId后有字符串则获取成功\nchnlUserId:' + $persistentStore.read('chnlUserId')) 4 | $done({}) -------------------------------------------------------------------------------- /Surge/CMB_piao.js: -------------------------------------------------------------------------------- 1 | //Adjust yourself or waiting for me. 2 | 3 | (async function() { 4 | await OMG(); 5 | $done(); 6 | })(); 7 | 8 | function OMG() { 9 | return new Promise(function(resolve) { 10 | $httpClient.post({url: 'https://fpwx.o2o.cmbchina.com/wechatmp-gateway/wechat/rush/order/create', headers: {'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.26(0x18001a25) NetType/WIFI Language/en', 'Content-Type': 'application/json'}, body: {"chnlUserId":`${$persistentStore.read("chnlUserId")}`,"chnlId":"01","productNo":$persistentStore.read("productNo"),"productBakNo":$persistentStore.read("productBakNo"),"buyCount":1,"cardType":"1100","userVouId":null,"cityNo":$persistentStore.read("cityNo"),"longitude":$persistentStore.read("longitude"),"dimension":$persistentStore.read("dimension"),"blackListToken":""}}, function(error,resp,body) { 11 | let msg = JSON.parse(body).respMsg 12 | let code = JSON.parse(body).respCode 13 | if (code == 1000 || code == "COU_PC_0000000019" || code == "COU_PC_0000000026") { 14 | $notification.post("🛍️周二提前购", "🧾订单状态:" + msg,"⚠️仅限周三使用哦(不要忘了去掌上生活付款)") 15 | resolve(); 16 | } else { 17 | console.log(msg) 18 | OMG() 19 | } 20 | }) 21 | }) 22 | } -------------------------------------------------------------------------------- /Surge/Capture.js: -------------------------------------------------------------------------------- 1 | !(async () => { 2 | let mods = (await httpAPI("GET", "/v1/modules", null)) 3 | let modsStatus = /MitM All Hostnames/.test(mods.enabled) 4 | let capture = (await httpAPI("GET", "/v1/features/capture", null)) 5 | if ($trigger === "button") { 6 | if (capture.enabled == false){ 7 | await httpAPI("POST", "/v1/features/capture", {enabled: "true"}) 8 | await httpAPI("POST", "/v1/modules", {"MitM All Hostnames": "true"}) 9 | $done({ 10 | title:"HTTP Capture", 11 | content:"Capture: \u2611 Hostnames: \u2611", 12 | icon: "hand.raised.square.on.square.fill", 13 | "icon-color": "ED0001" 14 | }) 15 | } else { 16 | await httpAPI("POST", "/v1/features/capture", {enabled: "false"}) 17 | await httpAPI("POST", "/v1/modules", {"MitM All Hostnames": "false"}) 18 | $done({ 19 | title:"HTTP Capture", 20 | content:"Capture: \u2612 Hostnames: \u2612", 21 | icon: "archivebox", 22 | "icon-color": "88989F" 23 | }) 24 | } 25 | } else if(modsStatus == true || capture.enabled == true) { 26 | $done({ 27 | title:"HTTP Capture", 28 | content:"Capture: " + iconStatus(capture.enabled) + " Hostnames: " + iconStatus(modsStatus), 29 | icon: "hand.raised.square.on.square.fill", 30 | "icon-color": "ED0001" 31 | }) 32 | } else { 33 | $done({ 34 | title:"HTTP Capture", 35 | content:"Capture: " + iconStatus(capture.enabled) + " Hostnames: " + iconStatus(modsStatus), 36 | icon: "archivebox", 37 | "icon-color": "88989F" 38 | }) 39 | } 40 | })(); 41 | 42 | function httpAPI(method = "", path = "", body = "") { 43 | return new Promise((resolve) => { 44 | $httpAPI(method, path, body, (result) => { 45 | resolve(result); 46 | }); 47 | }); 48 | } 49 | 50 | function iconStatus(status) { 51 | if (status) { 52 | return "\u2611"; 53 | } else { 54 | return "\u2612" 55 | } 56 | } -------------------------------------------------------------------------------- /Surge/EPIC_free_games.js: -------------------------------------------------------------------------------- 1 | /* 2 | 适配tf版本通知 3 | 建议cron:1 0 * * * 4 | 相比于rsshub来说,信息来自官网,更新更及时 5 | QX的js请去Quantumult X的文件夹路径寻找 6 | */ 7 | 8 | 9 | 10 | $httpClient.get({url:"https://store-site-backend-static-ipv4.ak.epicgames.com/freeGamesPromotions?locale=en-US&country=US&allowCountries=US"}, function(error,resp,body) { 11 | let jsonBody = JSON.parse(body) 12 | let i = 0 13 | let games = jsonBody.data.Catalog.searchStore.elements 14 | while (games) { 15 | if (jsonBody.data.Catalog.searchStore.elements[i] == undefined) { 16 | break; 17 | } else if (jsonBody.data.Catalog.searchStore.elements[i].title == "Mystery Game") { 18 | i++ 19 | } else { 20 | games = jsonBody.data.Catalog.searchStore.elements[i] 21 | console.log(games) 22 | if (games.promotions == null) { 23 | $notification.post('🎮EPIC: ' + games.title, '🕒UPCOMING: ' + 'UNKNOWN', '📜DESCRIPTION: ' + games.description, {'media-url':games.keyImages[1].url}) 24 | i++ 25 | } else if (games.promotions.upcomingPromotionalOffers == '') { 26 | $notification.post('🎮EPIC: ' + games.title, '🕒OPEN: ' + transFormTime(games.promotions.promotionalOffers[0].promotionalOffers[0].startDate) + '\n🕐END: ' + transFormTime(games.promotions.promotionalOffers[0].promotionalOffers[0].endDate), '📜DESCRIPTION: ' + games.description, {'media-url':games.keyImages[1].url,'action':'open-url','url':'https://store.epicgames.com/en-US/p/'+games.catalogNs.mappings[0].pageSlug}) 27 | i++ 28 | } else { 29 | $notification.post('🎮EPIC: ' + games.title, '🕒UPCOMING: ' + transFormTime(games.promotions.upcomingPromotionalOffers[0].promotionalOffers[0].startDate) + '\n🕐END: ' + transFormTime(games.promotions.upcomingPromotionalOffers[0].promotionalOffers[0].endDate), '📜DESCRIPTION: ' + games.description, {'media-url':games.keyImages[1].url,'action':'open-url','url':'https://store.epicgames.com/en-US/p/'+games.catalogNs.mappings[0].pageSlug}) 30 | i++ 31 | } 32 | } 33 | } 34 | $done() 35 | }) 36 | 37 | function transFormTime(times) { 38 | const date = new Date(times); 39 | return `${date.getFullYear()}Y-${ 40 | date.getMonth() + 1 41 | }M-${date.getDate()}D-${date.getHours()}H`; 42 | } -------------------------------------------------------------------------------- /Surge/Follow.js: -------------------------------------------------------------------------------- 1 | /**************** 2 | 只需要以下三个就能自动签到 3 | https://api.follow.is/wallets?userId=xxxxxxx 4 | 1: 这整个url 5 | 6 | 7 | https://api.follow.is/wallets/transactions/claim_daily 8 | 2: 请求头的cookie:authjs.session-token= 9 | 3: 整个请求体 10 | 11 | 现在已经有人写了脚本转换器。所以QX loon shadowrocket不再更新 12 | 以下示例脚本 自己改 13 | ****************/ 14 | 15 | function getPower(callback) { 16 | $httpClient.get({ 17 | url: $persistentStore.read('Follow_URL'), headers: {'cookie': 'authjs.session-token=' + `${$persistentStore.read('Follow_sToken')}`} 18 | }, function (error, resp, body) { 19 | let power = JSON.parse(body).data[0].dailyPowerToken / 1e18 20 | callback(power); // 将获取到的 power 通过回调传递给调用者 21 | }); 22 | } 23 | 24 | function postRequest() { 25 | $httpClient.post({ 26 | url: 'https://api.follow.is/wallets/transactions/claim_daily', 27 | headers: {'cookie': 'authjs.session-token=' + `${$persistentStore.read('Follow_sToken')}` + ';' + `${$persistentStore.read('Follow_CSRF')}`}, 28 | body: {"csrfToken": `${$persistentStore.read('Follow_csrfToken')}`} 29 | }, function (error, res, data) { 30 | let code = JSON.parse(data).code; 31 | console.log('Code: ' + code); 32 | 33 | if (code === 0) { 34 | getPower(function (finalPower) { // 如果code=0,再次获取power 35 | console.log('Final Power after POST: ' + finalPower); 36 | $notification.post('Follow', 'Power: ' + finalPower,'Sign successful. 数据可能有延迟。如需确认请自行登录Follow点击刷新power', {'media-url':'https://app.follow.is/opengraph-image.png'}) 37 | $done(); // 完成流程 38 | }); 39 | } else if (code === 4000) { 40 | console.log("Retrying request..."); 41 | postRequest(); // 如果code=4000,重新发起POST请求(不获取power) 42 | } else if (code === 1000) { 43 | $notification.post('Follow', '未授权', '请重新获取cookie', {'media-url':'https://app.follow.is/opengraph-image.png'}) 44 | console.log(data) 45 | $done(); // 其他情况结束流程 46 | } else { 47 | $notification.post('其他错误', '查看日志', '') 48 | console.log('\n'+error + '\n'+res + '\n'+data) 49 | $done() 50 | } 51 | }); 52 | } 53 | 54 | getPower(function (initialPower) { // 脚本运行时首次获取power 55 | console.log('Initial Power before POST: ' + initialPower); 56 | $notification.post('Follow', 'Power: ' + initialPower,'如果没收到Power更新通知请重新执行脚本', {'media-url':'https://app.follow.is/opengraph-image.png'}) 57 | postRequest(); // 获取完power后,开始执行POST请求 58 | }); -------------------------------------------------------------------------------- /Surge/IP-Geolocation.js: -------------------------------------------------------------------------------- 1 | const flags = new Map([[ "NA" , "globe.americas.fill" ],["SA","globe.americas.fill"], [ "EU" , "globe.europe.africa.fill" ], [ "AS" , "globe.asia.australia.fill" ], [ "OC" , "globe.asia.australia.fill" ], [ "AF" , "globe.europe.africa.fill" ]]) 2 | const carriers = new Map([["460-03","China Telecom"], ["460-05","China Telecom"], ["460-11","China Telecom"], ["460-01","China Unicom"], ["460-06","China Unicom"], ["460-09","China Unicom"], ["460-00","China Mobile"], ["460-02","China Mobile"], ["460-04","China Mobile"], ["460-07","China Mobile"], ["460-08","China Mobile"], ["460-15","China Broadcasting Network"], ["460-20","China Mobile"]]) 3 | 4 | $httpClient.get({url: 'https://www.youtube.com/premium', headers: {'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36'}}, function(error,resp,body) { 5 | let reg = new RegExp ("contentRegion\\\":\\\"\\w{2}\\\"") 6 | let a = JSON.stringify(reg.exec(body)) 7 | console.log(a) 8 | let YouTube = a.replace(/(\[\"contentRegion\\\":\\\")(\w+)\\\"\"\]/, '$2') 9 | $httpClient.get("http://ip-api.com/json/", function(error, response, body){ 10 | $httpClient.get("http://ip-api.com/json/" + JSON.parse(body).query + "?fields=status,message,continent,continentCode,country,countryCode,region,regionName,city,district,zip,lat,lon,timezone,offset,currency,isp,org,as,asname,reverse,mobile,proxy,hosting,query", function(error, response, body){ 11 | if ($network.wifi.ssid == null) { 12 | $done({ 13 | title: carriers.get($network["cellular-data"].carrier) + "|" + $network["cellular-data"].radio, 14 | content: `${flagEmojis(JSON.parse(body).countryCode)}: ${JSON.parse(body).city} :${flagEmojis(YouTube)}\nISP: ${JSON.parse(body).isp}`, 15 | icon: flags.get(JSON.parse(body).continentCode), 16 | 'icon-color': $argument 17 | }) 18 | } else { 19 | $done({ 20 | title: $network.wifi.ssid, 21 | content: `${flagEmojis(JSON.parse(body).countryCode)}: ${JSON.parse(body).city} :${flagEmojis(YouTube)}\nISP: ${JSON.parse(body).isp}`, 22 | icon: flags.get(JSON.parse(body).continentCode), 23 | 'icon-color': $argument 24 | }) 25 | } 26 | }) 27 | }) 28 | }) 29 | 30 | function flagEmojis(country_code) { 31 | const codes = (country_code == 'TW' || country_code == 'HK') ? 'CN':country_code 32 | const codePoints = codes 33 | .toUpperCase() 34 | .split('') 35 | .map(char => 127397 + char.charCodeAt()); 36 | return String.fromCodePoint(...codePoints); 37 | } -------------------------------------------------------------------------------- /Surge/IP-Score-All-Info.js: -------------------------------------------------------------------------------- 1 | /*** 2 | 本人懒,懒得改能用就行 3 | 4 | IP检测评分等等等等等等,懒得写了 5 | ***/ 6 | 7 | 8 | let net = {}; //预留的空对象, 便于"函数"(function)之间读 9 | 10 | net.中国电信 = ['460-03','460-05','460-11']; 11 | net.中国联通 = ['460-01','460-06','460-09']; 12 | net.中国移动 = ['460-00','460-02','460-04','460-07','460-08']; 13 | net.中国广电 = ['460-15']; 14 | net.中国铁通 = ['460-20']; 15 | net.v4 = $network.v4.primaryAddress 16 | net.ssid = $network.wifi.ssid 17 | net.carrier = $network["cellular-data"].carrier 18 | net.router = $network.v4.primaryRouter 19 | net.radio = $network["cellular-data"].radio; 20 | 21 | (async function() { 22 | await ipapi(); 23 | await Promise.all([ 24 | scam(), 25 | ipinfo(), 26 | youtube() 27 | ]); 28 | var regex=/^192.168/ 29 | if(regex.test(net.v4)){ 30 | if(net.v4 == net.query){ 31 | $done({ 32 | title: `${net.ssid}`, 33 | content: `ASN: `+net.asn+`\n`+net.youtube+`: Google `+net.emoji+`: `+net.query+`\nIPs: `+net.router+` & `+net.v4+`\nFraud score: `+net.score+` `+net.risk+` risk`+`\nTor: `+net.tor+` VPN: `+net.vpn+`\nRelay: `+net.relay+` Proxy: `+net.proxy+`\nServer: `+net.server+` Hosting: `+net.hosting+`\nASN Type: `+net.atype+`\nName: `+net.aname+`\nCompany Type: `+net.ctype+`\nName: `+net.cname, 34 | icon: "wifi", 35 | 'icon-color': "#00FF00" 36 | }); 37 | }else{ 38 | $done({ 39 | title: `${net.ssid}`, 40 | content: `ASN: `+net.asn+`\n`+net.youtube+`: Google `+net.emoji+`: `+net.query+`\nIPs: `+net.router+` & `+net.v4+`\nFraud score: `+net.score+` `+net.risk+` risk`+`\nTor: `+net.tor+` VPN: `+net.vpn+`\nRelay: `+net.relay+` Proxy: `+net.proxy+`\nServer: `+net.server+` Hosting: `+net.hosting+`\nASN Type: `+net.atype+`\nName: `+net.aname+`\nCompany Type: `+net.ctype+`\nName: `+net.cname, 41 | icon: "wifi", 42 | 'icon-color': "#00FF00" 43 | }); 44 | } 45 | }else if(`${net.radio}` == "null"){ 46 | if(`${net.v4}` == `${net.query}`){ 47 | $done({ 48 | title: `Hotspot`, 49 | content: `ASN: `+net.asn+`\n`+net.youtube+`: Google `+net.emoji+`: `+net.query+`\nIPs: `+net.router+` & `+net.v4+`\nFraud score: `+net.score+` `+net.risk+` risk`+`\nTor: `+net.tor+` VPN: `+net.vpn+`\nRelay: `+net.relay+` Proxy: `+net.proxy+`\nServer: `+net.server+` Hosting: `+net.hosting+`\nASN Type: `+net.atype+`\nName: `+net.aname+`\nCompany Type: `+net.ctype+`\nName: `+net.cname, 50 | icon: "personalhotspot", 51 | 'icon-color': "#0000FF" 52 | }); 53 | }else{ 54 | $done({ 55 | title: `Hotspot`, 56 | content: `ASN: `+net.asn+`\n`+net.youtube+`: Google `+net.emoji+`: `+net.query+`\nIPs: `+net.router+` & `+net.v4+`\nFraud score: `+net.score+` `+net.risk+` risk`+`\nTor: `+net.tor+` VPN: `+net.vpn+`\nRelay: `+net.relay+` Proxy: `+net.proxy+`\nServer: `+net.server+` Hosting: `+net.hosting+`\nASN Type: `+net.atype+`\nName: `+net.aname+`\nCompany Type: `+net.ctype+`\nName: `+net.cname, 57 | icon: "personalhotspot", 58 | 'icon-color': "#0000FF" 59 | }); 60 | } 61 | }else{ 62 | if(net.中国电信.includes(net.carrier)){ 63 | net.运营商 = "China Telecom"; 64 | }else if(net.中国联通.includes(net.carrier)){ 65 | net.运营商 = "China Unicom"; 66 | }else if(net.中国移动.includes(net.carrier)){ 67 | net.运营商 = "China Mobile"; 68 | }else if(net.中国广电.includes(net.carrier)){ 69 | net.运营商 = "China Broadcasting Network"; 70 | }else if(net.中国铁通.includes(net.carrier)){ 71 | net.运营商 = "China Tietong"; 72 | }else{ 73 | net.运营商 = "𝓜𝓸𝓫𝓲𝓵𝓮 𝓝𝓮𝓽𝔀𝓸𝓻𝓴"; 74 | } 75 | if(`${net.v4}` == `${net.query}`){ 76 | $done({ 77 | title: `${net.运营商}`, 78 | content: `Radio: `+net.radio+` ASN: `+net.asn+`\n`+net.youtube+`: Google `+net.emoji+`: `+net.query+`\nIPs: `+net.router+` & `+net.v4+`\nFraud score: `+net.score+` `+net.risk+` risk`+`\nTor: `+net.tor+` VPN: `+net.vpn+`\nRelay: `+net.relay+` Proxy: `+net.proxy+`\nServer: `+net.server+` Hosting: `+net.hosting+`\nASN Type: `+net.atype+`\nName: `+net.aname+`\nCompany Type: `+net.ctype+`\nName: `+net.cname, 79 | icon: "antenna.radiowaves.left.and.right", 80 | 'icon-color': "#EA0300" 81 | }); 82 | }else{ 83 | $done({ 84 | title: `${net.运营商}`, 85 | content: `Radio: `+net.radio+` ASN: `+net.asn+`\n`+net.youtube+`: Google `+net.emoji+`: `+net.query+`\nIPs: `+net.router+` & `+net.v4+`\nFraud score: `+net.score+` `+net.risk+` risk`+`\nTor: `+net.tor+` VPN: `+net.vpn+`\nRelay: `+net.relay+` Proxy: `+net.proxy+`\nServer: `+net.server+` Hosting: `+net.hosting+`\nASN Type: `+net.atype+`\nName: `+net.aname+`\nCompany Type: `+net.ctype+`\nName: `+net.cname, 86 | icon: "antenna.radiowaves.left.and.right", 87 | 'icon-color': "#EA0300" 88 | }); 89 | } 90 | }; 91 | })(); 92 | 93 | function ipapi() { 94 | return new Promise(function(resolve) { 95 | $httpClient.get("http://ip-api.com/json/", function(error, response, body){ 96 | var jsondata = JSON.parse(body) 97 | net.city = jsondata.city 98 | net.query = jsondata.query 99 | net.emoji = getFlagEmoji(jsondata.countryCode) 100 | //net.proxy = jsondata.proxy 101 | //net.hosting = jsondata.hosting 102 | resolve(); 103 | }) 104 | }) 105 | }; 106 | 107 | function scam() { 108 | return new Promise(function(resolve) { 109 | $httpClient.get({url: 'https://scamalytics.com/ip/' + net.query}, function(error,resp,html) { 110 | const regex = /"score":"(\d+)"/; 111 | const regex1 = /"risk":"(\w+)"/; 112 | const regex2 = /Server<\/th>\s*
(Yes|No)<\/div><\/td>/; 113 | const regex3 = /Tor Exit Node<\/th>\s*
(Yes|No)<\/div><\/td>/; 114 | const match = html.match(regex); 115 | const same = html.match(regex1); 116 | const server = html.match(regex2); 117 | const tor = html.match(regex3) 118 | net.score = match[1]; 119 | net.risk = same[1]; 120 | net.server = server[2]; 121 | net.tor = tor[2]; 122 | resolve(); 123 | }); 124 | }) 125 | }; 126 | 127 | function ipinfo() { 128 | return new Promise(function(resolve) { 129 | $httpClient.get({url: 'https://ipinfo.io/widget/demo/' + net.query}, function(error,resp,data) { 130 | let jsonData = JSON.parse(data) 131 | net.asn = jsonData.data.asn.asn 132 | net.atype = jsonData.data.asn.type 133 | net.aname = jsonData.data.asn.name 134 | net.ctype = jsonData.data.company.type 135 | net.cname = jsonData.data.company.name 136 | net.proxy = jsonData.data.privacy.proxy 137 | net.hosting = jsonData.data.privacy.hosting 138 | net.vpn = jsonData.data.privacy.vpn 139 | net.relay = jsonData.data.privacy.relay 140 | resolve(); 141 | }) 142 | }) 143 | }; 144 | 145 | function youtube() { 146 | return new Promise(function(resolve) { 147 | $httpClient.get({url: 'https://www.youtube.com/premium', headers: {'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36'}}, function(error,resp,body) { 148 | let reg = new RegExp ("contentRegion\\\":\\\"\\w{2}\\\"") 149 | let a = JSON.stringify(reg.exec(body)) 150 | let YouTube = a.replace(/(\[\"contentRegion\\\":\\\")(\w+)\\\"\"\]/, '$2') 151 | net.youtube = getFlagEmoji(YouTube) 152 | resolve(); 153 | }) 154 | }) 155 | }; 156 | 157 | /** 158 | function getFlagEmoji(countryCode) { 159 | const codePoints = countryCode 160 | .toUpperCase() 161 | .split('') 162 | .map(char => 127397 + char.charCodeAt()); 163 | return String.fromCodePoint(...codePoints); 164 | }; 165 | **/ 166 | 167 | function getFlagEmoji(country_code) { 168 | if(country_code === `TW`){ 169 | let codePoints = `CN` 170 | .toUpperCase() 171 | .split('') 172 | .map(char => 127397 + char.charCodeAt()); 173 | return String.fromCodePoint(...codePoints); 174 | }else{ 175 | const codePoints = country_code 176 | .toUpperCase() 177 | .split('') 178 | .map(char => 127397 + char.charCodeAt()); 179 | return String.fromCodePoint(...codePoints); 180 | } 181 | }; -------------------------------------------------------------------------------- /Surge/IP.js: -------------------------------------------------------------------------------- 1 | var 中国电信 = ['460-03','460-05','460-11']; 2 | var 中国联通 = ['460-01','460-06','460-09']; 3 | var 中国移动 = ['460-00','460-02','460-04','460-07','460-08']; 4 | var 中国广电 = ['460-15']; 5 | var 中国铁通 = ['460-20']; 6 | let v4 = $network.v4.primaryAddress 7 | var ssid = $network.wifi.ssid 8 | var carrier = $network["cellular-data"].carrier 9 | var router = $network.v4.primaryRouter 10 | var radio = $network["cellular-data"].radio 11 | $httpClient.get("http://ip-api.com/json/", function(error, response, body){ 12 | var jsondata = JSON.parse(body) 13 | var city = jsondata.city 14 | var query = jsondata.query 15 | var emoji = getFlagEmoji(jsondata.countryCode) 16 | var regex=/^192.168/ 17 | if(regex.test(v4)){ 18 | if(`${v4}` == `${query}`){ 19 | $done({ 20 | title: `${ssid}`, 21 | content: `${emoji}: ${query}\nRouter: ${router}\nLocal IP: ${v4}`, 22 | icon: "wifi", 23 | 'icon-color': "#00FF00" 24 | }); 25 | }else{ 26 | $done({ 27 | title: `${ssid}`, 28 | content: `${emoji}: ${query}\nRouter: ${router}\nLocal IP: ${v4}`, 29 | icon: "wifi", 30 | 'icon-color': "#00FF00" 31 | }); 32 | } 33 | }else if(`${radio}` == "null"){ 34 | if(`${v4}` == `${query}`){ 35 | $done({ 36 | title: `Hotspot`, 37 | content: `${emoji}: ${query}\nRouter: ${router}\nLocal IP: ${v4}`, 38 | icon: "personalhotspot", 39 | 'icon-color': "#0000FF" 40 | }); 41 | }else{ 42 | $done({ 43 | title: `Hotspot`, 44 | content: `${emoji}: ${query}\nRouter: ${router}\nLocal IP: ${v4}`, 45 | icon: "personalhotspot", 46 | 'icon-color': "#0000FF" 47 | }); 48 | } 49 | }else{ 50 | let 运营商 = ""; 51 | if(中国电信.includes(carrier)){ 52 | 运营商 = "China Telecom"; 53 | }else if(中国联通.includes(carrier)){ 54 | 运营商 = "China Unicom"; 55 | }else if(中国移动.includes(carrier)){ 56 | 运营商 = "China Mobile"; 57 | }else if(中国广电.includes(carrier)){ 58 | 运营商 = "China Broadcasting Network"; 59 | }else if(中国铁通.includes(carrier)){ 60 | 运营商 = "China Tietong"; 61 | }else{ 62 | 运营商 = "𝓜𝓸𝓫𝓲𝓵𝓮 𝓝𝓮𝓽𝔀𝓸𝓻𝓴"; 63 | } 64 | if(`${v4}` == `${query}`){ 65 | $done({ 66 | title: `${运营商}`, 67 | content: `Radio: ${radio}\n${emoji}: ${query}\nLocal IP: ${v4}`, 68 | icon: "antenna.radiowaves.left.and.right", 69 | 'icon-color': "#EA0300" 70 | }); 71 | }else{ 72 | $done({ 73 | title: `${运营商}`, 74 | content: `Radio: ${radio}\n${emoji}: ${query}\nLocal IP: ${v4}`, 75 | icon: "antenna.radiowaves.left.and.right", 76 | 'icon-color': "#EA0300" 77 | }); 78 | } 79 | } 80 | }); 81 | function getFlagEmoji(countryCode) { 82 | const codePoints = countryCode 83 | .toUpperCase() 84 | .split('') 85 | .map(char => 127397 + char.charCodeAt()); 86 | return String.fromCodePoint(...codePoints); 87 | }; 88 | function getFlagEmoji(country_code) { 89 | if(country_code === `TW`){ 90 | let codePoints = `CN` 91 | .toUpperCase() 92 | .split('') 93 | .map(char => 127397 + char.charCodeAt()); 94 | return String.fromCodePoint(...codePoints); 95 | }else{ 96 | const codePoints = country_code 97 | .toUpperCase() 98 | .split('') 99 | .map(char => 127397 + char.charCodeAt()); 100 | return String.fromCodePoint(...codePoints); 101 | } 102 | }; -------------------------------------------------------------------------------- /Surge/Nomo.js: -------------------------------------------------------------------------------- 1 | /**** 2 | Unlock Nomo CAM and Nomo RAW. 3 | 4 | Please note: 5 | Nomo RAW premium need restored in Nomo CAM APP. So....restore Nomo CAM first. 6 | 7 | Usage: Use Surge module or directly add them by yourself. 8 | 9 | [Script] 10 | Nomo = type=http-response,pattern=https://nomo.dafork.com/api/v5/iap/ios_verify$,requires-body=1,max-size=0,script-path=https://github.com/DecoAri/JavaScript/blob/main/Surge/Nomo.js?raw=true 11 | 12 | [MITM] 13 | hostname = %APPEND% nomo.dafork.com 14 | 15 | ****/ 16 | 17 | let obj = $response.body 18 | 19 | obj = '{"sign":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0aW1lc3RhbXAiOjE2OTY1Mzk1NTMsInJlcXVlc3Rfc2lnbiI6IjIxMDIwMjRjYTcxNWY0NjI5NDJlYzIzMmIwMDIyMmI0IiwidmFsaWRhdGVkX2lvc19pZHMiOlsiYmxpbmsuYWNhZGVteS5ub21vLnByby55ZWFyIl0sImhhc192YWxpZF9zdWJzY3JpcHRpb24iOnRydWUsInN1YnNjcmlwdGlvbl9leHBpcmVfYXQiOjQxMDA2ODgwMDB9.XLQk0ScKVpxIinNgtujwJtS75ckzkrlGdzcK76paTq65F2Bl5UH5ImTyTNvpj6YJiz_SoS87LkLMPAQOCEhESGCsqjYC4HUaKGBrPp1JW9bwa_P4UCKYddbyRv7Yr5-yuFYan6nxozRUTnze-6yd1dc8sJJnfaDyGTnnzieHodtHp0SFPD9zCkb4flrbaxciDIZVAWDt3MakkMe1azoGHjH2cYz1YU3aOZDaKChqZi4y-pevYIMTDFth1LQsJpzqfV0OcS25ObVs-8h8lKxSLRK338WIrB2cQbRM8MXTSx4Tm_dBXbbROoofIuPfU9WnLqF5xUCrLNpx_TuFwbUgaQ"}' 20 | 21 | $done({obj}); -------------------------------------------------------------------------------- /Surge/PDDNS.js: -------------------------------------------------------------------------------- 1 | /**** 2 | 写脚本缘由:私有DDNS脚本,由于Surge自带的sgddns无法同时解析ipv4和ipv6同时使用。由于经常换网络环境,不一定全是公网IP,可能只有公网V6,可能全部都有。所以自写一份私有ddns脚本。 3 | 4 | ⚠️需要配合python/JS自动上传本机公网IP到github后此脚本才可用 5 | 6 | ⚠️请详细(一个个字)阅读 7 | 8 | 使用方法:在Surge中文本编辑配置文件。 9 | 10 | Surge iOS添加内容如下: 11 | [Script]这个section下粘贴以下内容: 12 | DDNS = type=dns,script-path=https://raw.githubusercontent.com/DecoAri/JavaScript/main/Surge/PDDNS.js,argument=URL=🌍&TOKEN=🔑 13 | [Host]下添加以下内容: 14 | // 随便写一个不常见域名例如 15 | home.mac.pddns = script:DDNS 16 | 把你的家里的节点的server改为上面的域名: home.mac.pddns 17 | 18 | 请替换argument里面的🌍和🔑 19 | 🌍为你github私有库的dns IP文件的链接(该文件的IP由py/js自动上传,请不要自己填写文件内容) 20 | 🔑为github的personal access token。如不知道该开什么权限请全部勾选(⚠️别把token分享给别人) 21 | 22 | 自动上传IP到github请访问本库的up_pddns.js或者python库 23 | ****/ 24 | 25 | let ddnsurl = { 26 | url: getArgs().URL, 27 | headers: { 28 | 'Authorization': 'token ' + getArgs().TOKEN 29 | } 30 | } 31 | 32 | $httpClient.get(ddnsurl, function(error, response, data){ 33 | $done({addresses: data.split(';'), ttl: 600}); 34 | }); 35 | 36 | function getArgs() { 37 | return Object.fromEntries( 38 | $argument 39 | .split("&") 40 | .map((item) => item.split("=")) 41 | .map(([k, v]) => [k, decodeURIComponent(v)]) 42 | ); 43 | } -------------------------------------------------------------------------------- /Surge/Piao_Bak.js: -------------------------------------------------------------------------------- 1 | let productBakNo = JSON.parse($response.body).respData.bakNo 2 | $persistentStore.write(productBakNo, 'productBakNo') 3 | console.log('若productBakNo后有字符串则获取成功\nproductBakNo:' + $persistentStore.read('productBakNo')) 4 | $done({}) -------------------------------------------------------------------------------- /Surge/Piao_No.js: -------------------------------------------------------------------------------- 1 | let cityNo = getArgs().cityNo 2 | let longitude = getArgs().longitude 3 | let dimension = getArgs().dimension 4 | let productNo = getArgs().productNo 5 | $persistentStore.write(cityNo, 'cityNo') 6 | $persistentStore.write(longitude, 'longitude') 7 | $persistentStore.write(dimension, 'dimension') 8 | $persistentStore.write(productNo, 'productNo') 9 | console.log('\n' + $persistentStore.read('cityNo') + '\n' + $persistentStore.read('longitude') + '\n' + $persistentStore.read('dimension') + '\n' + $persistentStore.read('productNo') + '\n若为四个数字串则正确') 10 | $done({}) 11 | 12 | function getArgs() { 13 | return Object.fromEntries( 14 | $request.body 15 | .split(”&“) 16 | .map((item) => item.split(”=“)) 17 | .map(([k, v]) => [k, decodeURIComponent(v)]) 18 | ); 19 | } -------------------------------------------------------------------------------- /Surge/TF_keys.js: -------------------------------------------------------------------------------- 1 | $persistentStore.write(null, 'request_id') 2 | let url = $request.url 3 | let key = url.replace(/(.*accounts\/)(.*)(\/apps)/, '$2') 4 | let session_id = $request.headers['x-session-id'] || $request.headers['X-Session-Id'] 5 | let session_digest = $request.headers['x-session-digest'] || $request.headers['X-Session-Digest'] 6 | let request_id = $request.headers['x-request-id'] || $request.headers['X-Request-Id'] 7 | let X_Apple_AMD_M = $request.headers['X-Apple-AMD-M'] || $request.headers['x-apple-amd-m'] 8 | let UA = $request.headers['User-Agent'] || $request.headers['user-agent'] 9 | $persistentStore.write(key, 'key') 10 | $persistentStore.write(session_id, 'session_id') 11 | $persistentStore.write(session_digest, 'session_digest') 12 | $persistentStore.write(request_id, 'request_id') 13 | $persistentStore.write(X_Apple_AMD_M, 'X-Apple-AMD-M') 14 | $persistentStore.write(UA, 'TFUA') 15 | if ($persistentStore.read('request_id') !== null) { 16 | $notification.post('请关闭本脚本', '信息获取成功','') 17 | } else { 18 | $notification.post('信息获取失败','请打开MITM H2开关并添加testflight.apple.com','') 19 | } 20 | $done({}) -------------------------------------------------------------------------------- /Surge/TF_link.js: -------------------------------------------------------------------------------- 1 | /** 2 | 作用:显示公共TF的分享链接(非公测链接无法显示),若没有链接或者没有描述说明啥也没有(无法分享链接 3 | 路径:App--App Details--Description 4 | 使用方法: 5 | Surge: 6 | [Script] 7 | TF_link = type=http-response,pattern=^https:\/\/testflight\.apple\.com\/v2\/accounts\/\w+-\w+-\w+-\w+-\w+\/apps\/\d+\/builds\/\d+$,requires-body=1,max-size=0,script-path=https://github.com/DecoAri/JavaScript/blob/main/Surge/TF_link.js?raw=true 8 | [MITM] 9 | hostname = testflight.apple.com 10 | 11 | QX: 12 | ^https:\/\/testflight\.apple\.com\/v2\/accounts\/\w+-\w+-\w+-\w+-\w+\/apps\/\d+\/builds\/\d+$ url script-response-body https://github.com/DecoAri/JavaScript/blob/main/Surge/TF_link.js?raw=true 13 | hostname = testflight.apple.com 14 | 15 | **/ 16 | 17 | 18 | let obj = JSON.parse($response.body);obj.data.builds[0].description = obj.data.shareUrl + '\n' + obj.data.builds[0].description;$done({body:JSON.stringify(obj)}); -------------------------------------------------------------------------------- /Surge/XiYou-Sign.js: -------------------------------------------------------------------------------- 1 | let xy = {}; 2 | xy.city = "重庆市"; 3 | xy.district = "区"; 4 | xy.lat = 100.75648332114813; 5 | xy.lng = 107.2709211714478; 6 | xy.province = "重庆"; 7 | xy.street = "大道"; 8 | (async function() { 9 | await token(); 10 | await task(); 11 | await status(); 12 | if(xy.data == 0) { 13 | $notification.post("签到未开始", xy.id, ""); 14 | $httpClient.post({ 15 | url: 'https://sctapi.ftqq.com/SCT87132TpuhLxVx2dJZnsvyVfs0fYejf.send', 16 | headers: { 17 | 'Content-Type' : 'application/x-www-form-urlencoded; charset=utf-8' 18 | }, 19 | body: 'title=签到未开始&desp=' + xy.id 20 | }) 21 | } else if(xy.data == 1) { 22 | await submit(); 23 | $notification.post("习柚", xy.msgs, ""); 24 | $httpClient.post({ 25 | url: 'https://sctapi.ftqq.com/SCT87132TpuhLxVx2dJZnsvyVfs0fYejf.send', 26 | headers: { 27 | 'Content-Type' : 'application/x-www-form-urlencoded; charset=utf-8' 28 | }, 29 | body: 'title=习柚' + xy.msgs + '&desp=' + xy.msgs 30 | }) 31 | } else if(xy.data == "-1") { 32 | $notification.post("习柚", xy.msg, ""); 33 | $httpClient.post({ 34 | url: 'https://sctapi.ftqq.com/SCT87132TpuhLxVx2dJZnsvyVfs0fYejf.send', 35 | headers: { 36 | 'Content-Type' : 'application/x-www-form-urlencoded; charset=utf-8' 37 | }, 38 | body: 'title=习柚&desp=' + xy.msg 39 | }) 40 | } else { 41 | $notification.post("错误", "网络或其他错误,需重新运行", ""); 42 | $httpClient.post({ 43 | url: 'https://sctapi.ftqq.com/SCT87132TpuhLxVx2dJZnsvyVfs0fYejf.send', 44 | headers: { 45 | 'Content-Type' : 'application/x-www-form-urlencoded; charset=utf-8' 46 | }, 47 | body: 'title=错误&desp=网络或其他错误,需重新运行' 48 | }) 49 | } 50 | $done() 51 | })(); 52 | 53 | function token() { 54 | const loginurl = { 55 | url: 'https://www.yunzhixiyou.com/api/sys/manage/login', 56 | headers: { 57 | 'User-Agent' : 'xiyou/4.2.2 2280 ios14.3 (iPhone 6s Plus)', 58 | 'Content-Type' : 'application/x-www-form-urlencoded; charset=utf-8' 59 | }, 60 | body: 'password=00000&schoolId=000&username=0000000' 61 | }; 62 | return new Promise(function(resolve) { 63 | $httpClient.post(loginurl, function(error, resp, data) { 64 | xy.token =JSON.parse(data).token; 65 | resolve(); 66 | }); 67 | }); 68 | } 69 | 70 | function task() { 71 | const taskurl = { 72 | url: 'https://www.yunzhixiyou.com/api/task/getTopTask', 73 | headers: { 74 | 'User-Agent' : 'xiyou/4.2.2 2280 ios14.3 (iPhone 6s Plus)', 75 | 'token' : xy.token 76 | }, 77 | }; 78 | return new Promise(function(resolve) { 79 | $httpClient.get(taskurl, function(error, resp, data) { 80 | xy.id = JSON.parse(data).data[0].id; 81 | resolve(); 82 | }); 83 | }); 84 | } 85 | 86 | function status() { 87 | const statusurl = { 88 | url: 'https://www.yunzhixiyou.com/api/sign/isSignOrNoSignInt', 89 | headers: { 90 | 'User-Agent' : 'xiyou/4.2.2 2280 ios14.3 (iPhone 6s Plus)', 91 | 'Content-Type' : 'application/x-www-form-urlencoded; charset=utf-8', 92 | 'token' : xy.token 93 | }, 94 | body: 'taskId=' + xy.id 95 | }; 96 | return new Promise(function(resolve) { 97 | $httpClient.post(statusurl, function(error, resp, body) { 98 | xy.data =JSON.parse(body).result; 99 | console.log(body); 100 | xy.msg = JSON.parse(body).msg; 101 | resolve(); 102 | }); 103 | }); 104 | } 105 | 106 | function submit() { 107 | const submiturl = { 108 | url: 'https://www.yunzhixiyou.com/api/sign/signIn', 109 | headers: { 110 | 'User-Agent' : 'xiyou/4.2.2 2280 ios14.3 (iPhone 6s Plus)', 111 | 'Content-Type' : 'application/x-www-form-urlencoded; charset=utf-8', 112 | 'token' : xy.token 113 | }, 114 | body: "city=" + xy.city + "&district=" + xy.district + "&lat=" + xy.lat + "&lng=" + xy.lng + "&phoneUuid=uuid&province=" + xy.province + "&signStatus=1&street=" + xy.street + "&taskId=" + xy.id + "&type=1" 115 | }; 116 | return new Promise(function(resolve) { 117 | $httpClient.post(submiturl, function(error, resp, body) { 118 | xy.msgs = JSON.parse(body).msg; 119 | resolve(); 120 | }); 121 | }); 122 | } -------------------------------------------------------------------------------- /Surge/XiYou-summary.js: -------------------------------------------------------------------------------- 1 | let xy = {}; 2 | xy.body = "all", 3 | (async function() { 4 | await token(); 5 | await task(); 6 | await submit() 7 | $done() 8 | })(); 9 | 10 | function token() { 11 | const loginurl = { 12 | url: 'https://www.yunzhixiyou.com/api/sys/manage/login', 13 | headers: { 14 | 'User-Agent' : 'xiyou/4.2.2 2280 ios14.3 (iPhone 6s Plus)', 15 | 'Content-Type' : 'application/x-www-form-urlencoded; charset=utf-8' 16 | }, 17 | body: 'password=000000&schoolId=00000&username=00000' 18 | }; 19 | return new Promise(function(resolve) { 20 | $httpClient.post(loginurl, function(error, resp, data) { 21 | xy.token =JSON.parse(data).token; 22 | resolve(); 23 | }); 24 | }); 25 | } 26 | 27 | function task() { 28 | const taskurl = { 29 | url: 'https://www.yunzhixiyou.com/api/task/getTopTask', 30 | headers: { 31 | 'User-Agent' : 'xiyou/4.2.2 2280 ios14.3 (iPhone 6s Plus)', 32 | 'token' : xy.token 33 | }, 34 | }; 35 | return new Promise(function(resolve) { 36 | $httpClient.get(taskurl, function(error, resp, data) { 37 | xy.id = JSON.parse(data).data[0].id; 38 | resolve(); 39 | }); 40 | }); 41 | } 42 | 43 | function submit() { 44 | let content = `
  ` + xy.body 45 | xy.content = encodeURIComponent(content) 46 | xy.sign = encodeURI("
") 47 | const submiturl = { 48 | url: 'https://www.yunzhixiyou.com/api/summary/publish', 49 | headers: { 50 | 'User-Agent' : 'xiyou/4.2.2 2280 ios14.3 (iPhone 6s Plus)', 51 | 'Content-Type' : 'application/x-www-form-urlencoded; charset=utf-8', 52 | 'token' : xy.token 53 | }, 54 | body: "content=" + xy.content + xy.sign + "&taskId=" + xy.id 55 | }; 56 | return new Promise(function(resolve) { 57 | $httpClient.post(submiturl, function(error, resp, body) { 58 | xy.msg = JSON.parse(body).msg; 59 | console.log(body) 60 | $notification.post("习柚总结", xy.msg, "") 61 | resolve(); 62 | }); 63 | }); 64 | } -------------------------------------------------------------------------------- /Surge/campusphere-night.js: -------------------------------------------------------------------------------- 1 | let cp = {}; 2 | cp.long = $persistentStore.read("经度"); 3 | cp.la = $persistentStore.read("纬度"); 4 | cp.location = $persistentStore.read("地区"); 5 | (async function() { 6 | await login(); 7 | await wid(); 8 | await form() 9 | await submit() 10 | $done() 11 | })(); 12 | function login() { 13 | const loginurl = { 14 | url: 'http://' + $persistentStore.read("ip") + ':8080/wisedu-unified-login-api-v1.0/api/login?login_url=http%3A%2F%2Fauthserver.' + $persistentStore.read("学校") + '.cn%2Fauthserver%2Flogin%3Fservice%3Dhttps%253A%252F%252F' + $persistentStore.read("学校") + '.campusphere.net%252Fiap%252FloginSuccess&password=' + $persistentStore.read("密码") + '&username=' + $persistentStore.read("账号"), 15 | }; 16 | return new Promise(function(resolve) { 17 | $httpClient.post(loginurl, function(error, resp, data) { 18 | console.log(resp.status) 19 | if (resp.status != 200) { 20 | login() 21 | } else { 22 | let jsonData = JSON.parse(data); 23 | console.log(jsonData.msg) 24 | if (jsonData.msg != "login success!") { 25 | login() 26 | } else { 27 | let cookies = jsonData.cookies 28 | let regex = /route.*MOD_AUTH_CAS/ 29 | cp.cookie = cookies.replace(regex, "MOD_AUTH_CAS") 30 | console.log('\n' + cp.cookie) 31 | resolve(); //异步操作成功时调用, 将Promise对象的状态标记为"成功", 表示已完成 32 | } 33 | } 34 | }); 35 | }); 36 | } 37 | 38 | function wid() { 39 | const widurl = { 40 | url: 'https://' + $persistentStore.read("学校") + '.campusphere.net/wec-counselor-sign-apps/stu/sign/getStuSignInfosInOneDay', 41 | headers: { 42 | 'Cookie' : cp.cookie, 43 | 'Content-Type' : `application/json;charset=utf-8` 44 | }, 45 | body: '{}' 46 | }; 47 | return new Promise(function(resolve) { 48 | $httpClient.post(widurl, function(error, resp, data) { 49 | let jsonData = JSON.parse(data); 50 | console.log('\n' + data) 51 | cp.leave = jsonData["datas"].leaveTasks[0] 52 | if (cp.leave == undefined) { 53 | cp.wid = jsonData["datas"].unSignedTasks[0].signInstanceWid 54 | cp.signWid = jsonData["datas"].unSignedTasks[0].signWid 55 | } else { 56 | cp.wid = jsonData["datas"].leaveTasks[0].signInstanceWid 57 | cp.signWid = jsonData["datas"].leaveTasks[0].signWid 58 | } 59 | resolve(); //异步操作成功时调用, 将Promise对象的状态标记为"成功", 表示已完成 60 | }); 61 | }); 62 | } 63 | 64 | function form() { 65 | const formurl = { 66 | url: 'https://' + $persistentStore.read("学校") + '.campusphere.net/wec-counselor-sign-apps/stu/sign/detailSignInstance', 67 | headers: { 68 | 'Cookie' : cp.cookie, 69 | 'Content-Type' : 'application/json;charset=utf-8' 70 | }, 71 | body: `{ 72 | "signWid": ${cp.signWid}, 73 | "signInstanceWid": ${cp.wid} 74 | }`, 75 | }; 76 | return new Promise(function(resolve) { 77 | $httpClient.post(formurl, function(error, resp, data) { 78 | let jsonData = JSON.parse(data); 79 | cp.formWid = jsonData.datas.extraField[0].extraFieldItems[0].wid 80 | cp.formcontent = jsonData.datas.extraField[0].extraFieldItems[0].content 81 | resolve(); 82 | }) 83 | }) 84 | } 85 | function submit() { 86 | const bodys = { 87 | "position": `${cp.location}`, 88 | "isMalposition": 1, 89 | "extraFieldItems": [ 90 | { 91 | "extraFieldItemWid": `${cp.formWid}`, 92 | "extraFieldItemValue": `${cp.formcontent}` 93 | } 94 | ], 95 | "longitude": `${cp.long}`, 96 | "latitude": `${cp.la}`, 97 | "abnormalReason": "", 98 | "signInstanceWid": `${cp.wid}`, 99 | "isNeedExtra": 1, 100 | "signPhotoUrl": `${$persistentStore.read("照片")}`, 101 | "uaIsCpadaily": false 102 | } 103 | const submiturl = { 104 | url: 'https://' + $persistentStore.read("学校") + '.campusphere.net/wec-counselor-sign-apps/stu/sign/submitSign', 105 | headers: { 106 | 'Cookie' : cp.cookie, 107 | 'Content-Type' : 'application/json;charset=utf-8' 108 | }, 109 | body: JSON.stringify(bodys) 110 | }; 111 | return new Promise(function(resolve) { 112 | $httpClient.post(submiturl, function(error, resp, data) { 113 | let jsonData = JSON.parse(data); 114 | cp.msg = jsonData.message 115 | console.log(cp.msg) 116 | $httpClient.post({ 117 | url: 'https://sctapi.ftqq.com/' + $persistentStore.read("server酱") + '.send', 118 | header: { 119 | 'Content-Type' : 'application/x-www-form-urlencoded; charset=utf-8' 120 | }, 121 | body: 'title=今日校园' + cp.msg + '&desp=今日校园' 122 | }, function(error,resp,data) { 123 | let jsonData = JSON.parse(data) 124 | console.log('\n' + jsonData.message) 125 | $notification.post("今日校园", cp.msg, jsonData.message) 126 | resolve(); //异步操作成功时调用, 将Promise对象的状态标记为"成功", 表示已完成 127 | }) 128 | }); 129 | }); 130 | } 131 | -------------------------------------------------------------------------------- /Surge/campusphere.js: -------------------------------------------------------------------------------- 1 | let cp = {}; 2 | cp.long = $persistentStore.read("经度"); 3 | cp.la = $persistentStore.read("纬度"); 4 | cp.location = $persistentStore.read("地区"); 5 | (async function() { 6 | if ($persistentStore.read("sign") == "SUCCESS") { 7 | $done(console.log("已签到")) 8 | } else { 9 | await login(); 10 | await wid(); 11 | await form(); 12 | await submit(); 13 | $done(); 14 | } 15 | })(); 16 | function login() { 17 | console.log("await login") 18 | const loginurl = { 19 | url: 'http://' + $persistentStore.read("ip") + ':8080/wisedu-unified-login-api-v1.0/api/login?login_url=http%3A%2F%2Fauthserver.' + $persistentStore.read("学校") + '.cn%2Fauthserver%2Flogin%3Fservice%3Dhttps%253A%252F%252F' + $persistentStore.read("学校") + '.campusphere.net%252Fiap%252FloginSuccess&password=' + $persistentStore.read("密码") + '&username=' + $persistentStore.read("账号"), 20 | timeout: 30 21 | }; 22 | return new Promise(function(resolve) { 23 | $httpClient.post(loginurl, function(error, resp, data) { 24 | if (typeof(resp) == "undefined") { 25 | console.log(resp) 26 | login() 27 | }else if (resp.status != 200) { 28 | console.log(resp.status) 29 | login() 30 | } else { 31 | let jsonData = JSON.parse(data); 32 | console.log(jsonData.msg) 33 | if (jsonData.msg != "login success!") { 34 | login() 35 | } else { 36 | let cookies = jsonData.cookies 37 | let regex = /route.*MOD_AUTH_CAS/ 38 | cp.cookie = cookies.replace(regex, "MOD_AUTH_CAS") 39 | console.log('\n' + cp.cookie) 40 | resolve(); //异步操作成功时调用, 将Promise对象的状态标记为"成功", 表示已完成 41 | } 42 | } 43 | }); 44 | }); 45 | } 46 | 47 | function wid() { 48 | console.log("await wid") 49 | const widurl = { 50 | url: 'https://' + $persistentStore.read("学校") + '.campusphere.net/wec-counselor-sign-apps/stu/sign/getStuSignInfosInOneDay', 51 | headers: { 52 | 'Cookie' : cp.cookie, 53 | 'Content-Type' : `application/json;charset=utf-8` 54 | }, 55 | body: '{}' 56 | }; 57 | return new Promise(function(resolve) { 58 | $httpClient.post(widurl, function(error, resp, data) { 59 | let jsonData = JSON.parse(data); 60 | console.log('\n' + data) 61 | cp.leave = jsonData["datas"].leaveTasks[0] 62 | cp.unsign = jsonData["datas"].unSignedTasks[0] 63 | if (typeof(cp.unsign) == "undefined" && typeof(cp.leave) == "undefined") { 64 | console.log("无签到") 65 | $persistentStore.write('SUCCESS', 'sign') 66 | $done($notification.post("无签到","","")) 67 | } else if (typeof(cp.unsign) == "undefined") { 68 | cp.wid = jsonData["datas"].leaveTasks[0].signInstanceWid 69 | cp.signWid = jsonData["datas"].leaveTasks[0].signWid 70 | resolve(); 71 | } else { 72 | cp.wid = jsonData["datas"].unSignedTasks[0].signInstanceWid 73 | cp.signWid = jsonData["datas"].unSignedTasks[0].signWid 74 | resolve(); 75 | } 76 | }); 77 | }); 78 | } 79 | 80 | function form() { 81 | console.log("await form") 82 | const formurl = { 83 | url: 'https://' + $persistentStore.read("学校") + '.campusphere.net/wec-counselor-sign-apps/stu/sign/detailSignInstance', 84 | headers: { 85 | 'Cookie' : cp.cookie, 86 | 'Content-Type' : 'application/json;charset=utf-8' 87 | }, 88 | body: `{ 89 | "signWid": ${cp.signWid}, 90 | "signInstanceWid": ${cp.wid} 91 | }`, 92 | }; 93 | return new Promise(function(resolve) { 94 | $httpClient.post(formurl, function(error, resp, data) { 95 | let jsonData = JSON.parse(data); 96 | cp.formWid = jsonData.datas.extraField[0].extraFieldItems[0].wid 97 | cp.formWid1 = jsonData.datas.extraField[1].extraFieldItems[0].wid 98 | cp.formWid2 = jsonData.datas.extraField[2].extraFieldItems[0].wid 99 | cp.formWid3 = jsonData.datas.extraField[3].extraFieldItems[0].wid 100 | cp.formWid4 = jsonData.datas.extraField[4].extraFieldItems[0].wid 101 | cp.formcontent = jsonData.datas.extraField[0].extraFieldItems[0].content 102 | cp.formcontent1 = jsonData.datas.extraField[1].extraFieldItems[0].content 103 | cp.formcontent2 = jsonData.datas.extraField[2].extraFieldItems[0].content 104 | cp.formcontent3 = jsonData.datas.extraField[3].extraFieldItems[0].content 105 | cp.formcontent4 = jsonData.datas.extraField[4].extraFieldItems[0].content 106 | resolve(); 107 | }) 108 | }) 109 | } 110 | function submit() { 111 | console.log("await submit") 112 | const bodys = { 113 | "abnormalReason": "", 114 | "position": `${cp.location}`, 115 | "longitude": `${cp.long}`, 116 | "isNeedExtra": 1, 117 | "latitude": `${cp.la}`, 118 | "isMalposition": 1, 119 | "extraFieldItems": [ 120 | { 121 | "extraFieldItemWid": `${cp.formWid}`, 122 | "extraFieldItemValue": `${cp.formcontent}` 123 | }, 124 | { 125 | "extraFieldItemWid": `${cp.formWid1}`, 126 | "extraFieldItemValue": `${cp.formcontent1}` 127 | }, 128 | { 129 | "extraFieldItemWid": `${cp.formWid2}`, 130 | "extraFieldItemValue": `${cp.formcontent2}` 131 | }, 132 | { 133 | "extraFieldItemWid": `${cp.formWid3}`, 134 | "extraFieldItemValue": `${cp.formcontent3}` 135 | }, 136 | { 137 | "extraFieldItemWid": `${cp.formWid4}`, 138 | "extraFieldItemValue": `${cp.formcontent4}` 139 | } 140 | ], 141 | "signPhotoUrl": "", 142 | "uaIsCpadaily": false, 143 | "signInstanceWid": `${cp.wid}` 144 | } 145 | const submiturl = { 146 | url: 'https://' + $persistentStore.read("学校") + '.campusphere.net/wec-counselor-sign-apps/stu/sign/submitSign', 147 | headers: { 148 | 'Cookie' : cp.cookie, 149 | 'Content-Type' : 'application/json;charset=utf-8' 150 | }, 151 | body: JSON.stringify(bodys) 152 | }; 153 | return new Promise(function(resolve) { 154 | $httpClient.post(submiturl, function(error, resp, data) { 155 | let jsonData = JSON.parse(data); 156 | cp.msg = jsonData.message 157 | console.log(cp.msg) 158 | $notification.post("今日校园", cp.msg, "") 159 | if (cp.msg == "SUCCESS") { 160 | $persistentStore.write(cp.msg, 'sign') 161 | resolve() 162 | } else { 163 | resolve(); 164 | } 165 | }); 166 | }); 167 | } -------------------------------------------------------------------------------- /Surge/up_pddns.js: -------------------------------------------------------------------------------- 1 | /***** 2 | 使用方法: 3 | 1: Github创建私有库后直接创建DDNS.json文件。再创建classic personal access token并给予所有权限 4 | 5 | 2: Surge Mac文本编辑配置文件添加内容如下: 6 | 7 | 3: [Rule]规则: 8 | DOMAIN,api64.ipify.org,V6 9 | DOMAIN,ipapi.co,V6 10 | DOMAIN,api.ipify.org,V4 11 | 12 | 4: [Proxy]节点: 13 | V6 = direct, test-url=http://connectivitycheck.platform.hicloud.com/generate_204, ip-version=v6-only 14 | V4 = direct, test-url=http://connectivitycheck.platform.hicloud.com/generate_204, ip-version=v4-only 15 | 16 | 5: [Script]脚本: 17 | up_pddns = type=event,event-name=network-changed,script-path=https://raw.githubusercontent.com/DecoAri/JavaScript/main/Surge/up_pddns.js,argument=owner=👨&token=🔑&repo=🏠&branch=🛣️&filePath=📄&fileName=📖 18 | 19 | 6: 请替换步骤5里面argument里面的👨、🔑、🏠、🛣️、📄和📖。 20 | 👨为你github的用户名 21 | 🔑为github的personal access token。如不知道该开什么权限请全部勾选(⚠️别把token分享给别人) 22 | 🏠为你的第一步创建的库名称 23 | 🛣️为你的branch(一般为main或者master) 24 | 📄为你的最终文件的路径,如:path/to/your-DDNS.json 25 | 📖为你的文件名称:如DDNS.json 26 | 27 | 举个完整例子: 28 | https://raw.githubusercontent.com/woaini/PDDNS/main/DDNS.json 29 | 或 30 | https://raw.githubusercontent.com/woaini/PDDNS/main/Surge/DDNS.json 此条带filePath 31 | 32 | 以上例子owner为woaini、repo为PDDNS、branch为main、filePath为Surge/DDNS.json、fileName为DDNS.json 33 | ****/ 34 | 35 | 36 | 37 | function getArgs() { 38 | return Object.fromEntries( 39 | $argument 40 | .split("&") 41 | .map((item) => item.split("=")) 42 | .map(([k, v]) => [k, decodeURIComponent(v)]) 43 | ); 44 | } 45 | 46 | var base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', 47 | base64DecodeChars = new Array((-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), 62, (-1), (-1), (-1), 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, (-1), (-1), (-1), (-1), (-1), (-1), (-1), 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, (-1), (-1), (-1), (-1), (-1), (-1), 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, (-1), (-1), (-1), (-1), (-1)); 48 | var base64encode = function (e) { 49 | var r, a, c, h, o, t; 50 | for (c = e.length, a = 0, r = ''; a < c;) { 51 | if (h = 255 & e.charCodeAt(a++), a == c) { 52 | r += base64EncodeChars.charAt(h >> 2), 53 | r += base64EncodeChars.charAt((3 & h) << 4), 54 | r += '=='; 55 | break 56 | } 57 | if (o = e.charCodeAt(a++), a == c) { 58 | r += base64EncodeChars.charAt(h >> 2), 59 | r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4), 60 | r += base64EncodeChars.charAt((15 & o) << 2), 61 | r += '='; 62 | break 63 | } 64 | t = e.charCodeAt(a++), 65 | r += base64EncodeChars.charAt(h >> 2), 66 | r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4), 67 | r += base64EncodeChars.charAt((15 & o) << 2 | (192 & t) >> 6), 68 | r += base64EncodeChars.charAt(63 & t) 69 | } 70 | return r 71 | } 72 | var base64decode = function (e) { 73 | var r, a, c, h, o, t, d; 74 | for (t = e.length, o = 0, d = ''; o < t;) { 75 | do r = base64DecodeChars[255 & e.charCodeAt(o++)]; 76 | while (o < t && r == -1); 77 | if (r == -1) break; 78 | do a = base64DecodeChars[255 & e.charCodeAt(o++)]; 79 | while (o < t && a == -1); 80 | if (a == -1) break; 81 | d += String.fromCharCode(r << 2 | (48 & a) >> 4); 82 | do { 83 | if (c = 255 & e.charCodeAt(o++), 61 == c) return d; 84 | c = base64DecodeChars[c] 85 | } while (o < t && c == -1); 86 | if (c == -1) break; 87 | d += String.fromCharCode((15 & a) << 4 | (60 & c) >> 2); 88 | do { 89 | if (h = 255 & e.charCodeAt(o++), 61 == h) return d; 90 | h = base64DecodeChars[h] 91 | } while (o < t && h == -1); 92 | if (h == -1) break; 93 | d += String.fromCharCode((3 & c) << 6 | h) 94 | } 95 | return d 96 | } 97 | var hexToBytes = function (hex) { 98 | for (var bytes = [], c = 0; c < hex.length; c += 2) 99 | bytes.push(parseInt(hex.substr(c, 2), 16)); 100 | return bytes; 101 | } 102 | var bytesToHex = function (bytes) { 103 | for (var hex = [], i = 0; i < bytes.length; i++) { 104 | hex.push((bytes[i] >>> 4).toString(16)); 105 | hex.push((bytes[i] & 0xF).toString(16)); 106 | } 107 | return hex.join(""); 108 | } 109 | var bytesToString = function (arr) { 110 | var str = ""; 111 | arr = new Uint8Array(arr); 112 | for (i in arr) { 113 | str += String.fromCharCode(arr[i]); 114 | } 115 | return str; 116 | } 117 | var stringToBytes = function (str) { 118 | var ch, st, re = []; 119 | for (var i = 0; i < str.length; i++) { 120 | ch = str.charCodeAt(i); 121 | st = []; 122 | do { 123 | st.push(ch & 0xFF); 124 | ch = ch >> 8; 125 | } 126 | while (ch); 127 | re = re.concat(st.reverse()) 128 | } 129 | return re; 130 | } 131 | var bytesToBase64 = function (bytes) { 132 | 133 | // Use browser-native function if it exists 134 | // if (typeof btoa == "function") return btoa(bytesToString(bytes)); 135 | 136 | for (var base64 = [], i = 0; i < bytes.length; i += 3) { 137 | var triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]; 138 | for (var j = 0; j < 4; j++) { 139 | if (i * 8 + j * 6 <= bytes.length * 8) 140 | base64.push(base64EncodeChars.charAt((triplet >>> 6 * (3 - j)) & 0x3F)); 141 | else base64.push("="); 142 | } 143 | } 144 | return base64.join(""); 145 | } 146 | var base64ToBytes = function (base64) { 147 | 148 | // Use browser-native function if it exists 149 | // if (typeof atob == "function") return stringToBytes(atob(base64)); 150 | 151 | // Remove non-base-64 characters 152 | base64 = base64.replace(/[^A-Z0-9+\/]/ig, ""); 153 | 154 | for (var bytes = [], i = 0, imod4 = 0; i < base64.length; imod4 = ++i % 4) { 155 | if (imod4 == 0) continue; 156 | bytes.push(((base64EncodeChars.indexOf(base64.charAt(i - 1)) & (Math.pow(2, -2 * imod4 + 8) - 1)) << (imod4 * 2)) | 157 | (base64EncodeChars.indexOf(base64.charAt(i)) >>> (6 - imod4 * 2))); 158 | } 159 | 160 | return bytes; 161 | 162 | } 163 | var hexToString = function (hex) { 164 | var arr = hex.split("") 165 | var out = "" 166 | for (var i = 0; i < arr.length / 2; i++) { 167 | var tmp = "0x" + arr[i * 2] + arr[i * 2 + 1] 168 | var charValue = String.fromCharCode(tmp); 169 | out += charValue 170 | } 171 | return out 172 | } 173 | var stringToHex = function (str) { 174 | var val = ""; 175 | for (var i = 0; i < str.length; i++) { 176 | if (val == "") 177 | val = str.charCodeAt(i).toString(16); 178 | else 179 | val += str.charCodeAt(i).toString(16); 180 | } 181 | val += "0a" 182 | return val 183 | } 184 | var hexToBase64 = function (str) { 185 | return base64encode(String.fromCharCode.apply(null, str.replace(/\r|\n/g, "").replace(/([\da-fA-F]{2}) ?/g, "0x$1 ").replace(/ +$/, "").split(" "))); 186 | } 187 | var base64ToHex = function (str) { 188 | for (var i = 0, 189 | bin = base64decode(str.replace(/[ \r\n]+$/, "")), hex = []; i < bin.length; ++i) { 190 | var tmp = bin.charCodeAt(i).toString(16); 191 | if (tmp.length === 1) tmp = "0" + tmp; 192 | hex[hex.length] = tmp; 193 | } 194 | return hex.join(""); 195 | }; 196 | 197 | let ddns = {}; 198 | ddns.owner = getArgs().owner; 199 | ddns.token = getArgs().token; 200 | ddns.repo = getArgs().repo; 201 | ddns.branch = getArgs().branch; 202 | ddns.filePath = getArgs().filePath; 203 | ddns.fileName = getArgs().fileName; 204 | ddns.commitMessage = "Auto update"; 205 | 206 | (async function() { 207 | console.log("等待 1 分钟后运行脚本..."); //防止网络更换脚本识别错误 208 | await new Promise(resolve => setTimeout(resolve, 60000)); 209 | console.log("开始运行脚本..."); 210 | await Promise.all([ 211 | getV4(), //如果没有公网v4不要执行此条,因为api能获取到公网IP但你没有。surge连接此地址不通。直接使用ddns.v4 = null 212 | getV6(), //有公网v6。这里v6可以直接使用$network.v6.primaryAddress。不用api请求更快更准。没有公网v6使用ddns.v6 = null 213 | getSha() 214 | ]); 215 | ddns.fileContent = ddns.v4 + ';' + ddns.v6 + ';' 216 | ddns.hexContent = stringToHex(ddns.fileContent); 217 | ddns.base64Content = hexToBase64(ddns.hexContent); 218 | console.log(ddns.base64Content) 219 | await commit(); 220 | $done(); 221 | })(); 222 | 223 | // get public ip 224 | function getV4() { 225 | return new Promise(function(resolve) { 226 | $httpClient.get('https://api.ipify.org', function(error,head,data) { 227 | ddns.v4 = data 228 | console.log(ddns.v4) 229 | resolve() 230 | }) 231 | }); 232 | } 233 | 234 | function getV6() { 235 | return new Promise(function(resolve) { 236 | $httpClient.get('https://api64.ipify.org', function(error,head,data) { 237 | ddns.v6 = data 238 | console.log(ddns.v6) 239 | resolve() 240 | }) 241 | }); 242 | } 243 | 244 | //获取文件sha值 245 | function getSha() { 246 | return new Promise(function(resolve) { 247 | $httpClient.get({ 248 | url: `https://api.github.com/repos/${ddns.owner}/${ddns.repo}/contents/${ddns.fileName}`, 249 | headers: { 250 | "Authorization": 'token ' + ddns.token 251 | }}, 252 | function(error,headers,resp) { 253 | let jsonResp = JSON.parse(resp) 254 | ddns.sha = jsonResp.sha 255 | resolve() 256 | } 257 | ); 258 | }) 259 | } 260 | 261 | //commit message 262 | function commit() { 263 | const body = { 264 | message: ddns.commitMessage, 265 | content: ddns.base64Content, 266 | branch: ddns.branch, 267 | sha: ddns.sha, 268 | }; 269 | return new Promise(function(resolve) { 270 | $httpClient.put({ 271 | url: `https://api.github.com/repos/${ddns.owner}/${ddns.repo}/contents/${ddns.fileName}`, 272 | headers: { 273 | "Authorization": 'token ' + ddns.token 274 | }, 275 | body: body}, 276 | function(error,headers,resp) { 277 | console.log(headers.status) 278 | console.log(resp) 279 | if (headers.status === 200 || headers.status === 201) { 280 | $notification.post('Commit DDNS IP','文件上传/修改成功!',''), 281 | console.log("文件修改成功!"); 282 | resolve(); 283 | } else { 284 | console.log("文件修改失败!"); 285 | console.log(error) 286 | resolve(); 287 | } 288 | }, 289 | ); 290 | }) 291 | } --------------------------------------------------------------------------------