├── Hey.m4a ├── package.json ├── readme.md ├── src ├── console-colors.js ├── convert-stores.js └── index.js ├── db ├── models.md ├── stores.md ├── stores.json └── stores.xml └── .gitignore /Hey.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShinChven/apple-storage-watcher/HEAD/Hey.m4a -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apple-storage-watcher", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "start": "node src/index.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "json2md": "^2.0.0", 15 | "node-schedule": "^2.1.1", 16 | "sound-play": "^1.1.0", 17 | "superagent": "^8.1.2", 18 | "xml2js": "^0.6.2" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Apple Storage Watcher 2 | 3 | > 简陋版 苹果库存检查器 4 | > A really simple Apple Storage Watcher from commandline. 5 | 6 | ## Installation 安装 7 | 8 | ```bash 9 | npm install 10 | ``` 11 | 12 | ## Usage 使用 13 | 14 | ```bash 15 | npm start 16 | ``` 17 | 18 | ## Configuration 配置 19 | 20 | - [Store Codes / 店铺编码](db/stores.md) 21 | - [Products Code / 产品编码](db/models.md) 22 | 23 | ## 支持2种模式 24 | ## 1.Interval 时钟频率 25 | 26 | [Request Interval / 配置时钟频率](src/index.js#L64) 27 | 28 | ## 2.ScheduleJob 周期性定时运行 29 | [Request Schedule / 配置周期性定时运行](src/index.js#L150) 30 | 31 | ### 使用 cron 设定 周期性定时运行,设置及验证规则可参考[cron在线解析](https://cron.qqe2.com/) -------------------------------------------------------------------------------- /src/console-colors.js: -------------------------------------------------------------------------------- 1 | const consoleColors = { 2 | Reset: "\x1b[0m", 3 | Bright: "\x1b[1m", 4 | Dim: "\x1b[2m", 5 | Underscore: "\x1b[4m", 6 | Blink: "\x1b[5m", 7 | Reverse: "\x1b[7m", 8 | Hidden: "\x1b[8m", 9 | 10 | FgBlack: "\x1b[30m", 11 | FgRed: "\x1b[31m", 12 | FgGreen: "\x1b[32m", 13 | FgYellow: "\x1b[33m", 14 | FgBlue: "\x1b[34m", 15 | FgMagenta: "\x1b[35m", 16 | FgCyan: "\x1b[36m", 17 | FgWhite: "\x1b[37m", 18 | 19 | BgBlack: "\x1b[40m", 20 | BgRed: "\x1b[41m", 21 | BgGreen: "\x1b[42m", 22 | BgYellow: "\x1b[43m", 23 | BgBlue: "\x1b[44m", 24 | BgMagenta: "\x1b[45m", 25 | BgCyan: "\x1b[46m", 26 | BgWhite: "\x1b[47m", 27 | } 28 | 29 | module.exports = consoleColors; 30 | -------------------------------------------------------------------------------- /db/models.md: -------------------------------------------------------------------------------- 1 | # Model References 2 | 3 | ## iPhone 15 Series 4 | 5 | | Model | Model Name | Storage | Color | 6 | | --------- | ----------------- | ------- | ---------- | 7 | | MTQ63CH/A | iPhone 15 Pro | 128GB | 原色钛金属 | 8 | | MTQ73CH/A | iPhone 15 Pro | 128GB | 蓝色钛金属 | 9 | | MTQ53CH/A | iPhone 15 Pro | 128GB | 白色钛金属 | 10 | | MTQ43CH/A | iPhone 15 Pro | 128GB | 黑色钛金属 | 11 | | MTQA3CH/A | iPhone 15 Pro | 256GB | 原色钛金属 | 12 | | MTQC3CH/A | iPhone 15 Pro | 256GB | 蓝色钛金属 | 13 | | MTQ93CH/A | iPhone 15 Pro | 256GB | 白色钛金属 | 14 | | MTQ83CH/A | iPhone 15 Pro | 256GB | 黑色钛金属 | 15 | | MTQF3CH/A | iPhone 15 Pro | 512GB | 原色钛金属 | 16 | | MTQG3CH/A | iPhone 15 Pro | 512GB | 蓝色钛金属 | 17 | | MTQE3CH/A | iPhone 15 Pro | 512GB | 白色钛金属 | 18 | | MTQD3CH/A | iPhone 15 Pro | 512GB | 黑色钛金属 | 19 | | MTQK3CH/A | iPhone 15 Pro | 1TB | 原色钛金属 | 20 | | MTQL3CH/A | iPhone 15 Pro | 1TB | 蓝色钛金属 | 21 | | MTQJ3CH/A | iPhone 15 Pro | 1TB | 白色钛金属 | 22 | | MTQH3CH/A | iPhone 15 Pro | 1TB | 黑色钛金属 | 23 | | MU2Q3CH/A | iPhone 15 Pro Max | 256GB | 原色钛金属 | 24 | | MU2R3CH/A | iPhone 15 Pro Max | 256GB | 蓝色钛金属 | 25 | | MU2P3CH/A | iPhone 15 Pro Max | 256GB | 白色钛金属 | 26 | | MU2N3CH/A | iPhone 15 Pro Max | 256GB | 黑色钛金属 | 27 | | MU2V3CH/A | iPhone 15 Pro Max | 512GB | 原色钛金属 | 28 | | MU2W3CH/A | iPhone 15 Pro Max | 512GB | 蓝色钛金属 | -------------------------------------------------------------------------------- /src/convert-stores.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const json2md = require('json2md'); 3 | const xml2js = require('xml2js'); 4 | const yaml = require('js-yaml'); 5 | 6 | // Read the XML file 7 | fs.readFile('db/stores.xml', (err, data) => { 8 | if (err) { 9 | console.error(err); 10 | return; 11 | } 12 | 13 | // Parse the XML to JSON 14 | const parser = new xml2js.Parser(); 15 | parser.parseString(data, (err, result) => { 16 | if (err) { 17 | console.error(err); 18 | return; 19 | } 20 | 21 | // Convert the JSON to Markdown 22 | const markdown = json2md([ 23 | { h1: 'Apple Stores in China' }, 24 | ...result.records.country.map(country => ({ 25 | h2: country.$.name, 26 | table: { 27 | headers: ['Name', 'Apple ID', 'City', 'Phone', 'Longitude', 'Latitude', 'Link'], 28 | rows: country.state.map(state => state.store.map(store => [ 29 | store.name[0], 30 | store.appleid[0], 31 | state.$.name, 32 | store.phone[0], 33 | store.longitude[0], 34 | store.latitude[0], 35 | `[Link](${store.link[0]})` 36 | ])).flat() 37 | } 38 | })) 39 | ]); 40 | 41 | // Write the Markdown to a file 42 | fs.writeFile('db/stores.md', markdown, (err) => { 43 | if (err) { 44 | console.error(err); 45 | return; 46 | } 47 | console.log('Markdown file written successfully!'); 48 | }); 49 | 50 | // Convert the JSON to a string 51 | const jsonString = JSON.stringify(result); 52 | 53 | 54 | // Write the JSON to a file 55 | fs.writeFile('db/stores.json', jsonString, (err) => { 56 | if (err) { 57 | console.error(err); 58 | return; 59 | } 60 | console.log('JSON file written successfully!'); 61 | }); 62 | }); 63 | }); -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | output/ 2 | lib/ 3 | 4 | test/config.json 5 | 6 | *.sqlite 7 | 8 | # Created by .ignore support plugin (hsz.mobi) 9 | ### Linux template 10 | *~ 11 | 12 | # temporary files which can be created if a process still has a handle open of a deleted file 13 | .fuse_hidden* 14 | 15 | # KDE directory preferences 16 | .directory 17 | 18 | # Linux trash folder which might appear on any partition or disk 19 | .Trash-* 20 | 21 | # .nfs files are created when an open file is removed but is still being accessed 22 | .nfs* 23 | 24 | ### Windows template 25 | # Windows thumbnail cache files 26 | Thumbs.db 27 | Thumbs.db:encryptable 28 | ehthumbs.db 29 | ehthumbs_vista.db 30 | 31 | # Dump file 32 | *.stackdump 33 | 34 | # Folder config file 35 | [Dd]esktop.ini 36 | 37 | # Recycle Bin used on file shares 38 | $RECYCLE.BIN/ 39 | 40 | # Windows Installer files 41 | *.cab 42 | *.msi 43 | *.msix 44 | *.msm 45 | *.msp 46 | 47 | # Windows shortcuts 48 | *.lnk 49 | 50 | package-lock.json 51 | 52 | ### Node template 53 | # Logs 54 | logs 55 | *.log 56 | npm-debug.log* 57 | yarn-debug.log* 58 | yarn-error.log* 59 | lerna-debug.log* 60 | 61 | # Diagnostic reports (https://nodejs.org/api/report.html) 62 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 63 | 64 | # Runtime data 65 | pids 66 | *.pid 67 | *.seed 68 | *.pid.lock 69 | 70 | # Directory for instrumented libs generated by jscoverage/JSCover 71 | lib-cov 72 | 73 | # Coverage directory used by tools like istanbul 74 | coverage 75 | *.lcov 76 | 77 | # nyc test coverage 78 | .nyc_output 79 | 80 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 81 | .grunt 82 | 83 | # Bower dependency directory (https://bower.io/) 84 | bower_components 85 | 86 | # node-waf configuration 87 | .lock-wscript 88 | 89 | # Compiled binary addons (https://nodejs.org/api/addons.html) 90 | build/Release 91 | 92 | # Dependency directories 93 | node_modules/ 94 | jspm_packages/ 95 | 96 | # Snowpack dependency directory (https://snowpack.dev/) 97 | web_modules/ 98 | 99 | # TypeScript cache 100 | *.tsbuildinfo 101 | 102 | # Optional npm cache directory 103 | .npm 104 | 105 | # Optional eslint cache 106 | .eslintcache 107 | 108 | # Microbundle cache 109 | .rpt2_cache/ 110 | .rts2_cache_cjs/ 111 | .rts2_cache_es/ 112 | .rts2_cache_umd/ 113 | 114 | # Optional REPL history 115 | .node_repl_history 116 | 117 | # Output of 'npm pack' 118 | *.tgz 119 | 120 | # Yarn Integrity file 121 | .yarn-integrity 122 | 123 | # dotenv environment variables file 124 | .env 125 | .env.test 126 | 127 | # parcel-bundler cache (https://parceljs.org/) 128 | .cache 129 | .parcel-cache 130 | 131 | # Next.js build output 132 | .next 133 | out 134 | 135 | # Nuxt.js build / generate output 136 | .nuxt 137 | dist 138 | 139 | # Gatsby files 140 | .cache/ 141 | # Comment in the public line in if your project uses Gatsby and not Next.js 142 | # https://nextjs.org/blog/next-9-1#public-directory-support 143 | # public 144 | 145 | # vuepress build output 146 | .vuepress/dist 147 | 148 | # Serverless directories 149 | .serverless/ 150 | 151 | # FuseBox cache 152 | .fusebox/ 153 | 154 | # DynamoDB Local files 155 | .dynamodb/ 156 | 157 | # TernJS port file 158 | .tern-port 159 | 160 | # Stores VSCode versions used for testing VSCode extensions 161 | .vscode-test 162 | 163 | # yarn v2 164 | .yarn/cache 165 | .yarn/unplugged 166 | .yarn/build-state.yml 167 | .yarn/install-state.gz 168 | .pnp.* 169 | 170 | ### Example user template template 171 | ### Example user template 172 | 173 | # IntelliJ project files 174 | .idea 175 | *.iml 176 | out 177 | gen 178 | ### macOS template 179 | # General 180 | .DS_Store 181 | .AppleDouble 182 | .LSOverride 183 | 184 | # Icon must end with two \r 185 | Icon 186 | 187 | # Thumbnails 188 | ._* 189 | 190 | # Files that might appear in the root of a volume 191 | .DocumentRevisions-V100 192 | .fseventsd 193 | .Spotlight-V100 194 | .TemporaryItems 195 | .Trashes 196 | .VolumeIcon.icns 197 | .com.apple.timemachine.donotpresent 198 | 199 | # Directories potentially created on remote AFP share 200 | .AppleDB 201 | .AppleDesktop 202 | Network Trash Folder 203 | Temporary Items 204 | .apdisk 205 | 206 | -------------------------------------------------------------------------------- /db/stores.md: -------------------------------------------------------------------------------- 1 | # Apple Stores in China 2 | 3 | ## China 4 | | Name | Apple ID | City | Phone | Longitude | Latitude | Link | 5 | | ---- | -------- | ---- | ----- | --------- | -------- | ---- | 6 | | 七宝 | R705 | 上海 | 400-613-9773 | 121.345228 | 31.156105 | [Link](https://www.apple.com.cn/retail/qibao/) | 7 | | 上海环贸 iapm | R401 | 上海 | 400-617-1324 | 121.453441 | 31.217679 | [Link](https://www.apple.com.cn/retail/shanghaiiapm/) | 8 | | 五角场 | R581 | 上海 | 400-613-9771 | 121.514167 | 31.301667 | [Link](https://www.apple.com.cn/retail/wujiaochang/) | 9 | | 南京东路 | R359 | 上海 | 400-663-9988 | 121.47954 | 31.23943 | [Link](https://www.apple.com.cn/retail/nanjingeast/) | 10 | | 浦东 | R389 | 上海 | 400-617-1305 | 121.49695 | 31.23937 | [Link](https://www.apple.com.cn/retail/pudong/) | 11 | | 环球港 | R683 | 上海 | 400-617-1335 | 121.407222 | 31.233611 | [Link](https://www.apple.com.cn/retail/globalharbor/) | 12 | | 香港广场 | R390 | 上海 | 400-617-1312 | 121.46994 | 31.22555 | [Link](https://www.apple.com.cn/retail/hongkongplaza/) | 13 | | 昆明 | R670 | 云南 | 400-639-3602 | 102.706111 | 25.039167 | [Link](https://www.apple.com.cn/retail/kunming/) | 14 | | 三里屯 | R320 | 北京 | 400-617-1363 | 116.447967 | 39.933456 | [Link](https://www.apple.com.cn/retail/sanlitun/) | 15 | | 华贸购物中心 | R479 | 北京 | 400-617-1210 | 116.47316 | 39.90804 | [Link](https://www.apple.com.cn/retail/chinacentralmall/) | 16 | | 朝阳大悦城 | R645 | 北京 | 400-617-1284 | 116.511624 | 39.923571 | [Link](https://www.apple.com.cn/retail/chaoyangjoycity/) | 17 | | 王府井 | R448 | 北京 | 400-617-1205 | 116.405781 | 39.913621 | [Link](https://www.apple.com.cn/retail/wangfujing/) | 18 | | 西单大悦城 | R388 | 北京 | 400-617-1204 | 116.36727 | 39.90917 | [Link](https://www.apple.com.cn/retail/xidanjoycity/) | 19 | | 成都万象城 | R502 | 四川 | 400-617-1214 | 104.112546 | 30.652387 | [Link](https://www.apple.com.cn/retail/mixcchengdu/) | 20 | | 成都太古里 | R580 | 四川 | 400-617-1275 | 104.080782 | 30.653748 | [Link](https://www.apple.com.cn/retail/taikoolichengdu/) | 21 | | 天津万象城 | R638 | 天津 | 400-613-9745 | 117.20707 | 39.08892 | [Link](https://www.apple.com.cn/retail/mixctianjin/) | 22 | | 天津大悦城 | R637 | 天津 | 400-617-1262 | 117.173993 | 39.134588 | [Link](https://www.apple.com.cn/retail/tianjinjoycity/) | 23 | | 天津恒隆广场 | R579 | 天津 | 400-613-9744 | 117.19388 | 39.12662 | [Link](https://www.apple.com.cn/retail/riverside66tianjin/) | 24 | | 济南恒隆广场 | R648 | 山东 | 400-613-9743 | 117.018213 | 36.664099 | [Link](https://www.apple.com.cn/retail/parc66jinan/) | 25 | | 青岛万象城 | R557 | 山东 | 400-617-1285 | 120.3746 | 36.06571 | [Link](https://www.apple.com.cn/retail/mixcqingdao/) | 26 | | 天环广场 | R577 | 广东 | 400-613-9742 | 113.31916 | 23.135 | [Link](https://www.apple.com.cn/retail/parccentral/) | 27 | | 珠江新城 | R639 | 广东 | 400-639-3601 | 113.32729 | 23.118437 | [Link](https://www.apple.com.cn/retail/zhujiangnewtown/) | 28 | | 深圳益田假日广场 | R484 | 广东 | 400-617-1254 | 113.97079 | 22.53986 | [Link](https://www.apple.com.cn/retail/holidayplazashenzhen/) | 29 | | 南宁万象城 | R571 | 广西壮族自治区 | 400-617-1265 | 108.388345 | 22.814123 | [Link](https://www.apple.com.cn/retail/mixcnanning/) | 30 | | 南京艾尚天地 | R493 | 江苏 | 400-617-1334 | 118.779405 | 32.048234 | [Link](https://www.apple.com.cn/retail/nanjingist/) | 31 | | 玄武湖 | R703 | 江苏 | 400-613-9772 | 118.778214 | 32.074006 | [Link](https://www.apple.com.cn/retail/xuanwulake/) | 32 | | 虹悦城 | R643 | 江苏 | 400-617-1332 | 118.759761 | 32.011387 | [Link](https://www.apple.com.cn/retail/wondercity/) | 33 | | 无锡恒隆广场 | R574 | 江苏 | 400-617-1325 | 120.29362 | 31.576872 | [Link](https://www.apple.com.cn/retail/center66wuxi/) | 34 | | 苏州 | R688 | 江苏 | 400-613-9775 | 120.672737 | 31.318124 | [Link](https://www.apple.com.cn/retail/suzhou/) | 35 | | 郑州万象城 | R572 | 河南 | 400-617-1264 | 113.656689 | 34.755756 | [Link](https://www.apple.com.cn/retail/mixczhengzhou/) | 36 | | 天一广场 | R531 | 浙江 | 400-613-9774 | 121.549272 | 29.872722 | [Link](https://www.apple.com.cn/retail/tianyisquare/) | 37 | | 杭州万象城 | R532 | 浙江 | 400-617-1304 | 120.210154 | 30.254012 | [Link](https://www.apple.com.cn/retail/mixchangzhou/) | 38 | | 西湖 | R471 | 浙江 | 400-617-1302 | 120.158777 | 30.256553 | [Link](https://www.apple.com.cn/retail/westlake/) | 39 | | 厦门新生活广场 | R644 | 福建 | 400-617-1383 | 118.1204 | 24.5024 | [Link](https://www.apple.com.cn/retail/xiamenlifestylecenter/) | 40 | | 泰禾广场 | R646 | 福建 | 400-617-1354 | 119.331828 | 26.09336 | [Link](https://www.apple.com.cn/retail/tahoeplaza/) | 41 | | 大连恒隆广场 | R609 | 辽宁 | 400-613-9741 | 121.605313 | 38.905865 | [Link](https://www.apple.com.cn/retail/olympia66dalian/) | 42 | | 百年城 | R478 | 辽宁 | 400-056-0921 | 121.631667 | 38.91494 | [Link](https://www.apple.com.cn/retail/parkland/) | 43 | | 中街大悦城 | R534 | 辽宁 | 400-617-1252 | 123.462022 | 41.800213 | [Link](https://www.apple.com.cn/retail/zhongjiejoycity/) | 44 | | 沈阳万象城 | R576 | 辽宁 | 400-617-1274 | 123.42897 | 41.77235 | [Link](https://www.apple.com.cn/retail/mixcshenyang/) | 45 | | 解放碑 | R480 | 重庆 | 400-617-1224 | 106.572272 | 29.560981 | [Link](https://www.apple.com.cn/retail/jiefangbei/) | 46 | | 重庆万象城 | R573 | 重庆 | 400-617-1215 | 106.514417 | 29.518192 | [Link](https://www.apple.com.cn/retail/mixcchongqing/) | 47 | | 重庆北城天街 | R476 | 重庆 | 400-617-1240 | 106.529328 | 29.580283 | [Link](https://www.apple.com.cn/retail/paradisewalkchongqing/) | 48 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const http = require('superagent'); 2 | const consoleColors = require('./console-colors'); 3 | const sound = require('sound-play'); 4 | const schedule = require('node-schedule'); 5 | 6 | /** 7 | * 要监听的型号 8 | */ 9 | const models = { 10 | // -----iPhone 15 Pro ----- 11 | 12 | // // iPhone 15 Pro 128GB 13 | // 'MTQ63CH/A': '原色钛金属', 14 | // 'MTQ73CH/A': '蓝色钛金属', 15 | // 'MTQ53CH/A': '白色钛金属', 16 | // 'MTQ43CH/A': '黑色钛金属', 17 | 18 | // // iPhone 15 Pro 256GB 19 | // 'MTQA3CH/A': '原色钛金属', 20 | // 'MTQC3CH/A': '蓝色钛金属', 21 | // 'MTQ93CH/A': '白色钛金属', 22 | // 'MTQ83CH/A': '黑色钛金属', 23 | 24 | // // iPhone 15 Pro 512GB 25 | // 'MTQF3CH/A': '原色钛金属', 26 | // 'MTQG3CH/A': '蓝色钛金属', 27 | // 'MTQE3CH/A': '白色钛金属', 28 | // 'MTQD3CH/A': '黑色钛金属', 29 | 30 | // // iPhone 15 Pro 1TB 31 | // 'MTQK3CH/A': '原色钛金属', 32 | // 'MTQL3CH/A': '蓝色钛金属', 33 | // 'MTQJ3CH/A': '白色钛金属', 34 | // 'MTQH3CH/A': '黑色钛金属', 35 | 36 | // -----iPhone 15 Pro Max----- 37 | 38 | // iPhone 15 Pro Max 256GB 39 | // 'MU2Q3CH/A': '原色钛金属', 40 | // 'MU2R3CH/A': '蓝色钛金属', 41 | // 'MU2P3CH/A': '白色钛金属', 42 | // 'MU2N3CH/A': '黑色钛金属', 43 | 44 | // // iPhone 15 Pro Max 512GB 45 | // 'MU2V3CH/A': '原色钛金属', 46 | 'MU2W3CH/A': '蓝色钛金属', 47 | // 'MU2U3CH/A': '白色钛金属', 48 | // 'MU2T3CH/A': '黑色钛金属', 49 | // // iPhone 15 Pro Max 1TB 50 | // 'MU603CH/A': '原色钛金属', 51 | // 'MU613CH/A': '蓝色钛金属', 52 | // 'MU2Y3CH/A': '白色钛金属', 53 | // 'MU2X3CH/A': '黑色钛金属', 54 | } 55 | 56 | const searchNearby = true; 57 | // 默认查询 浦东店 58 | const storeNum = 'R389'; 59 | 60 | 61 | const monitorIphoneStorage = async (productName) => { 62 | // 获取单个门店库存数据 63 | // const url = encodeURI(`https://www.apple.com.cn/shop/fulfillment-messages?pl=true&mts.0=regular&parts.0=${productName}&location=${locationName}`); 64 | // 查询 附近门店,searchNearby=false 查询指定门店 65 | // 查询指定门店及附近门店数据 66 | const url = encodeURI(`https://www.apple.com.cn/shop/fulfillment-messages?pl=true&mts.0=regular&mts.1=compact&parts.0=${productName}&searchNearby=${searchNearby}&store=${storeNum}`); 67 | console.log(consoleColors.Reset, url); 68 | const res = await http.get(url); 69 | // console.log('res=>>>', res); 70 | const { 71 | stores 72 | } = res.body.body.content.pickupMessage; 73 | const { 74 | subHeader 75 | } = res.body.body.content.deliveryMessage[productName].regular; 76 | 77 | console.log(subHeader, productName); 78 | 79 | if (Array.isArray(stores) && stores.length > 0) { 80 | for (const store of stores) { 81 | try { 82 | const { 83 | pickupDisplay 84 | } = store.partsAvailability[productName]; 85 | const color = pickupDisplay === 'available' ? consoleColors.FgGreen : consoleColors.FgRed; 86 | const { city, storeName } = store; 87 | console.log(color, city, storeName, pickupDisplay); 88 | pickupDisplay === 'available' && sound.play('Hey.m4a'); 89 | } catch (e) { 90 | console.error(consoleColors.FgRed, '解析店铺信息出错'); 91 | } 92 | } 93 | } else { 94 | console.log(consoleColors.FgRed, subHeader, { 95 | productName, 96 | storage: '无货可用商店', 97 | }); 98 | } 99 | 100 | } 101 | 102 | // 选择颜色 103 | const selectColors = []; 104 | 105 | const startTask = async () => { 106 | console.time(`----------------刷新耗时----------------`); 107 | console.log(consoleColors.Reset, `----------------本次刷新开始 ${new Date().toLocaleString()}----------------\n`); 108 | for (const [productName, productColor] of Object.entries(models)) { 109 | try { 110 | if (selectColors.length === 0 || selectColors.includes(productColor)) { 111 | await monitorIphoneStorage(productName); 112 | } 113 | } catch (e) { 114 | console.error(e); 115 | } 116 | console.log(consoleColors.Reset, `----------------${new Date().toLocaleString()}----------------`); 117 | } 118 | console.log(consoleColors.Reset, `----------------本次刷新结束 ${new Date().toLocaleString()}----------------\n`); 119 | console.timeEnd(`----------------刷新耗时----------------`); 120 | console.log('\n'); 121 | } 122 | 123 | /** 124 | * Run program in loop 125 | */ 126 | // const interval = setInterval(async () => { 127 | // await startTask(); 128 | // }, 1000 * (30 + Math.floor(Math.random()*10))); // Fetch interval 刷新周期,别太快。 129 | 130 | // setTimeout(async () => { 131 | // clearInterval(interval); 132 | // console.log(consoleColors.Reset, `----------------定时任务结束 ${new Date().toLocaleString()}----------------`); 133 | // process.exit(); 134 | // }, 10 * 60 * 1000); 135 | 136 | 137 | // 周期性运行定时任务 138 | // 开始时间 139 | const startTime = new Date(Date.now()); 140 | // 结束时间, 持续运行时间要大于 开始运行的时间,否则定制任务不会执行 141 | // 设定持续运行时间 24小时 142 | const endTime = new Date(startTime.getTime() + 24 * 3600 * 1000); 143 | 144 | // 切忌 请求过快,可能会被封IP 145 | // 每2分钟执行一次 0 0/2 * * * ? 146 | // 每天 15:00 - 19:00 每3分钟执行一次 147 | schedule.scheduleJob({ start: startTime, end: endTime, rule: '0 0/3 15,16,17,18 * * ?' }, function(){ 148 | // 设置一个相对随机的延迟,避免固定时间访问 149 | const timeOut = Math.floor(Math.random()*10) * 1000; 150 | setTimeout(async () => { 151 | await startTask(); 152 | }, timeOut); 153 | }); 154 | 155 | startTask().then(); -------------------------------------------------------------------------------- /db/stores.json: -------------------------------------------------------------------------------- 1 | {"records":{"$":{"storeWidgetVersion":"1.0","conciergeWidgetVersion":"1.0"},"country":[{"$":{"name":"China"},"state":[{"$":{"name":"上海"},"store":[{"appleid":["R705"],"name":["七宝"],"city":["上海"],"phone":["400-613-9773"],"longitude":["121.345228"],"latitude":["31.156105"],"link":["https://www.apple.com.cn/retail/qibao/"]},{"appleid":["R401"],"name":["上海环贸 iapm "],"city":["上海"],"phone":["400-617-1324"],"longitude":["121.453441"],"latitude":["31.217679"],"link":["https://www.apple.com.cn/retail/shanghaiiapm/"]},{"appleid":["R581"],"name":["五角场"],"city":["上海"],"phone":["400-613-9771"],"longitude":["121.514167"],"latitude":["31.301667"],"link":["https://www.apple.com.cn/retail/wujiaochang/"]},{"appleid":["R359"],"name":["南京东路"],"city":["上海"],"phone":["400-663-9988"],"longitude":["121.47954"],"latitude":["31.23943"],"link":["https://www.apple.com.cn/retail/nanjingeast/"]},{"appleid":["R389"],"name":["浦东"],"city":["上海"],"phone":["400-617-1305"],"longitude":["121.49695"],"latitude":["31.23937"],"link":["https://www.apple.com.cn/retail/pudong/"]},{"appleid":["R683"],"name":["环球港"],"city":["上海"],"phone":["400-617-1335"],"longitude":["121.407222"],"latitude":["31.233611"],"link":["https://www.apple.com.cn/retail/globalharbor/"]},{"appleid":["R390"],"name":["香港广场"],"city":["上海"],"phone":["400-617-1312"],"longitude":["121.46994"],"latitude":["31.22555"],"link":["https://www.apple.com.cn/retail/hongkongplaza/"]}]},{"$":{"name":"云南"},"store":[{"appleid":["R670"],"name":["昆明"],"city":["昆明"],"phone":["400-639-3602"],"longitude":["102.706111"],"latitude":["25.039167"],"link":["https://www.apple.com.cn/retail/kunming/"]}]},{"$":{"name":"北京"},"store":[{"appleid":["R320"],"name":["三里屯"],"city":["北京"],"phone":["400-617-1363"],"longitude":["116.447967"],"latitude":["39.933456"],"link":["https://www.apple.com.cn/retail/sanlitun/"]},{"appleid":["R479"],"name":["华贸购物中心"],"city":["北京"],"phone":["400-617-1210"],"longitude":["116.47316"],"latitude":["39.90804"],"link":["https://www.apple.com.cn/retail/chinacentralmall/"]},{"appleid":["R645"],"name":["朝阳大悦城"],"city":["北京"],"phone":["400-617-1284"],"longitude":["116.511624"],"latitude":["39.923571"],"link":["https://www.apple.com.cn/retail/chaoyangjoycity/"]},{"appleid":["R448"],"name":["王府井"],"city":["北京"],"phone":["400-617-1205"],"longitude":["116.405781"],"latitude":["39.913621"],"link":["https://www.apple.com.cn/retail/wangfujing/"]},{"appleid":["R388"],"name":["西单大悦城"],"city":["北京"],"phone":["400-617-1204"],"longitude":["116.36727"],"latitude":["39.90917"],"link":["https://www.apple.com.cn/retail/xidanjoycity/"]}]},{"$":{"name":"四川"},"store":[{"appleid":["R502"],"name":["成都万象城"],"city":["成都"],"phone":["400-617-1214"],"longitude":["104.112546"],"latitude":["30.652387"],"link":["https://www.apple.com.cn/retail/mixcchengdu/"]},{"appleid":["R580"],"name":["成都太古里"],"city":["成都"],"phone":["400-617-1275"],"longitude":["104.080782"],"latitude":["30.653748"],"link":["https://www.apple.com.cn/retail/taikoolichengdu/"]}]},{"$":{"name":"天津"},"store":[{"appleid":["R638"],"name":["天津万象城"],"city":["天津"],"phone":["400-613-9745"],"longitude":["117.20707"],"latitude":["39.08892"],"link":["https://www.apple.com.cn/retail/mixctianjin/"]},{"appleid":["R637"],"name":["天津大悦城"],"city":["天津"],"phone":["400-617-1262"],"longitude":["117.173993"],"latitude":["39.134588"],"link":["https://www.apple.com.cn/retail/tianjinjoycity/"]},{"appleid":["R579"],"name":["天津恒隆广场"],"city":["天津"],"phone":["400-613-9744"],"longitude":["117.19388"],"latitude":["39.12662"],"link":["https://www.apple.com.cn/retail/riverside66tianjin/"]}]},{"$":{"name":"山东"},"store":[{"appleid":["R648"],"name":["济南恒隆广场"],"city":["济南"],"phone":["400-613-9743"],"longitude":["117.018213"],"latitude":["36.664099"],"link":["https://www.apple.com.cn/retail/parc66jinan/"]},{"appleid":["R557"],"name":["青岛万象城"],"city":["青岛"],"phone":["400-617-1285"],"longitude":["120.3746"],"latitude":["36.06571"],"link":["https://www.apple.com.cn/retail/mixcqingdao/"]}]},{"$":{"name":"广东"},"store":[{"appleid":["R577"],"name":["天环广场 "],"city":["广州"],"phone":["400-613-9742"],"longitude":["113.31916"],"latitude":["23.135"],"link":["https://www.apple.com.cn/retail/parccentral/"]},{"appleid":["R639"],"name":["珠江新城"],"city":["广州"],"phone":["400-639-3601"],"longitude":["113.32729"],"latitude":["23.118437"],"link":["https://www.apple.com.cn/retail/zhujiangnewtown/"]},{"appleid":["R484"],"name":["深圳益田假日广场"],"city":["深圳"],"phone":["400-617-1254"],"longitude":["113.97079"],"latitude":["22.53986"],"link":["https://www.apple.com.cn/retail/holidayplazashenzhen/"]}]},{"$":{"name":"广西壮族自治区"},"store":[{"appleid":["R571"],"name":["南宁万象城"],"city":["南宁"],"phone":["400-617-1265"],"longitude":["108.388345"],"latitude":["22.814123"],"link":["https://www.apple.com.cn/retail/mixcnanning/"]}]},{"$":{"name":"江苏"},"store":[{"appleid":["R493"],"name":["南京艾尚天地"],"city":["南京"],"phone":["400-617-1334"],"longitude":["118.779405"],"latitude":["32.048234"],"link":["https://www.apple.com.cn/retail/nanjingist/"]},{"appleid":["R703"],"name":["玄武湖"],"city":["南京"],"phone":["400-613-9772"],"longitude":["118.778214"],"latitude":["32.074006"],"link":["https://www.apple.com.cn/retail/xuanwulake/"]},{"appleid":["R643"],"name":["虹悦城"],"city":["南京"],"phone":["400-617-1332"],"longitude":["118.759761"],"latitude":["32.011387"],"link":["https://www.apple.com.cn/retail/wondercity/"]},{"appleid":["R574"],"name":["无锡恒隆广场"],"city":["无锡"],"phone":["400-617-1325"],"longitude":["120.29362"],"latitude":["31.576872"],"link":["https://www.apple.com.cn/retail/center66wuxi/"]},{"appleid":["R688"],"name":["苏州"],"city":["苏州"],"phone":["400-613-9775"],"longitude":["120.672737"],"latitude":["31.318124"],"link":["https://www.apple.com.cn/retail/suzhou/"]}]},{"$":{"name":"河南"},"store":[{"appleid":["R572"],"name":["郑州万象城"],"city":["郑州"],"phone":["400-617-1264"],"longitude":["113.656689"],"latitude":["34.755756"],"link":["https://www.apple.com.cn/retail/mixczhengzhou/"]}]},{"$":{"name":"浙江"},"store":[{"appleid":["R531"],"name":["天一广场"],"city":["宁波"],"phone":["400-613-9774"],"longitude":["121.549272"],"latitude":["29.872722"],"link":["https://www.apple.com.cn/retail/tianyisquare/"]},{"appleid":["R532"],"name":["杭州万象城"],"city":["杭州"],"phone":["400-617-1304"],"longitude":["120.210154"],"latitude":["30.254012"],"link":["https://www.apple.com.cn/retail/mixchangzhou/"]},{"appleid":["R471"],"name":["西湖"],"city":["杭州"],"phone":["400-617-1302"],"longitude":["120.158777"],"latitude":["30.256553"],"link":["https://www.apple.com.cn/retail/westlake/"]}]},{"$":{"name":"福建"},"store":[{"appleid":["R644"],"name":["厦门新生活广场"],"city":["厦门"],"phone":["400-617-1383"],"longitude":["118.1204"],"latitude":["24.5024"],"link":["https://www.apple.com.cn/retail/xiamenlifestylecenter/"]},{"appleid":["R646"],"name":["泰禾广场"],"city":["福州"],"phone":["400-617-1354"],"longitude":["119.331828"],"latitude":["26.09336"],"link":["https://www.apple.com.cn/retail/tahoeplaza/"]}]},{"$":{"name":"辽宁"},"store":[{"appleid":["R609"],"name":["大连恒隆广场"],"city":["大连"],"phone":["400-613-9741"],"longitude":["121.605313"],"latitude":["38.905865"],"link":["https://www.apple.com.cn/retail/olympia66dalian/"]},{"appleid":["R478"],"name":["百年城"],"city":["大连"],"phone":["400-056-0921"],"longitude":["121.631667"],"latitude":["38.91494"],"link":["https://www.apple.com.cn/retail/parkland/"]},{"appleid":["R534"],"name":["中街大悦城"],"city":["沈阳"],"phone":["400-617-1252"],"longitude":["123.462022"],"latitude":["41.800213"],"link":["https://www.apple.com.cn/retail/zhongjiejoycity/"]},{"appleid":["R576"],"name":["沈阳万象城"],"city":["沈阳"],"phone":["400-617-1274"],"longitude":["123.42897"],"latitude":["41.77235"],"link":["https://www.apple.com.cn/retail/mixcshenyang/"]}]},{"$":{"name":"重庆"},"store":[{"appleid":["R480"],"name":["解放碑"],"city":["重庆"],"phone":["400-617-1224"],"longitude":["106.572272"],"latitude":["29.560981"],"link":["https://www.apple.com.cn/retail/jiefangbei/"]},{"appleid":["R573"],"name":["重庆万象城"],"city":["重庆"],"phone":["400-617-1215"],"longitude":["106.514417"],"latitude":["29.518192"],"link":["https://www.apple.com.cn/retail/mixcchongqing/"]},{"appleid":["R476"],"name":["重庆北城天街"],"city":["重庆"],"phone":["400-617-1240"],"longitude":["106.529328"],"latitude":["29.580283"],"link":["https://www.apple.com.cn/retail/paradisewalkchongqing/"]}]}]}]}} -------------------------------------------------------------------------------- /db/stores.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | R705 6 | 七宝 7 | 上海 8 | 400-613-9773 9 | 121.345228 10 | 31.156105 11 | https://www.apple.com.cn/retail/qibao/ 12 | 13 | 14 | R401 15 | 上海环贸 iapm 16 | 上海 17 | 400-617-1324 18 | 121.453441 19 | 31.217679 20 | https://www.apple.com.cn/retail/shanghaiiapm/ 21 | 22 | 23 | R581 24 | 五角场 25 | 上海 26 | 400-613-9771 27 | 121.514167 28 | 31.301667 29 | https://www.apple.com.cn/retail/wujiaochang/ 30 | 31 | 32 | R359 33 | 南京东路 34 | 上海 35 | 400-663-9988 36 | 121.47954 37 | 31.23943 38 | https://www.apple.com.cn/retail/nanjingeast/ 39 | 40 | 41 | R389 42 | 浦东 43 | 上海 44 | 400-617-1305 45 | 121.49695 46 | 31.23937 47 | https://www.apple.com.cn/retail/pudong/ 48 | 49 | 50 | R683 51 | 环球港 52 | 上海 53 | 400-617-1335 54 | 121.407222 55 | 31.233611 56 | https://www.apple.com.cn/retail/globalharbor/ 57 | 58 | 59 | R390 60 | 香港广场 61 | 上海 62 | 400-617-1312 63 | 121.46994 64 | 31.22555 65 | https://www.apple.com.cn/retail/hongkongplaza/ 66 | 67 | 68 | 69 | 70 | R670 71 | 昆明 72 | 昆明 73 | 400-639-3602 74 | 102.706111 75 | 25.039167 76 | https://www.apple.com.cn/retail/kunming/ 77 | 78 | 79 | 80 | 81 | R320 82 | 三里屯 83 | 北京 84 | 400-617-1363 85 | 116.447967 86 | 39.933456 87 | https://www.apple.com.cn/retail/sanlitun/ 88 | 89 | 90 | R479 91 | 华贸购物中心 92 | 北京 93 | 400-617-1210 94 | 116.47316 95 | 39.90804 96 | https://www.apple.com.cn/retail/chinacentralmall/ 97 | 98 | 99 | R645 100 | 朝阳大悦城 101 | 北京 102 | 400-617-1284 103 | 116.511624 104 | 39.923571 105 | https://www.apple.com.cn/retail/chaoyangjoycity/ 106 | 107 | 108 | R448 109 | 王府井 110 | 北京 111 | 400-617-1205 112 | 116.405781 113 | 39.913621 114 | https://www.apple.com.cn/retail/wangfujing/ 115 | 116 | 117 | R388 118 | 西单大悦城 119 | 北京 120 | 400-617-1204 121 | 116.36727 122 | 39.90917 123 | https://www.apple.com.cn/retail/xidanjoycity/ 124 | 125 | 126 | 127 | 128 | R502 129 | 成都万象城 130 | 成都 131 | 400-617-1214 132 | 104.112546 133 | 30.652387 134 | https://www.apple.com.cn/retail/mixcchengdu/ 135 | 136 | 137 | R580 138 | 成都太古里 139 | 成都 140 | 400-617-1275 141 | 104.080782 142 | 30.653748 143 | https://www.apple.com.cn/retail/taikoolichengdu/ 144 | 145 | 146 | 147 | 148 | R638 149 | 天津万象城 150 | 天津 151 | 400-613-9745 152 | 117.20707 153 | 39.08892 154 | https://www.apple.com.cn/retail/mixctianjin/ 155 | 156 | 157 | R637 158 | 天津大悦城 159 | 天津 160 | 400-617-1262 161 | 117.173993 162 | 39.134588 163 | https://www.apple.com.cn/retail/tianjinjoycity/ 164 | 165 | 166 | R579 167 | 天津恒隆广场 168 | 天津 169 | 400-613-9744 170 | 117.19388 171 | 39.12662 172 | https://www.apple.com.cn/retail/riverside66tianjin/ 173 | 174 | 175 | 176 | 177 | R648 178 | 济南恒隆广场 179 | 济南 180 | 400-613-9743 181 | 117.018213 182 | 36.664099 183 | https://www.apple.com.cn/retail/parc66jinan/ 184 | 185 | 186 | R557 187 | 青岛万象城 188 | 青岛 189 | 400-617-1285 190 | 120.3746 191 | 36.06571 192 | https://www.apple.com.cn/retail/mixcqingdao/ 193 | 194 | 195 | 196 | 197 | R577 198 | 天环广场 199 | 广州 200 | 400-613-9742 201 | 113.31916 202 | 23.135 203 | https://www.apple.com.cn/retail/parccentral/ 204 | 205 | 206 | R639 207 | 珠江新城 208 | 广州 209 | 400-639-3601 210 | 113.32729 211 | 23.118437 212 | https://www.apple.com.cn/retail/zhujiangnewtown/ 213 | 214 | 215 | R484 216 | 深圳益田假日广场 217 | 深圳 218 | 400-617-1254 219 | 113.97079 220 | 22.53986 221 | https://www.apple.com.cn/retail/holidayplazashenzhen/ 222 | 223 | 224 | 225 | 226 | R571 227 | 南宁万象城 228 | 南宁 229 | 400-617-1265 230 | 108.388345 231 | 22.814123 232 | https://www.apple.com.cn/retail/mixcnanning/ 233 | 234 | 235 | 236 | 237 | R493 238 | 南京艾尚天地 239 | 南京 240 | 400-617-1334 241 | 118.779405 242 | 32.048234 243 | https://www.apple.com.cn/retail/nanjingist/ 244 | 245 | 246 | R703 247 | 玄武湖 248 | 南京 249 | 400-613-9772 250 | 118.778214 251 | 32.074006 252 | https://www.apple.com.cn/retail/xuanwulake/ 253 | 254 | 255 | R643 256 | 虹悦城 257 | 南京 258 | 400-617-1332 259 | 118.759761 260 | 32.011387 261 | https://www.apple.com.cn/retail/wondercity/ 262 | 263 | 264 | R574 265 | 无锡恒隆广场 266 | 无锡 267 | 400-617-1325 268 | 120.29362 269 | 31.576872 270 | https://www.apple.com.cn/retail/center66wuxi/ 271 | 272 | 273 | R688 274 | 苏州 275 | 苏州 276 | 400-613-9775 277 | 120.672737 278 | 31.318124 279 | https://www.apple.com.cn/retail/suzhou/ 280 | 281 | 282 | 283 | 284 | R572 285 | 郑州万象城 286 | 郑州 287 | 400-617-1264 288 | 113.656689 289 | 34.755756 290 | https://www.apple.com.cn/retail/mixczhengzhou/ 291 | 292 | 293 | 294 | 295 | R531 296 | 天一广场 297 | 宁波 298 | 400-613-9774 299 | 121.549272 300 | 29.872722 301 | https://www.apple.com.cn/retail/tianyisquare/ 302 | 303 | 304 | R532 305 | 杭州万象城 306 | 杭州 307 | 400-617-1304 308 | 120.210154 309 | 30.254012 310 | https://www.apple.com.cn/retail/mixchangzhou/ 311 | 312 | 313 | R471 314 | 西湖 315 | 杭州 316 | 400-617-1302 317 | 120.158777 318 | 30.256553 319 | https://www.apple.com.cn/retail/westlake/ 320 | 321 | 322 | 323 | 324 | R644 325 | 厦门新生活广场 326 | 厦门 327 | 400-617-1383 328 | 118.1204 329 | 24.5024 330 | https://www.apple.com.cn/retail/xiamenlifestylecenter/ 331 | 332 | 333 | R646 334 | 泰禾广场 335 | 福州 336 | 400-617-1354 337 | 119.331828 338 | 26.09336 339 | https://www.apple.com.cn/retail/tahoeplaza/ 340 | 341 | 342 | 343 | 344 | R609 345 | 大连恒隆广场 346 | 大连 347 | 400-613-9741 348 | 121.605313 349 | 38.905865 350 | https://www.apple.com.cn/retail/olympia66dalian/ 351 | 352 | 353 | R478 354 | 百年城 355 | 大连 356 | 400-056-0921 357 | 121.631667 358 | 38.91494 359 | https://www.apple.com.cn/retail/parkland/ 360 | 361 | 362 | R534 363 | 中街大悦城 364 | 沈阳 365 | 400-617-1252 366 | 123.462022 367 | 41.800213 368 | https://www.apple.com.cn/retail/zhongjiejoycity/ 369 | 370 | 371 | R576 372 | 沈阳万象城 373 | 沈阳 374 | 400-617-1274 375 | 123.42897 376 | 41.77235 377 | https://www.apple.com.cn/retail/mixcshenyang/ 378 | 379 | 380 | 381 | 382 | R480 383 | 解放碑 384 | 重庆 385 | 400-617-1224 386 | 106.572272 387 | 29.560981 388 | https://www.apple.com.cn/retail/jiefangbei/ 389 | 390 | 391 | R573 392 | 重庆万象城 393 | 重庆 394 | 400-617-1215 395 | 106.514417 396 | 29.518192 397 | https://www.apple.com.cn/retail/mixcchongqing/ 398 | 399 | 400 | R476 401 | 重庆北城天街 402 | 重庆 403 | 400-617-1240 404 | 106.529328 405 | 29.580283 406 | https://www.apple.com.cn/retail/paradisewalkchongqing/ 407 | 408 | 409 | 410 | --------------------------------------------------------------------------------