├── .gitignore ├── Readme.md ├── docs ├── 01-overview.md ├── 02-Docker.md ├── 03-rules.md ├── 04-JS.md ├── 05-rewrite.md ├── 06-task.md ├── 07-feed¬ify.md ├── 08-logger&efss.md ├── 09-webhook.md ├── 10-config.md ├── Advanced.md ├── Readme.md ├── dev_note │ ├── archive │ │ ├── favend JS 重构-efh.md │ │ ├── minishell subprocess.md │ │ ├── webUI.md │ │ └── websocket 通信协议设计.md │ ├── clash delegate efh.md │ ├── elecV2P 错误自检指南.md │ ├── ev 命令行程序.md │ ├── favend JS 重构-efh.md │ ├── favend 模块化.md │ ├── readme.md │ ├── runJSFile 执行逻辑及优化.md │ ├── script_store.efh 应用中心.md │ ├── service workers 开发与优化.md │ ├── sse 通信模块.md │ ├── store 常量加密存储读取.md │ ├── webUI transparent mode.md │ ├── webUI 主题设计.md │ ├── webUI 首页快捷运行程序 eapp.md │ ├── webhook token 权限设计.md │ ├── 下载其他扩展程序.md │ ├── 关于引入区块链的可行性.md │ ├── 可能永不执行的长期计划.md │ ├── 启动器快捷方式 $run.md │ ├── 开发者激励计划.md │ ├── 引入广告系统.md │ ├── 待深度优化部分.md │ ├── 根据 mitmhost 生成 pac 文件.md │ ├── 脚本缓存_内容结果等.md │ ├── 节点互联.md │ └── 通过脚本管理规则 $rewrite.md └── res │ ├── custnotify.png │ ├── eapp_edit.png │ ├── eapp_overview.png │ ├── evuitest.png │ ├── favend.png │ ├── favend2.png │ ├── iftttnotify.png │ ├── init.png │ ├── initrunjs.png │ ├── limitip.png │ ├── log_ansi_color.png │ ├── logo │ ├── V2P.svg │ ├── elecV2P-180x180.png │ ├── elecV2P.svg │ ├── elecV2P.t.svg │ ├── elecV2PB-720x720.png │ ├── elecV2PBR-720x720.png │ ├── elecV2PBW-720x720.png │ ├── elecV2P_noback_64x64.png │ ├── elecV2Pall-720x720.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon.ico │ └── readme.md │ ├── minishell.png │ ├── mock.png │ ├── overview.open.png │ ├── overview.png │ ├── overview.v331.png │ ├── overview.v344.png │ ├── rewrite.png │ ├── rewritenote.png │ ├── rootCAinstall.png │ ├── rules.png │ ├── security.png │ ├── setifttt.png │ ├── setiftttm.jpg │ ├── setting-eaxios.png │ ├── task.png │ ├── taskall.png │ ├── tasksub.png │ ├── temp_token.png │ ├── theme_preview_01.jpg │ ├── theme_preview_02.png │ └── theme_preview_03.png ├── examples ├── JS-elecV2P.sublime-build ├── JSTEST │ ├── 0body.js │ ├── TGbotonFavend.js │ ├── aria2-env.js │ ├── asyncPool.js │ ├── boxjs.ev.js │ ├── cheerio-hbin.js │ ├── efh │ │ ├── kuwo-music.efh │ │ ├── markdown.efh │ │ ├── notepad.efh │ │ └── readme.md │ ├── evui-chatroom.js │ ├── evui-dou.js │ ├── exam-ahk-send.js │ ├── exam-ahk.js │ ├── exam-chcp.js │ ├── exam-clipboard.js │ ├── exam-rss.js │ ├── exam-tasksub.js │ ├── example-cheerio.js │ ├── example-rule.js │ ├── fendtest.efh │ ├── github-subdownload.js │ ├── markdown.efh │ ├── reboot.js │ ├── simple.efh │ ├── starturl.js │ ├── tgbotmessage.js │ └── webonlinetest.js ├── Readme.md ├── Shell │ ├── aria2c │ ├── elecV2P-runjs.ahk │ ├── exam-request.py │ ├── mousemove.ahk │ └── sendkey.ahk ├── TGbotonCFworker.js ├── TGbotonCFworker2.0.js ├── archive │ ├── Caddyfile │ └── dht.dat ├── docker-compose-clash.yaml ├── docker-compose.yaml ├── ev2p-nginx.conf ├── res │ ├── boxjs-test.jpg │ ├── cookieadd.png │ ├── evuidou.png │ ├── evuiplayer.png │ ├── holdrequest.png │ ├── holdrespose.png │ ├── holdresults.png │ ├── ifttt-test.jpg │ ├── jdcookie.png │ ├── jdcookie2.png │ ├── rrtv.png │ ├── taskrun.png │ ├── tgbot.png │ └── tgbotkv.png └── theme │ ├── elecV2P_theme.20220420.json │ └── readme.md └── information ├── readme.md ├── res ├── dev_sponse_844x50t.png ├── gp_promo_844x50t.png ├── sponse_alipay.png ├── sponser_freebitco.in.png └── sponsors_overview.png ├── 广告位招租.md └── 开发者激励计划.md /.gitignore: -------------------------------------------------------------------------------- 1 | .git -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | ## elecV2P 文档/例程/通知/反馈 - documents/examples/information/issues 2 | 3 | 主项目地址: https://github.com/elecV2/elecV2P 4 | 5 | ![](https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/docs/res/overview.png) 6 | 7 | TG 频道: https://t.me/elecV2 8 | TG 交流群: https://t.me/elecV2G 9 | 10 | 欢迎提交功能需求或者其他建议。 11 | 12 | ### 说明 13 | 14 | - 文档目录:[docs](https://github.com/elecV2/elecV2P-dei/tree/master/docs) 15 | - 例程目录:[examples](https://github.com/elecV2/elecV2P-dei/tree/master/examples) 16 | - 初次使用建议先把 docs 内容浏览一遍,涉及内容较多,大部分可以直接跳过,在使用中碰到问题时再来查看 -------------------------------------------------------------------------------- /docs/01-overview.md: -------------------------------------------------------------------------------- 1 | ``` 2 | 最近更新: 2022-10-21 3 | 适用版本: 3.7.3 4 | ``` 5 | 6 | *此章节内容同步自 [elecV2P Readme 文档](https://github.com/elecV2/elecV2P)* 7 | 8 | ## 简介 9 | 10 | elecV2P - customize personal network. 11 | 一款基于 NodeJS,可通过 JS 修改网络请求,以及定时运行脚本或 SHELL 指令的网络工具。 12 | 13 | ![elecV2P overview/预览](https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/docs/res/overview.png) 14 | 15 | ### 基础功能 16 | 17 | - 查看/修改网络请求 (MITM) 18 | - 定时执行 JS/SHELL 脚本 19 | - FEED/IFTTT/自定义 通知 20 | - EFSS 基础文件管理 21 | 22 | ## 安装/INSTALL 23 | 24 | ***程序开放权限极大,建议局域网使用。公网部署(务必参考 [Advanced.md](https://github.com/elecV2/elecV2P-dei/blob/master/docs/Advanced.md)),风险自负*** 25 | 26 | *elecV2P 所有文件及依赖总大小约 90 M。初始运行时内存占用约 90 M,运行 100 个定时任务时总内存占用约 150 M(仅供参考,不同软硬件条件下程序调用资源可能有所不同)* 27 | 28 | **在可使用 Docker 的情况下,推荐使用方法三进行安装** 29 | 30 | ### 方法一:直接 NODEJS 运行 31 | 32 | **需求 NODEJS 版本 (node -v) >= 14.17.0** 33 | 34 | ``` sh 35 | git clone https://github.com/elecV2/elecV2P.git 36 | cd elecV2P 37 | 38 | # 安装依赖库(根据网络环境和硬盘读写速度,需要 1-10 分钟不等 39 | yarn 40 | 41 | # elecV2P 默认以 pm2 的方式启动,需要先安装好 pm2 42 | # pm2 的安装方式: 43 | # 1. 添加 elecV2P 所在目录/node_modules/.bin 到系统环境变量 PATH 中 44 | # 2. 或者直接执行 yarn global add pm2 45 | # 然后执行命令 46 | yarn start 47 | 48 | # 其他基础方式启动命令 49 | node index.js 50 | # 假如提示 80 端口不可用,尝试命令 51 | # windows 平台 CMD: 52 | # set PORT=8000 && node index.js 53 | # windows 平台 PowerShell: 54 | # $env:PORT="8000";node index.js 55 | # 其他平台: 56 | # PORT=8000 TZ=Asia/Shanghai node index.js 57 | ## TZ=Asia/Shanghai 用于设置程序运行时区 58 | ``` 59 | 60 | #### 升级 61 | 62 | 方式一:使用 [softupdate.js](https://raw.githubusercontent.com/elecV2/elecV2P/master/script/JSFile/softupdate.js) 软更新升级 63 | 64 | - 首先在 webUI/JSMANAGE 脚本管理中找到 softupdate.js 文件,假如不存在就远程推送或本地上传一下 65 | - 然后按照文件内的说明,根据自身需求更改 CONFIG 设置项 66 | - 最后点击测试运行即可 67 | 68 | 方式二:手动升级(不推荐 69 | 70 | - 先备份好个人数据,比如 根证书,以及 efss、script/JSFile、Store、Lists、Shell 等文件夹 71 | - (推荐在 webUI/efss 界面,右键对应文件夹,然后 zip 打包下载。) 72 | - 然后在项目目录下执行命令 git pull,拉取最新的代码进行覆盖升级 73 | - 最后再把备份好的文件上传/复制还原到之前的位置 74 | 75 | ### 其他 PM2 相关指令 76 | 77 | ``` sh 78 | pm2 stop elecV2P # 停止 elecV2P 79 | pm2 stop all # 停止所有程序 80 | 81 | pm2 restart elecV2P # 重启 elecV2P 82 | pm2 restart 0 83 | 84 | pm2 ls # 查看运行状态 85 | pm2 logs # 查看运行日志 86 | 87 | pm2 -h # 查看 PM2 帮助列表 88 | ``` 89 | 90 | ### 方法二:DOCKER 91 | 92 | 镜像名称: elecv2/elecv2p 93 | 镜像地址: https://hub.docker.com/r/elecv2/elecv2p 94 | 95 | ``` sh 96 | # 基础使用命令 97 | docker run --restart=always -d --name elecv2p -e TZ=Asia/Shanghai -p 80:80 -p 8001:8001 -p 8002:8002 elecv2/elecv2p 98 | 99 | # 推荐使用命令 100 | docker run --restart=always \ 101 | -d --name elecv2p \ 102 | -e TZ=Asia/Shanghai \ 103 | -p 8100:80 -p 8101:8001 -p 8102:8002 \ 104 | -v /elecv2p/JSFile:/usr/local/app/script/JSFile \ 105 | -v /elecv2p/Lists:/usr/local/app/script/Lists \ 106 | -v /elecv2p/Store:/usr/local/app/script/Store \ 107 | -v /elecv2p/Shell:/usr/local/app/script/Shell \ 108 | -v /elecv2p/rootCA:/usr/local/app/rootCA \ 109 | -v /elecv2p/efss:/usr/local/app/efss \ 110 | elecv2/elecv2p 111 | 112 | # -p/-v 对应参数 宿主:容器 113 | # 如需更改默认的 80 端口,可在 -e 后面加上 PORT=8000 114 | # 升级 Docker 镜像(如果没有使用 -v 持久化存储,容器内数据会丢失,请提前备份) 115 | docker rm -f elecv2p # 先删除旧的容器 116 | docker pull elecv2/elecv2p # 再拉取新的镜像 117 | # 再使用之前的 docker run xxxx 命令重新启动一下 118 | # 如果拉取到的镜像不是最新的版本,请修改 Docker 当前使用的仓库地址 119 | ``` 120 | 121 | - ARM32 平台如果出错,参考 [issues #78](https://github.com/elecV2/elecV2P/issues/78) 122 | 123 | ### 方法三:DOCKER-COMPOSE (推荐) 124 | 125 | ``` sh 126 | # 创建 elecV2P 持久化数据保存目录 127 | mkdir /elecv2p && cd /elecv2p 128 | # 假如失败,请尝试在其他有权限的目录进行创建 129 | # 后面 docker-compose.yaml 映射目录保持和创建的目录一致 130 | 131 | # 下载 docker-compose.yaml 文件 132 | curl -sL https://git.io/JLw7s > docker-compose.yaml 133 | # 启动运行 elecV2P 134 | docker-compose up -d 135 | 136 | # 注意: 需提前安装好 docker-compose 管理器 137 | # 默认将 80/8001/8002 端口分别映射到了宿主机的 8100/8101/8102 端口,以防出现占用的情况 138 | # 如果需要设置为其他端口,请自行修改 docker-compose.yaml 文件内容,然后重新启动 139 | ``` 140 | 141 | 以下为 docker-compose.yaml 文件内容,可根据自身需求进行修改。 142 | 143 | ``` yaml 144 | version: '3.7' 145 | services: 146 | elecv2p: 147 | image: elecv2/elecv2p 148 | container_name: elecv2p 149 | restart: always 150 | environment: 151 | - TZ=Asia/Shanghai 152 | ports: 153 | - "8100:80" 154 | - "8101:8001" 155 | - "8102:8002" 156 | volumes: 157 | - "/elecv2p/JSFile:/usr/local/app/script/JSFile" 158 | - "/elecv2p/Lists:/usr/local/app/script/Lists" 159 | - "/elecv2p/Store:/usr/local/app/script/Store" 160 | - "/elecv2p/Shell:/usr/local/app/script/Shell" 161 | - "/elecv2p/rootCA:/usr/local/app/rootCA" 162 | - "/elecv2p/efss:/usr/local/app/efss" 163 | ``` 164 | 165 | 修改后保存文件,然后在 docker-compose.yaml 文件所在目录下执行以下任一命令 166 | 167 | ``` sh 168 | # 直接启动(首次启动命令) 169 | docker-compose up -d 170 | 171 | # 更新镜像并重新启动 172 | docker-compose pull elecv2p && docker-compose up -d 173 | ``` 174 | 175 | - 如果在某些设备上无法启动,尝试把文件开头的 version: '3.7' 更改为 version: '3.3' 176 | - ARM32 平台如果出错,参考 [issues #78](https://github.com/elecV2/elecV2P/issues/78) 177 | 178 | 其他 docker 相关指令 179 | 180 | ``` sh 181 | # 查看是否启动及对应端口 182 | docker ps 183 | 184 | # 查看 elecV2P 运行日志 185 | docker logs elecv2p -f 186 | ``` 187 | 188 | ## 默认端口 189 | 190 | - 80: webUI 后台管理界面。用于添加规则/管理脚本/定时任务/MITM 证书 等 191 | - 8001: ANYPROXY HTTP 代理端口。(*代理端口不是网页,不能通过浏览器直接访问*) 192 | - 8002: ANYPROXY 代理请求查看端口 193 | 194 | **ANYPROXY 相关端口默认关闭。可在 webUI 首页双击 ANYPROXY 临时开启。** 195 | **如需在启动时自动开启,请前往 webUI->SETTING->初始化相关设置 中进行设置。** 196 | **80/8002 对应端口需要用到 websocket,在使用 nginx 等反代工具时注意设置。参考 [ev2p-nginx.conf](https://github.com/elecV2/elecV2P-dei/blob/master/examples/ev2p-nginx.conf)** 197 | 198 | - *80 端口可使用环境变量 **PORT** 进行修改(比如: PORT=8000 node index.js)* 199 | - *在 elecV2P 已经启动时,可在 webUI->SETTING->初始化相关设置 中修改其他端口* 200 | - *在 elecV2P 尚未启动时,可在 script/Lists/config.json 文件中修改对应端口* 201 | 202 | ## 根证书相关 - HTTPS 解密 203 | 204 | - *如果不使用 RULES/REWRITE 等 MITM 相关功能,此步骤可跳过。* 205 | - *升级启动后,如果不是使用之前的证书,需要重新下载安装信任根证书。* 206 | - *根证书包含两个文件 rootCA.crt/rootCA.key,文件名不可修改。* 207 | 208 | ### 安装证书 209 | 210 | 选择以下任意一种方式下载证书,然后安装并信任 211 | 212 | - 直接打开 :80/crt 213 | - :80 -> MITM -> 安装证书 214 | - :8002 -> RootCA 215 | 216 | 根证书物理存储目录位于 `$HOME/.anyproxy/certificates`。 217 | 218 | *windows 平台的证书存储位置选择 浏览->受信任的根证书颁发机构* 219 | 220 | ### 使用自签根证书 221 | 222 | 在 webUI->MITM 界面上传自签根证书,然后重启 elecV2P 223 | 224 | **注意:使用新的证书后,记得重新下载安装信任证书,并清除由之前根证书签发的域名证书。** 225 | 226 | ## RULES - 网络请求修改 227 | 228 | ![rules](https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/docs/res/rules.png) 229 | 230 | 详细说明参考: [docs/03-rules.md](https://github.com/elecV2/elecV2P-dei/tree/master/docs/03-rules.md) 231 | 232 | ## 定时任务 233 | 234 | ![task](https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/docs/res/taskall.png) 235 | 236 | 支持两种定时方式: 237 | 238 | - 倒计时 239 | - cron 定时 240 | 241 | ### 时间格式: 242 | 243 | - 倒计时 30 999 3 2 (以空格分开的四个数字,后三项可省略) 244 | 245 | | 30(秒) | 999(次) | 3(秒) | 2(次) 246 | :--------------: | :-------------: | :------------------: | :------------------: 247 | | 基础倒计时时间 | 重复次数(可选)| 增加随机时间(可选) | 增加随机重复次数(可选) 248 | 249 | 250 | - *当重复次数大于等于 **999** 时,无限循环* 251 | 252 | 示例: 40 8 10 3 ,表示倒计时40秒,随机10秒,所以具体倒计时时间位于 40-50 秒之间,重复运行 8-11 次 253 | 254 | - cron 定时 255 | 256 | 时间格式:* * * * * * (五/六位 cron 时间格式) 257 | 258 | | * (0-59) | * (0-59) | * (0-23) | * (1-31) | * (1-12) | * (0-7) 259 | :----------: | :--------: | :--------: | :--------: | :--------: | :---------: 260 | | 秒(可选) | 分 | 小时 | 日 | 月 | 星期 261 | 262 | 263 | ### 可执行任务类型 264 | 265 | - 运行 JS 266 | - 开始/停止 其他定时任务 267 | - 基础 shell 指令。比如 *rm -f \**, *python test.py*, *reboot* 等等 268 | 269 | 更多说明参考:[docs/06-task.md](https://github.com/elecV2/elecV2P-dei/tree/master/docs/06-task.md) 270 | 271 | ## 通知 272 | 273 | 目前支持通知方式: 274 | - FEED/RSS 订阅 275 | - IFTTT WEBHOOK 276 | - BARK 通知 277 | - 自定义通知 278 | 279 | FEED/RSS 订阅地址为 webUI/feed。 280 | 281 | 通知内容: 282 | - 定时任务开始/结束 283 | - 定时任务 JS 运行次数 284 | - 脚本中的自主调用通知 285 | 286 | IFTTT/BARK/自定义通知等相关设置参考: [07-feed¬ify](https://github.com/elecV2/elecV2P-dei/tree/master/docs/07-feed¬ify.md) 287 | 288 | ## DOCUMENTS&EXAMPLES 289 | 290 | 说明文档及一些例程: [https://github.com/elecV2/elecV2P-dei](https://github.com/elecV2/elecV2P-dei) 291 | 292 | 如果遇到问题欢迎 [open a issue](https://github.com/elecV2/elecV2P/issues)。尽量说明使用平台,版本,以及附上相关的错误日志(提供的信息越详细,越有助于解决问题)。 293 | 294 | TG 频道: https://t.me/elecV2 295 | TG 交流群: https://t.me/elecV2G 296 | 297 | ## 更新日志 298 | 299 | 查看: https://github.com/elecV2/elecV2P/blob/master/logs/update.log 300 | 301 | ## 贡献参考 302 | 303 | - [anyproxy](https://github.com/alibaba/anyproxy) 304 | - [axios](https://github.com/axios/axios) 305 | - [expressjs](https://expressjs.com) 306 | - [node-cron](https://github.com/merencia/node-cron) 307 | - [node-rss](https://github.com/dylang/node-rss) 308 | - [pm2](https://pm2.keymetrics.io) 309 | - [vue](https://vuejs.org) 310 | - [vue-draggable-resizable](https://github.com/mauricius/vue-draggable-resizable) 311 | - [ace](https://github.com/ajaxorg/ace) 312 | - [adm-zip](https://github.com/cthackers/adm-zip) 313 | - [Ant Design Vue](https://www.antdv.com) 314 | 315 | ### 说明文档列表 316 | 317 | - [overview - 简介及安装](01-overview.md) 318 | - [task - 定时任务](06-task.md) 319 | - [rewrite - 重写网络请求](05-rewrite.md) 320 | - [rules - 网络请求更改规则](03-rules.md) 321 | - [script - 脚本编写及说明](04-JS.md) 322 | - [Docker - Docker 运行相关](02-Docker.md) 323 | - [feed¬ify - 通知相关](07-feed¬ify.md) 324 | - [logger&efss - 日志和 EFSS 文件管理](08-logger&efss.md) 325 | - [webhook - webhook 使用简介](09-webhook.md) 326 | - [config - 配置文件说明](10-config.md) 327 | - [Advanced - 高级使用篇](Advanced.md) 328 | -------------------------------------------------------------------------------- /docs/02-Docker.md: -------------------------------------------------------------------------------- 1 | ``` 2 | 最近更新: 2022-03-15 3 | 适用版本: 3.6.3 4 | 文档地址: https://github.com/elecV2/elecV2P-dei/blob/master/docs/02-Docker.md 5 | ``` 6 | 7 | ## 简介 8 | 9 | Docker 镜像名称: elecv2/elecv2p 10 | Docker 镜像地址: https://hub.docker.com/r/elecv2/elecv2p 11 | 12 | ## docker 及 docker-compose 的安装 13 | 14 | ``` sh 15 | # 不同平台的安装方式可能不一样,仅供参考 16 | # docker 安装 17 | wget -qO- https://get.docker.com/ | sh 18 | 19 | # docker-compose 安装。(前往 https://github.com/docker/compose/releases 查看适合自己设备的版本) 20 | curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 21 | ``` 22 | 23 | ## Docker 运行 elecV2P 24 | 25 | *以下命令仅供参考,具体映射端口和卷根据实际情况进行调整* 26 | 27 | ```sh 28 | # 基础启动命令(重建后数据会丢失) 29 | docker run --restart=always -d --name elecv2p -e TZ=Asia/Shanghai -p 80:80 -p 8001:8001 -p 8002:8002 elecv2/elecv2p 30 | 31 | # 推荐使用命令 32 | docker run --restart=always \ 33 | -d --name elecv2p \ 34 | -e TZ=Asia/Shanghai \ 35 | -p 8100:80 -p 8101:8001 -p 8102:8002 \ 36 | -v /elecv2p/JSFile:/usr/local/app/script/JSFile \ 37 | -v /elecv2p/Lists:/usr/local/app/script/Lists \ 38 | -v /elecv2p/Store:/usr/local/app/script/Store \ 39 | -v /elecv2p/Shell:/usr/local/app/script/Shell \ 40 | -v /elecv2p/rootCA:/usr/local/app/rootCA \ 41 | -v /elecv2p/efss:/usr/local/app/efss \ 42 | elecv2/elecv2p 43 | 44 | # -p/-v 对应环境参数 宿主参数:容器内参数 45 | # 宿主机映射目录尽量填写尚未创建或空的文件夹 46 | # 如需更改默认的 80 端口,可在 -e 后面加上 PORT=8000 47 | # 某些设备上,可能无法在根目录创建 elecv2p 文件夹,这时请根据使用设备搜索可操作的目录,进行替换 48 | # 如果在部分复杂的网络情况下出现无法联网或访问的问题,尝试在命令中添加 --net=host 49 | 50 | # 查看 docker 运行状态 51 | docker ps 52 | 53 | # 进入容器内部 54 | docker exec -it elecv2p /bin/sh 55 | 56 | # Docker 的启动暂停 57 | docker start elecv2p 58 | docker stop elecv2p 59 | docker restart elecv2p 60 | 61 | # 查看 Docker 运行日志 62 | docker logs elecv2p -f 63 | docker logs elecv2p --tail 20 64 | 65 | # 清除 Docker 运行日志 66 | echo "" > $(docker inspect --format='{{.LogPath}}' elecv2p) 67 | 68 | # 升级容器 69 | # 先移除容器 70 | docker rm -f elecv2p 71 | # 再拉取最新的镜像 72 | docker pull elecv2/elecv2p 73 | # 最后再使用上面的 docker run 命令重新启动 74 | ``` 75 | 76 | ## docker-compose 启动 77 | 78 | ``` sh 79 | mkdir /elecv2p && cd /elecv2p 80 | curl -sL https://git.io/JLw7s > docker-compose.yaml 81 | 82 | docker-compose up -d 83 | 84 | # 默认把 80/8001/8002 端口分别映射成了 8100/8101/8102,以防出现端口占用的情况,访问时注意 85 | # 如果需要设置为其他端口,可以自行修改下面的内容然后手动保存 86 | ``` 87 | 88 | 或者将以下内容手动保存为 docker-compose.yaml 文件。 89 | 90 | ``` yaml 91 | version: '3.7' 92 | services: 93 | elecv2p: 94 | image: elecv2/elecv2p 95 | container_name: elecv2p 96 | restart: always 97 | environment: 98 | - TZ=Asia/Shanghai 99 | ports: 100 | - "8100:80" 101 | - "8101:8001" 102 | - "8102:8002" 103 | volumes: 104 | - "/elecv2p/JSFile:/usr/local/app/script/JSFile" 105 | - "/elecv2p/Lists:/usr/local/app/script/Lists" 106 | - "/elecv2p/Store:/usr/local/app/script/Store" 107 | - "/elecv2p/Shell:/usr/local/app/script/Shell" 108 | - "/elecv2p/rootCA:/usr/local/app/rootCA" 109 | - "/elecv2p/efss:/usr/local/app/efss" 110 | ``` 111 | 112 | - *具体使用的映射端口和 volumes 目录,根据个人情况进行调整* 113 | - *如需更改默认的 80 端口,在 environment 下添加一行: - PORT=8000* 114 | - *如果在某些设备上无法启动,尝试把文件开头的 version: '3.7' 更改为 version: '3.3'* 115 | 116 | 然后在 docker-compose.yaml 同目录执行命令 **docker-compose up -d** ,启动程序。 117 | 118 | ### env 默认环境变量 119 | 120 | 在 elecV2P 启动前,可设置部分环境变量 121 | 122 | - TZ: 时区设置 timezone 123 | - PORT: webUI 对应端口,默认为 80 124 | - TOKEN: 启动时指定 WEBHOOK TOKEN 125 | 126 | 使用示例: 127 | 128 | ``` sh 129 | docker run --restart=always \ 130 | -d --name elecv2p \ 131 | -e TZ=Asia/Shanghai PORT=8000 TOKEN=YOUR-WEBHOOK-TOKEN \ 132 | -p 8100:8000 -p 8101:8001 -p 8102:8002 \ 133 | -v /elecv2p/JSFile:/usr/local/app/script/JSFile \ 134 | -v /elecv2p/Lists:/usr/local/app/script/Lists \ 135 | -v /elecv2p/Store:/usr/local/app/script/Store \ 136 | -v /elecv2p/Shell:/usr/local/app/script/Shell \ 137 | -v /elecv2p/rootCA:/usr/local/app/rootCA \ 138 | -v /elecv2p/efss:/usr/local/app/efss \ 139 | elecv2/elecv2p 140 | ``` 141 | 142 | 环境变量可以同时设置部分或全部 143 | 144 | **在 docker-compose 中 env 对应 environment** 145 | 146 | ### 其他指令 147 | 148 | ``` sh 149 | # 更新升级 150 | docker-compose pull elecv2p && docker-compose up -d 151 | 152 | # 拉取特定版本的镜像文件。可用版本以 https://hub.docker.com/r/elecv2/elecv2p 的 tag 为准 153 | docker pull elecv2/elecv2p:3.4.5 154 | docker pull elecv2/elecv2p:arm64-3.0 # 在使用这些特定版本的镜像时,docker run 后面的镜像名也要记得调整 155 | 156 | docker image prune # 清除没有挂载的镜像文件 157 | 158 | # 查看运行日志 159 | docker logs elecv2p -f 160 | ``` 161 | 162 | ### 一些说明 163 | 164 | - 当使用国内的一些 docker 源,因为缓存问题,更新之后可能不是最新的版本,需要手动更换一下 docker 源。(具体步骤谷歌) 165 | - arm32 平台如果出错,参考 [issues #78](https://github.com/elecV2/elecV2P/issues/78) 166 | 167 | ### 说明文档列表 168 | 169 | - [overview - 简介及安装](01-overview.md) 170 | - [task - 定时任务](06-task.md) 171 | - [rewrite - 重写网络请求](05-rewrite.md) 172 | - [rules - 网络请求更改规则](03-rules.md) 173 | - [script - 脚本编写及说明](04-JS.md) 174 | - [Docker - Docker 运行相关](02-Docker.md) 175 | - [feed¬ify - 通知相关](07-feed¬ify.md) 176 | - [logger&efss - 日志和 EFSS 文件管理](08-logger&efss.md) 177 | - [webhook - webhook 使用简介](09-webhook.md) 178 | - [config - 配置文件说明](10-config.md) 179 | - [Advanced - 高级使用篇](Advanced.md) 180 | -------------------------------------------------------------------------------- /docs/03-rules.md: -------------------------------------------------------------------------------- 1 | ``` 2 | 最近更新: 2022-03-24 3 | 适用版本: 3.7.8 4 | 文档地址: https://github.com/elecV2/elecV2P-dei/blob/master/docs/03-rules.md 5 | ``` 6 | 7 | ## 准备工作 8 | 9 | - **再使用 RULES/REWRITE 相关功能前,请确定 ANYPROXY 已打开** 10 | - 已正确将网络请求代理到 ANYPROXY 端口 11 | - 匹配 https 请求请先添加 MITM host,普通 http 请求无需添加 12 | - *首次命中 https 请求时,系统需要生成中间证书,可能会稍长一点时间返回结果* 13 | 14 | ## modify 规则集 格式说明 15 | 16 | | 匹配方式 | 匹配内容(正则) | 修改方式 | 修改目标 | 修改时间点 17 | :-----------: | --------------------- | :-------: | ------------------- | ---------- 18 | | url | ^https://api.b.com/v2 | JS | file.js | 前(req) 19 | | host | api.bilibili.com | useragent | iPhone 6s | 后(res) 20 | | useragent | neteaseMusic / aliApp | block | reject|tinyimg | 21 | | reqmethod | GET/POST/PUT/DELETE | $HOLD | 30 22 | | reqbody | queryPara/word string | | 23 | | resstatus | 200 / 404 / 301 / ... | | 24 | | restype | text/html / text/json | ----- | 25 | | resbody | Keyword(string) | all - JS | 26 | 27 | - *实际使用中匹配方式和修改方式可以任意搭配* 28 | 29 | ### 匹配方式 30 | 31 | ``` 32 | url // 匹配 url 33 | host // 匹配 url host 部分 34 | useragent // 匹配 User-Agent 35 | reqmethod // 匹配 网络请求方式 36 | reqbody // 匹配 请求体(body) 37 | resstatus // 匹配 请求返回的状态码 38 | restype // 匹配 返回的数据类型 39 | resbody // 匹配 返回的数据内容 40 | ``` 41 | 42 | - **v3.7.8 默认不再对 reqbody/resbody 内容进行匹配,以提升 elecV2P MITM 效率。如需开启,请参考下文源文件格式部分,增加属性项 "enbody": true。(不匹配不代表不可以修改,仍然可以通过 url/host 等方式进行匹配,然后使用脚本对 body 内容进行修改)** 43 | 44 | ### 修改方式 45 | 46 | #### JS 47 | 48 | 通过 JS 脚本修改网络请求数据,对应修改内容为 JS 文件名或远程 JS 链接。 49 | 50 | 从该模块运行 JS,默认会添加 $request,$response(**数据返回前**) 两个变量,具体参数如下: 51 | 52 | - $request.headers, $request.body, $request.method, $request.hostname, $request.port, $request.path, $request.url 53 | - $response.headers, $response.body, $response.statusCode 54 | 55 | #### 307 重定向 56 | 57 | 对应修改内容为重定向目标网址 58 | 59 | #### 阻止 60 | 61 | reject: 返回状态码 200, body 为空。 62 | tinyimg: 返回状态码为 200, body 为一张 1x1 的图片 63 | 64 | #### $HOLD 65 | 66 | 将原网络请求的 header 和 body 发送到前端网页进行修改处理,然后将修改后的数据直接发送给服务器/客户端。 67 | 68 | 对应修改内容表示等待前端修改数据的时间,单位秒。当为 **0** 时,表示一直等待。如果为其他值且超时时则直接使用原数据进行下步操作。 69 | 70 | 使用该修改方式时,请尽量使用比较详细的匹配规则,匹配单一网络请求,否则后面的 $HOLD 请求会覆盖前面的数据。 71 | 72 | **2020.7.16 2.1.0 更新** 73 | 74 | $HOLD request reject - 直接返回当前数据 75 | 76 | 返回默认状态码: 200 77 | 78 | 数据包含两部分: header 和 body 79 | 80 | #### User-Agent 81 | 82 | 修改请求 header 中的 User-Agent。 83 | 84 | 默认 User-Agent 可在 webUI->SETTING->网络请求相关设置进行管理修改 85 | 86 | ### 修改时间 87 | 88 | 网络请求匹配时间 89 | 90 | #### 网络请求前 91 | 92 | beforeSendRequest 93 | 94 | #### 数据返回前 95 | 96 | beforeSendResponse 97 | 98 | ## 源文件格式 99 | 100 | RULES 规则列表保存于 **./script/Lists/default.list**,实际格式为严格的 JSON 类型(不包含任何注释)。 101 | *(参考: https://raw.githubusercontent.com/elecV2/elecV2P/master/script/Lists/default.list )* 102 | 103 | ``` JSON 104 | { 105 | "rules": { 106 | "note": "elecV2P RULES 规则列表", 107 | "enable": false, // 是否启用下面列表中的规则,仅在该值为 false 时,表示不启用,默认启用 108 | "enbody": false, // 是否对请求体(body)进行匹配,仅在该值为 true 时,表示启用(v3.7.8 添加,默认不启用 109 | "list": [ 110 | { 111 | "mtype": "url", 112 | "match": "adtest", 113 | "ctype": "block", 114 | "target": "reject", 115 | "stage": "req" 116 | }, 117 | { 118 | "mtype": "url", 119 | "match": "httpbin.org/get\\?hold", 120 | "ctype": "hold", 121 | "target": "0", 122 | "stage": "req", // enable 可省略。仅在 enable 为 false 的时候表示不启用 123 | "enable": true 124 | } 125 | ] 126 | } 127 | } 128 | ``` 129 | 130 | *如非必要,请不要手动修改 list 源文件* 131 | 132 | ### 说明文档列表 133 | 134 | - [overview - 简介及安装](01-overview.md) 135 | - [task - 定时任务](06-task.md) 136 | - [rewrite - 重写网络请求](05-rewrite.md) 137 | - [rules - 网络请求更改规则](03-rules.md) 138 | - [script - 脚本编写及说明](04-JS.md) 139 | - [Docker - Docker 运行相关](02-Docker.md) 140 | - [feed¬ify - 通知相关](07-feed¬ify.md) 141 | - [logger&efss - 日志和 EFSS 文件管理](08-logger&efss.md) 142 | - [webhook - webhook 使用简介](09-webhook.md) 143 | - [config - 配置文件说明](10-config.md) 144 | - [Advanced - 高级使用篇](Advanced.md) 145 | -------------------------------------------------------------------------------- /docs/05-rewrite.md: -------------------------------------------------------------------------------- 1 | ``` 2 | 最近更新: 2021-10-16 3 | 适用版本: 3.5.0 4 | 文档地址: https://github.com/elecV2/elecV2P-dei/blob/master/docs/05-rewrite.md 5 | ``` 6 | 7 | ## 简述 8 | 9 | 在 elecV2P 中,REWRITE 规则是 RULES 规则特定项的简化版本,匹配效率较高,建议在可使用 REWRITE 的情况下,关闭 RULES 规则集。 10 | 11 | ## webUI 相关说明 12 | 13 | ![rewrite](https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/docs/res/rewritenote.png) 14 | 15 | - REWRITE 规则的匹配对象为网络请求的 URL,如果是 https 请求,请在 MITM host 中添加对应的解析域名。 16 | - *具体的匹配公式: `(new RegExp('匹配链接正则表达式')).test($request.url)`。* 17 | 18 | v3.5.0 添加 **匹配阶段** 选项 19 | - 网络请求前,用于修改网络请求体 request headers/body 等 20 | - 数据返回前,用于修改获取到的内容 response headers/body 等 21 | 22 | - 当规则对应重写方式为 (reject|reject-200|reject-dict|reject-json|reject-array|reject-img) 中的某个参数时,表示阻止该网络请求(直接返回相应内容) 23 | - 当规则对应重写方式为脚本时,表示在通过该脚本修改该网络请求或返回内容 24 | - 脚本编写参考说明文档 [04-JS.md](https://github.com/elecV2/elecV2P-dei/blob/master/docs/04-JS.md) 或 示例脚本 [0body.js](https://raw.githubusercontent.com/elecV2/elecV2P/master/script/JSFile/0body.js) 25 | 26 | - 订阅链接必须以 http 或 efss 开头,具体订阅内容参考下面的 **订阅内容格式** 部分 27 | - http: 表示订阅为远程地址,比如: https://raw.githubusercontent.com/elecV2/elecV2P/master/efss/rewritesub.json 28 | - efss: 表示直接读取服务器上 EFSS 虚拟目录中的文件,比如 efss/rewritesub.json 29 | 30 | - 删除订阅时并不会删除已添加的 MITMHOST 和 TASK 31 | - 所有规则的更改在保存后才正式生效 32 | 33 | ## 源文件格式 34 | 35 | REWRITE 规则列表保存于 **./script/Lists/rewrite.list**,实际格式为严格的 JSON 类型(不包含任何注释)。 36 | *(参考: https://raw.githubusercontent.com/elecV2/elecV2P/master/script/Lists/rewrite.list )* 37 | 38 | ``` JSON 39 | { 40 | "rewritesub": { // 订阅列表 41 | "eSubUuid": { 42 | "name": "elecV2P 重写订阅", 43 | "resource": "https://raw.githubusercontent.com/elecV2/elecV2P/master/efss/rewritesub.json" 44 | } 45 | }, 46 | "rewrite": { // 规则列表 47 | "note": "elecV2P 重写规则", // 关于规则列表的注释。可省略 48 | "list": [ // 具体规则 49 | { 50 | "match": "^https?://httpbin\\.org/get\\?rewrite=elecV2P", // 网络请求 url 匹配 51 | "stage": "res", // 匹配阶段。req: 网络请求前 res: 数据返回前。 v3.5.0 添加 52 | "target": "https://raw.githubusercontent.com/elecV2/elecV2P/master/script/JSFile/0body.js", // 匹配后使用的脚本文件 53 | "enable": true 54 | } 55 | ] 56 | } 57 | } 58 | ``` 59 | 60 | *如非必要,请不要手动修改 list 源文件* 61 | 62 | ## 订阅内容格式 63 | 64 | 订阅内容同样为严格的 JSON 类型,不包含任何注释。参考: https://raw.githubusercontent.com/elecV2/elecV2P/master/efss/rewritesub.json 65 | 66 | ``` JSON 67 | { 68 | "name": "elecV2P 重写订阅", // 订阅名称。可省略 69 | "resource": "https://raw.githubusercontent.com/elecV2/elecV2P/master/efss/rewritesub.json", // 该订阅的更新地址。可省略 70 | "type": "rewrite", // 订阅类型,固定为 rewrite。用于区分 task 订阅,可省略 71 | "note": "关于该订阅的一些说明(可省略)。该订阅目前仅适用于 elecV2P,与其他软件并不兼容。更详细说明请查看: https://github.com/elecV2/elecV2P-dei/tree/master/docs/05-rewrite.md", 72 | "author": "https://t.me/elecV2", // 制作者。可省略 73 | "bkcolor": "#2fa885", // 该订阅背景颜色。当省略时,将随机生成。可使用 url(http://xxxx.jpg) 74 | "mitmhost": [ // 和重写规则相关的 mitmhost。可省略。 75 | "test.com", "httpbin.org" 76 | ], 77 | "list": [ // 重写规则列表 78 | { 79 | "match": "https:\\/\\/test\\.com\\/block", // url 匹配正则表达式 80 | "stage": "req", // 匹配阶段。req: 网络请求前 res: 数据返回前。 v3.5.0 添加 81 | "target": "reject-json", // 阻止网络请求,并返回默认的 json 数据 82 | "enable": true 83 | }, 84 | { 85 | "match": "https:\\/\\/httpbin\\.org", // enable 可省略。如只添加不启用,则设置 enable: false 86 | "stage": "res", 87 | "target": "https://raw.githubusercontent.com/elecV2/elecV2P/master/script/JSFile/exam-cheerio.js" 88 | } 89 | ], 90 | "task": { // 同时添加定时任务(可省略) 91 | "type": "skip", // 当任务列表中包含同名任务时,新任务的添加方式。skip: 跳过, addition: 新增, replace: 替换(默认,如省略) 92 | "list": [ // 任务列表,具体格式参考: https://github.com/elecV2/elecV2P-dei/tree/master/docs/06-task.md 订阅 list 相关部分 93 | { 94 | "name": "REWRITE 订阅添加的任务", 95 | "type": "cron", 96 | "time": "30 0 0 * * *", 97 | "job": { 98 | "type": "runjs", 99 | "target": "https://raw.githubusercontent.com/elecV2/elecV2P/master/script/JSFile/test.js" 100 | } 101 | } 102 | ] 103 | } 104 | } 105 | ``` 106 | 107 | *反引号"\" 为转义字符,实际保存/读取时会自动转义一次,请不要直接在订阅文件中进行复制,然后粘贴到 webUI 中。* 108 | 109 | ### 其他说明 110 | 111 | - *REWRITE 列表的优先级高于 RULES 规则列表。* 112 | - *规则订阅对其他软件的订阅格式有一定的兼容性,但并不保证完全适配。* 113 | - *首次命中 https 请求时,系统会自动签发一张中间证书,可能需要稍长一点时间。* 114 | - *推荐文章: [elecV2P 进阶使用之抓包及 COOKIE 获取](https://elecv2.github.io/#elecV2P%20%E8%BF%9B%E9%98%B6%E4%BD%BF%E7%94%A8%E4%B9%8B%E6%8A%93%E5%8C%85%E5%8F%8A%20COOKIE%20%E8%8E%B7%E5%8F%96)* 115 | 116 | ### 说明文档列表 117 | 118 | - [overview - 简介及安装](01-overview.md) 119 | - [task - 定时任务](06-task.md) 120 | - [rewrite - 重写网络请求](05-rewrite.md) 121 | - [rules - 网络请求更改规则](03-rules.md) 122 | - [script - 脚本编写及说明](04-JS.md) 123 | - [Docker - Docker 运行相关](02-Docker.md) 124 | - [feed¬ify - 通知相关](07-feed¬ify.md) 125 | - [logger&efss - 日志和 EFSS 文件管理](08-logger&efss.md) 126 | - [webhook - webhook 使用简介](09-webhook.md) 127 | - [config - 配置文件说明](10-config.md) 128 | - [Advanced - 高级使用篇](Advanced.md) 129 | -------------------------------------------------------------------------------- /docs/06-task.md: -------------------------------------------------------------------------------- 1 | ``` 2 | 最近更新: 2022-02-08 3 | 适用版本: 3.6.0 4 | 文档地址: https://github.com/elecV2/elecV2P-dei/blob/master/docs/06-task.md 5 | ``` 6 | 7 | ![task](https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/docs/res/taskall.png) 8 | 9 | ### 时间格式 10 | 11 | - 倒计时 30 999 3 2 (以空格分开的四个数字,后三项可省略) 12 | 13 | | 30(秒) | 999(次) | 3(秒) | 2(次) 14 | : --------------: | :--------------: | :------------------: | :------------------: 15 | | 基础倒计时时间 | 重复次数(可选)| 增加随机时间(可选) | 增加随机重复次数(可选) 16 | 17 | *当重复次数大于等于 **999** 时,无限循环。* 18 | 19 | 示例: 400 8 10 3 ,表示倒计时40秒,随机10秒,所以具体倒计时时间位于 40-50 秒之间,重复运行 8-11 次 20 | 21 | - cron 定时 22 | 23 | 时间格式: * * * * * * (五/六位 cron 时间格式) 24 | 25 | | * (0-59) | * (0-59) | * (0-23) | * (1-31) | * (1-12) | * (0-7) 26 | :----------: | :--------: | :--------: | :--------: | :--------: | :---------: 27 | | 秒(可选) | 分 | 小时 | 日 | 月 | 星期 28 | 29 | 30 | ## 可执行任务类型 31 | 32 | - 运行 JS: runjs 33 | - Shell 指令: exec 34 | - 开始任务: taskstart 35 | - 停止任务: taskstop 36 | 37 | ### 运行 JS 38 | 39 | 支持本地 JS, 及远程 JS。 40 | 本地 JS 文件位于 script/JSFile 目录,可在 webUI->JSMANAGE 中查看。设置定时任务时,直接复制文件名到任务栏对应框即可。 41 | 42 | 如使用远程 JS,则直接在任务栏对应框内输入以 **http 或 https** 开头的网络地址。远程 JS 默认更新时间为 86400 秒(一天),可在 webUI->SETTING 界面修改。超过此时间,则会先下载最新的 JS 文件,然后再执行。如果下载失败,会继续尝试执行本地 JS 文件。 43 | 44 | *所以在执行需要特别准时的任务时,不建议使用远程 JS。或者提前手动更新一下,也可以设置一个稍微提前一点的定时任务提前下载好最新的 JS 文件,避免执行任务时先下载文件带来的延迟。* 45 | 46 | *此模式下的脚本运行在 vm 虚拟环境中,如果想要以原生的 nodejs 环境运行脚本,请选择 **shell 指令** 模式,然后填写 node xxx.js。(关于两者的区别,参考 [04-JS.md](https://github.com/elecV2/elecV2P-dei/blob/master/docs/04-JS.md) 相关部分)* 47 | 48 | 定时任务运行 JS 还支持附带 env 临时变量, 使用 **-env** 关键字进行声明,然后在 JS 文件中使用 **$env[变量名]** 的方式进行读取。例如: **exam-js-env.js -env name=一个名字 cookie=acookiestring** 49 | 50 | ``` JS exam-js-env.js 51 | // exam-js-env.js 文件内容 52 | let name = $env.name || 'elecV2P' 53 | console.log('hello', name) 54 | 55 | if ($env.cookie) { 56 | console.log('a cookie from task env', $env.cookie) 57 | } 58 | // 如果变量值包含空格等特殊字符,先使用 encodeURI 进行编码 59 | // 比如: command.js -env cmd=pm2%20ls 60 | ``` 61 | 62 | - v3.2.8 增加 -local 关键字,用于优先使用本地文件(如果存在),忽略默认更新时间间隔 63 | 64 | 具体使用: 65 | 66 | | 运行 JS | https://raw.githubusercontent.com/elecV2/elecV2P/master/script/JSFile/test.js -local 67 | 68 | 如果本地存在 test.js 文件,则直接运行,否则,下载远程文件后再运行 69 | 70 | - v3.3.1 增加 -rename 关键字,用于重命名文件(支持重命名远程和本地文件) 71 | 72 | | 运行 JS | notify.js -rename feed.js 73 | | 运行 JS | https://raw.githubusercontent.com/elecV2/elecV2P/master/script/JSFile/test.js -local -rename=t.js 74 | 75 | *使用 -rename 参数运行每次都会重新写入文件内容,建议不要在运行频率较高的任务中使用* 76 | 77 | - v3.4.5 增加 -grant 关键字,用于指定脚本增强功能。 78 | 79 | 可设置值 require/nodejs/quiet/sudo 等,多个值用英文竖线符(|)隔开。比如: 80 | 81 | | 运行 JS | requirex.js -grant=nodejs 82 | | 运行 JS | test.js -grant require|sudo 83 | 84 | *grant 后面接一个等号(=)或空格( )* 85 | *关于 grant 的功能,参考 [04-JS.md](https://github.com/elecV2/elecV2P-dei/blob/master/docs/04-JS.md) @grant 相关部分* 86 | 87 | ### Shell 指令 88 | 89 | *Shell 指令的运行基于 nodejs 的 [child_process_exec](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback) 模块* 90 | 91 | timeout 默认为 60000ms(60秒)。如果要执行长时间命令,在 JS 中使用 $exec() 执行,将 timeout 设置为 0 (表示不设定超过时间),或其他数值。 92 | **v3.4.1 更新: 可使用 -timeout=xx 参数来设置 timeout 时间。xx 为数字,单位 ms(省略不写)。比如: ls -timeout=2** 93 | 94 | cwd 默认目录为 script/Shell 95 | **v3.4.1 更新: 当使用 node 命令并且没有指定 cwd 时,默认 cwd 为 script/JSFile** 96 | 97 | ``` sh 示例命令 98 | # 单条命令 99 | ls 100 | node -v 101 | start https://github.com/elecV2/elecV2P 102 | reboot 103 | 104 | # 文件执行(先将相关文件放置到 script/Shell 目录下) 105 | hello.sh 106 | python3 -u test.py 107 | binaryfile 108 | # 以上文件会通过系统默认程序打开,请先安装好对应执行环境,以及注意文件的执行权限 109 | # 文件可通过 EFSS 界面上传至相关目录 110 | 111 | # 其他一些指令,仅供参考,谨慎使用(设置倒计时为 0,在需要时运行一次即可) 112 | echo {} > task.list -cwd script/Lists # 清空任务列表,重启后生效 113 | pm2 restart elecV2P # 重启 elecV2P 114 | apk add git # 使用 apk 安装一些常用包 115 | git clone https://github.com/xxxx/xxxx -cwd script/JSFile # 使用 git 命令 clone 远程库到 script/JSFile 目录 116 | ``` 117 | 118 | **v3.2.6 更新增加 -env/-cwd 变量** (*v2.3.4 版本到 v3.2.5版本,使用关键字是 -e/-c,为避免和其他命令冲突,v3.2.6 修改为 **-env/-cwd***) 119 | 可通过 **-cwd/-env** 关键字更改工作目录和环境变量,比如: 120 | 121 | ``` sh 122 | sh hello.sh -env name=Polo 123 | # 如果要传递比较复杂的环境变量,比如带有空格=-%*等特殊符合,建议在 JS 使用 $exec 函数来完成。具体参考说明文档 04-JS.md $exec 相关部分 124 | 125 | ls -cwd script/JSFile 126 | 127 | # 当使用 node 命令,且没有设置 cwd 时,默认 cwd 为 script/JSFile (v3.4.1) 128 | node requirex.js 129 | # 注意: 使用 node 命令执行的 JS,必须为原生 JS,即不包含 elecV2P 附加的 $axios/$feed/$store 等函数变量。 130 | # 如果既想使用 node 命令执行 JS,又想使用 $feed/$store 等函数,可在 JS 中使用 $exec('node xxxx.js') 来执行。具体参考说明文档 04-JS.md $exec 相关部分 131 | ``` 132 | 133 | **v3.2.7 增加 -stdin 变量,用于延迟输入交互指令** 134 | 135 | ``` sh 136 | askinput.py -stdin elecV2P%0Afine,%20thank%20you 137 | # -stdin 后面的文字如果较复杂,应先使用 encodeURI 函数进行简单编码 138 | # 默认延时时间为 2000ms (2秒),即在 2 秒后自动输入 stdin 后面的文字 139 | # 更多说明参考: 04-JS.md $exec 相关部分 140 | ``` 141 | 142 | **v3.2.8 增加支持运行远程文件** 143 | 144 | ``` sh 145 | python -u https://raw.githubusercontent.com/elecV2/elecV2P/master/script/Shell/test.py 146 | 147 | sh https://raw.githubusercontent.com/elecV2/elecV2P/master/script/Shell/hello.sh 148 | 149 | # 如果原来的命令中带有 http 链接,需使用 -http 进行转义 150 | echo -http://127.0.0.1/efss/readme.md 151 | # 也可以通知添加引号来避免这种问题 152 | echo 'https://github.com/elecV2/elecV2P-dei/tree/master/docs/06-task.md' 153 | 154 | # 假如没有转义,直接使用命令 155 | echo http://127.0.0.1/efss/readme.md 156 | # elecV2P 将会尝试先下载 http://127.0.0.1/efss/readme.md 文件到 script/Shell 目录,然后使用下载完成后的文件地址替换远程链接,所以最终输出结果可能是: /xxxx/xxxx/script/Shell/readme.md 157 | # (v3.4.2 echo 无需转义,按原样输出) 158 | 159 | # 部分常用网络命令已排除下载,比如: curl/wget/git/start/you-get/youtube-dl 开头命令 160 | curl https://www.google.com/ 161 | ``` 162 | 163 | - 远程文件默认下载目录为 **script/Shell** 164 | - 远程文件执行时默认每次都会重新下载 165 | - 如果远程文件下载失败将会尝试运行本地文件 166 | - 可使用 \-local 关键字优先使用本地文件 167 | 168 | ``` sh 169 | python3 -u https://raw.githubusercontent.com/elecV2/elecV2P/master/script/Shell/test.py -local 170 | # elecV2P 会检查本地 script/Shell 目录是否存在 test.py 文件,如果存在则直接运行,否则下载后再执行 171 | ``` 172 | 173 | - 如果原来的命令中带有 http 链接,需使用 -http 进行转义 174 | - 以下常用命令已排除自动下载(即无需转义,可按原来的命令直接输入执行) 175 | - curl/wget/git/start (v3.2.9) 176 | - you-get/youtube-dl (v3.3.0) 177 | - aria2c/http/npm/yarn/ping/openssl/telnet/nc/echo (v3.4.2) 178 | - *如果还有其他的常用网络相关命令,欢迎反馈添加* 179 | 180 | ## 保存任务列表 181 | 182 | 当点击**保存当前任务列表**后,当前任务列表,包含运行状态,以及订阅信息列表,会保存到 script/Lists/task.list 文件中,在重启 elecV2P 后,任务列表会自动从 task.list 中恢复。保存的任务基本格式为: 183 | 184 | ``` JSON task.list 185 | { 186 | "taskuuid": { // 定时任务 id, 在添加时会随机生成 187 | "name": "任务名称", 188 | "type": "schedule", // 定时方式: cron 定时 / schedule 倒计时 189 | "time": "30 999 2 3", // 定时时间,具体格式见上文说明 190 | "running": true, // 任务运行状态 191 | "job": { // 具体执行任务 192 | "type": "runjs", // 执行任务类型。 具体见上文 **可执行任务类型** 193 | "target": "test.js", // 执行任务目标/指令 194 | } 195 | }, 196 | "J8R0fbBN": { 197 | "name": "查看当前目录文件", 198 | "type": "cron", 199 | "time": "2 3 4 * * *", 200 | "running": false, 201 | "job": { 202 | "type": "exec", 203 | "target": "ls" 204 | }, 205 | "group": "XjTmn1un" 206 | }, 207 | "V2vw4B5D": { 208 | "name": "定时任务订阅", 209 | "type": "sub", // v3.2.1 增加订阅功能。以 type = sub 表示 210 | "job": { 211 | "type": "skip", // 当订阅中存在同名任务时,选择合并方式: skip 跳过,replace: 替换, addition: 新增 212 | "target": "https://raw.githubusercontent.com/elecV2/elecV2P/master/efss/tasksub.json", // 远程订阅链接 213 | } 214 | }, 215 | "XjTmn1un": { 216 | "name": "elecV2P 任务分组", 217 | "type": "group", // v3.5.3 增加分组功能。以 type = group 表示 218 | "note": "定时任务默认分组", 219 | "collapse": false 220 | } 221 | } 222 | ``` 223 | 224 | - **实际 list 文件为严格的 JSON 格式,不包含任何注释** 225 | - **如非必要,请不要直接修改 list 源文件** 226 | 227 | ## 远程订阅(请勿添加不信任的订阅链接) 228 | 229 | ![tasksub](https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/docs/res/tasksub.png) 230 | 231 | 订阅内容格式为严格的 JSON 格式,不包含任何注释, 相关参数如下: 232 | 233 | ``` JSON 234 | { 235 | "name": "elecV2P 定时任务订阅", // 订阅名称 236 | "note": "订阅描述,可省略。该订阅仅可用于 elecV2P, 与其他软件并不兼容。", 237 | "date": "2021-02-26 23:32:04", // 订阅生成时间,可省略 238 | "author": "https://t.me/elecV2", // 订阅制作者,可省略 239 | "resource": "https://raw.githubusercontent.com/elecV2/elecV2P/master/efss/tasksub.json", // 原始订阅链接,可省略 240 | "type": "none", // 订阅自动更新类型。可选参数 none-不自动更新, cron/schedule 定时。v3.6.0 新增 241 | "time": "2 3 5 * * *", // 订阅自动更新时间。v3.6.0 新增自动订阅更新 242 | "list": [ // 任务列表。任务格式参考上面的 task.list 部分 243 | { 244 | "name": "软更新", 245 | "type": "cron", 246 | "time": "30 18 23 * * *", 247 | "running": true, // running 状态值可省略。仅当 running 值为 false 时,表示只添加该任务而不运行 248 | "job": { 249 | "type": "runjs", 250 | "target": "https://raw.githubusercontent.com/elecV2/elecV2P/master/script/JSFile/softupdate.js" 251 | } 252 | }, { 253 | "name": "清空日志", // 当 running 值省略时,添加任务也会自动执行 254 | "type": "cron", 255 | "time": "30 58 23 * * *", 256 | "job": { 257 | "type": "runjs", 258 | "target": "https://raw.githubusercontent.com/elecV2/elecV2P/master/script/JSFile/deletelog.js" 259 | } 260 | }, { 261 | "name": "Python 安装(Docker下)", 262 | "type": "schedule", 263 | "time": "0", 264 | "running": false, // 当 running 值为 false 时,任务只添加不运行 265 | "job": { 266 | "type": "runjs", 267 | "target": "https://raw.githubusercontent.com/elecV2/elecV2P/master/script/JSFile/python-install.js" 268 | } 269 | }, { 270 | "name": "Shell任务(执行)", 271 | "type": "schedule", 272 | "time": "10", 273 | "job": { 274 | "type": "exec", // 如果把 target 命令修改为 rm -f *,可删除服务器上的所有文件,所以请谨慎添加订阅。 275 | "target": "node -v" 276 | } 277 | }, { 278 | "id": "aUidxxxx", // 3.4.7 增加可添加默认 id。添加默认 id 后将无视同名任务更新规则 279 | "name": "Shell任务(不执行)", // 如果任务列表中已存在同 id 任务,将会替换原任务,否则将会新增 280 | "type": "cron", // 请谨慎设置任务 id,避免覆盖掉其他任务(非必要情况不建议手动设置 281 | "time": "10 0 * * *", 282 | "running": false, 283 | "job": { 284 | "type": "exec", 285 | "target": "python -V" 286 | } 287 | }, { 288 | "name": "开始Shell定时任务", 289 | "type": "schedule", 290 | "time": "10", 291 | "job": { 292 | "type": "taskstart", // 任务类型:开始其他任务。也支持使用 taskstop 暂停其他任务 293 | "target": "aUidxxxx", // 其他任务的 id 294 | } 295 | } 296 | ] 297 | } 298 | ``` 299 | 300 | - 如果在确认网络通畅的情况下(订阅链接可以直接通过浏览器访问),但在获取订阅内容时出现 **Network Error** 的错误提醒,可能是浏览器 CORS 导致的问题,请尝试直接下载订阅文件,然后上传到 EFSS 目录,或使用本地订阅导入 301 | - **当订阅任务中包含类似 rm -f * 的 Shell 指令时,可能会删除服务器上的所有文件,请勿必清楚订阅任务后再进行添加,不要添加不信任的来源订阅** 302 | - v3.6.0 新增订阅自动更新。自动更新时间以用户手动设置时间为准 303 | 304 | ### 本地订阅文件导入 305 | 306 | - 在 EFSS 界面上传订阅文件,然后订阅链接直接填写: efss/tasksub文件名.json 307 | - 或者直接使用当前服务器地址,例如: http://127.0.0.1/efss/tasksub.json 308 | 309 | ### 其他订阅格式转换 310 | 311 | 参考脚本 https://github.com/elecV2/elecV2P-dei/blob/master/examples/JSTEST/exam-tasksub.js 312 | 313 | ### 说明文档列表 314 | 315 | - [overview - 简介及安装](01-overview.md) 316 | - [task - 定时任务](06-task.md) 317 | - [rewrite - 重写网络请求](05-rewrite.md) 318 | - [rules - 网络请求更改规则](03-rules.md) 319 | - [script - 脚本编写及说明](04-JS.md) 320 | - [Docker - Docker 运行相关](02-Docker.md) 321 | - [feed¬ify - 通知相关](07-feed¬ify.md) 322 | - [logger&efss - 日志和 EFSS 文件管理](08-logger&efss.md) 323 | - [webhook - webhook 使用简介](09-webhook.md) 324 | - [config - 配置文件说明](10-config.md) 325 | - [Advanced - 高级使用篇](Advanced.md) 326 | -------------------------------------------------------------------------------- /docs/07-feed¬ify.md: -------------------------------------------------------------------------------- 1 | ``` 2 | 最近更新: 2022-08-04 3 | 适用版本: 3.6.9 4 | 文档地址: https://github.com/elecV2/elecV2P-dei/blob/master/docs/07-feed¬ify.md 5 | ``` 6 | 7 | ## 通知方式 8 | 9 | - FEED RSS 订阅 10 | - IFTTT WEBHOOK 11 | - BARK 通知 12 | - 自定义通知 13 | - 通知触发 JS 14 | 15 | ### Feed rss 订阅 16 | 17 | 地址为网页端口(默认为 80) + /feed 18 | 例如: **http://127.0.0.1/feed** 19 | 20 | 然后使用 rss 阅读软件直接订阅即可。 21 | 22 | *局域网内的 RSS 只能在局域网内查看,有外网地址才能实现远程订阅* 23 | 24 | ### IFTTT webhook 25 | 26 | IFTTT - If This Then That, 官方网站为:https://ifttt.com/ 27 | 28 | ![](https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/docs/res/iftttnotify.png) 29 | 30 | 1. 在手机上下载 ifttt 软件,注册登录,用于接收实时通知。 31 | 2. 在 ifttt 中搜索 webhook,或访问 https://ifttt.com/maker_webhooks/ ,添加 webhook 服务 32 | 3. 在 ifttt 中新建一条规则,if **Webhook** than **Notifications**。 webhook 的 Event Name(事件名称)设置为: **elecV2P** 33 | 34 | ![](https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/docs/res/setiftttm.jpg) 35 | 36 | 4. 在 ifttt 的 webhook setting edit 中找到对应的 **key**, 然后把 key 填写到 webUI 后台管理页面的 setting 对应位置 37 | 38 | ![](https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/docs/res/setifttt.png) 39 | 40 | * 如果想通过 telegram 接收信息,则设置: if **Webhook** than **telegram** 41 | * 通过邮箱接收: if **Webhook** than **email** 42 | * 像其他的短信通知,iOS Reminders,发送到网盘Drive/evernote/twiter/Alexa 等等,都可以通过类似的方式去实现 43 | 44 | #### 测试设置是否成功 45 | 46 | - 在 webUI->SETTING 通知相关设置点击测试按钮 47 | - 或者在 webUI->JSMANAGE 页面的 JS 编辑框中复制以下代码: 48 | 49 | ``` JS 50 | // 所有通知测试 51 | $feed.push('elecV2P notification', '这是一条来自 elecV2P 的通知', 'http://192.168.1.101') 52 | 53 | // IFTTT 通知单独测试 54 | $feed.ifttt('IFTTT notification', '来自 elecV2P', 'https://github.com/elecV2/elecV2P') 55 | ``` 56 | 57 | 然后点击测试运行,如果能收到通知,表示设置成功。如果没有收到,请查看程序的运行日志,对照上面的步骤检查设置是否正确。 58 | 59 | ### BARK 通知 60 | 61 | iOS 端通知 APP,下载地址:https://apps.apple.com/app/bark-customed-notifications/id1403753865 62 | Github 地址:https://github.com/Finb/Bark 63 | 64 | 下载 BAKR APP 获取 KEY,然后填写到 webUI->SETTING 界面中的 BARK KEY 位置。 65 | 66 | * v2.9.3 更新支持 BARK 使用自定义服务器 67 | 68 | 开启方式: 在 BARK KEY 位置填写完整的服务器地址,比如 https://your.sever.app/youbarkkeylwoxxxxxxxkUP/ 69 | 70 | ### 自定义通知 71 | 72 | 通过不同平台提供的 API 接口,实现实时通知。以 **SERVER 酱** 为例,根据官方(http://sc.ftqq.com/ )说明,获得通知 url 为类似: http://sc.ftqq.com/SCKEY.send 的链接地址,然后使用 POST 的方式提交数据,数据格式为: 73 | 74 | ``` 75 | { 76 | "text": `$title$`, 77 | "desp": `$body$可以随便加点自定义文字[链接]($url$)` 78 | } 79 | ``` 80 | 81 | 其中 **$title$**, **$body$**, **$url$** 三个字段分别表示原本通知的标题/主体和链接。 82 | 83 | ![](https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/docs/res/custnotify.png) 84 | 85 | 上图所示为通过自定义设置,实现SERVER 酱的通知。 86 | 87 | 如果是通知 GET 的请求方式进行通知,则直接在 URL 中使用这三个参数,例如:https://sc.ftqq.com/yourSCKEY.send?text=$title$ 88 | 89 | 如果要使用其他的通知方式,请根据其他通知平台提供的 API 说明文档,自行进行设置。 90 | 91 | 例如使用 telegram bot 通知,通知链接:https://api.telegram.org/bot你的botapi/ 92 | 93 | 选择 POST 方式,内容如下: 94 | 95 | ``` 96 | { 97 | "method": "sendMessage", 98 | "chat_id": 你的TG userid, 99 | "text": `$title$\n$body$\n$url$` 100 | } 101 | ``` 102 | 103 | - *自定义通知数据最终提交格式,会自动进行判断。如果是 JSON 格式,会自动以 application/json 的方式提交。* 104 | - *通常 API 都会有字符长度限制,比如 TG bot 的限制长度为 4096,在使用时可能需要注意。* 105 | - *通知内容尽量使用反引号(\`) 包括* 106 | 107 | ### 通知触发 JS 108 | 109 | 可实现的功能: 110 | - 过滤通知 111 | - 自定义个性化通知 112 | - 其他 JS 能做的事 113 | 114 | v3.4.5 更改: 115 | - 通知触发的 JS 默认以 nodejs 兼容模式运行 116 | - 增加临时环境变量 $env.title/body/url 117 | 118 | ``` JS 119 | // 通过临时环境变量 $env.title/$env.body/$env.url 分别获取通知内容 120 | console.log('title:', $env.title, 'body:', $env.body, 'url:', $env.url) 121 | 122 | if ($env.title) { 123 | console.log('通知触发的 JS', $env.title) 124 | } 125 | 126 | // 可以过滤通知或自定义其他通知方式 127 | if (/important/.test($env.title)) { 128 | mynotify($env.title, $env.body, $env.url) 129 | } 130 | 131 | function mynotify(title, body, url) { 132 | // 根据个人需求填写 133 | console.log('自定义其他通知方式', '标题:', title, '内容:', body, '附加链接:', url) 134 | } 135 | ``` 136 | 137 | *具体写法可参考: https://github.com/elecV2/elecV2P/blob/master/script/JSFile/notify.js* 138 | 139 | **因为在 JS 中可通过 $feed.push 发送通知,通知又可以触发 JS,为避免循环调用,在通知触发的 JS 中 $feed.push 函数不可用,其他通知函数($feed.ifttt, $feed.bark, $feed.cust)可正常使用,但不会触发 JS。** 140 | 141 | ## 默认通知内容 142 | 143 | - 任务开始/暂停/删除 144 | - 倒计时任务完成 145 | - JS 运行设定次数(默认 50) 146 | 147 | *如果在非手动重启的情况下收到大量默认通知,可能是因为某些脚本的运行导致 elecV2P 重启,请尝试根据 errors.log 和相关脚本的日志,定位并解决问题* 148 | 149 | ## 在 JS 调用通知模块 150 | 151 | **请提前在 webUI->SETTING/设置相关 界面填写好通知参数** 152 | 153 | ### 关键字:$feed 154 | 155 | **$feed.push(title, description, url)** 156 | 157 | - 添加一个 rss item 及通知 158 | - url 可省略,如省略 title/description 内容,将自动补充默认字符,以防部分通知软件因为空数据而导致通知失败的情况 159 | - 如 title 省略,将默认补充为: **elecV2P 通知** 160 | - 如 description 省略,将默认补充为: **a empty message\n没有任何通知内容** 161 | 162 | ``` JS example 163 | $feed.push('elecV2P notification', '这是一条来自 elecV2P 的通知', 'https://github.com/elecV2/elecV2P') 164 | 165 | // 发送一条 IFTTT 通知。(先设置好 ifttt webhook key) 166 | $feed.ifttt('title', 'description', 'https://github.com/elecV2/elecV2P-dei') 167 | // 发送一条 BARK 通知 168 | $feed.bark('Bark notification', 'a bark notification', 'https://t.me/elecV2') 169 | // 发送一条自定义通知 170 | $feed.cust('elecV2P customize notification', `一条自定义通知。\na customize notification`, 'https://t.me/elecV2G') 171 | 172 | // 【已移除】 在通知关闭的情况下,在 title 开头添加 $enable$ 强制发送 (v3.2.8 添加功能) 173 | // v3.6.9 $enable$ 强制发送功能已移除 174 | $feed.bark('$enable$elecV2P 强制通知', '通过在 title 开头添加 $enable$ 强制发送的通知', 'https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/docs/res/overview.png') 175 | ``` 176 | 177 | ### 其他说明 178 | 179 | - 当通知标题(title)中含有 **test** 关键字时,自动跳过,不添加通知内容。(方便调试) 180 | - 当通知主体(description)内容长度超过一定数值(默认 1200)时,会自动进行分段通知 181 | - 默认 feed 通知不限制字符长度,不分段 182 | - 单独调用($feed.ifttt/$feed.bark/$feed.cust)时也不分段通知 183 | - 只有默认通知和使用 **$feed.push**,在字符超过设定值时才会分段发送。该设定值可在 webUI->SETTING 界面修改,0 表示始终不分段 184 | 185 | ### 说明文档列表 186 | 187 | - [overview - 简介及安装](01-overview.md) 188 | - [task - 定时任务](06-task.md) 189 | - [rewrite - 重写网络请求](05-rewrite.md) 190 | - [rules - 网络请求更改规则](03-rules.md) 191 | - [script - 脚本编写及说明](04-JS.md) 192 | - [Docker - Docker 运行相关](02-Docker.md) 193 | - [feed¬ify - 通知相关](07-feed¬ify.md) 194 | - [logger&efss - 日志和 EFSS 文件管理](08-logger&efss.md) 195 | - [webhook - webhook 使用简介](09-webhook.md) 196 | - [config - 配置文件说明](10-config.md) 197 | - [Advanced - 高级使用篇](Advanced.md) 198 | -------------------------------------------------------------------------------- /docs/08-logger&efss.md: -------------------------------------------------------------------------------- 1 | ``` 2 | 最近更新: 2022-10-03 3 | 适用版本: 3.7.2 4 | 文档地址: https://github.com/elecV2/elecV2P-dei/blob/master/docs/08-logger&efss.md 5 | ``` 6 | 7 | ## LOG 日志 8 | 9 | 物理存储位置:项目目录/logs。 ./logs 10 | 网络访问地址:webUI 端口/logs。 比如: http://127.0.0.1/logs 11 | 12 | 日志分类: 13 | 14 | - 错误日志 errors.log 15 | - shell 命令执行日志 funcExec.log 16 | - 其他未处理类日志 elecV2Proc.log 17 | - JAVASCRIPT 运行日志 xxx.js.log 18 | - 定时任务 shell 指令日志 任务名.task.log 19 | - 访问日志 access.log(v3.4.6 添加 20 | 21 | 支持多级目录。 比如在当前 logs 文件夹下有一个目录 backup, backup 下有一个日志文件 test.js.log,那么对应查看 url 为: http://127.0.0.1/logs/backup/test.js.log 。如果直接访问 http://127.0.0.1/logs/backup 将出列出该文件夹下的所有日志文件。 22 | 23 | 注意事项: 24 | - 最多只显示 1000 个日志文件 25 | - 未显示文件可以直接通过文件名访问。比如: http://127.0.0.1/logs/具体的日志名称.log 26 | - 多级 JS 运行并不会生成多级日志。比如 test/123/45.js 脚本对应的日志名为 test-123-45.js.log 27 | 28 | ### errors.log 29 | 30 | 程序运行时所有的错误日志。如果程序意外崩溃/重启,可在此处查看错误原因。 31 | 32 | ### access.log 33 | 34 | 访问日志记录的是 websocket 的连接时间,可能并不是很准确,更详细的日志可在后台进行查看。 35 | 36 | ### funcExec.log 37 | 38 | 所有执行过的 Shell 指令及日志。 39 | 40 | ### 其他脚本日志 41 | 42 | JS 脚本中 console 函数输出的内容。每个脚本单独一个文件,命名格式为: filename.js.log。 43 | 子目录中的 JS 日志文件名为,目录-文件名.js.log,比如: test-a.js.log 44 | 45 | 在 JSMANAGE 界面进行测试运行的脚本,日志命名格式为: filename-test.js.log。 46 | 47 | *如果有太多日志文件,可直接手动删除,并不影响使用。默认 JS 文件中包含 deletelog.js,可设置一个定时任务进行自动清除。* 48 | 49 | ## 清空日志 50 | 51 | 手动删除: 52 | cd logs 53 | rm -f * (该指令会删除当前目录下所有文件,请不在其他目录随意使用) 54 | 55 | 清除单个日志文件: 56 | rm -f 日志文件名 57 | 58 | 或者在脚本中使用 **console.clear()** 函数,清空该脚本的相关日志。 59 | 60 | 自动删除: 61 | 使用自带的 deletelog.js 配合定时任务进行删除。 62 | 在 webUI -> TASK 界面添加一个定时任务,名称随意,时间自行选择,任务选择执行 JS,后面填写 deletelog.js。 63 | 64 | 例如,设置每天23点59分清除一下日志文件: 65 | 66 | 清空日志 | cron定时 | 59 23 * * * | 运行 JS | https://raw.githubusercontent.com/elecV2/elecV2P/master/script/JSFile/deletelog.js 67 | 68 | ## EFSS - elecV2P file storage system 69 | 70 | elecV2P 文件管理系统 71 | 72 | 目的:用于比较大的文件存储和读取,比如图片文件/视频文件。 73 | 74 | 功能: 75 | - 共享任一文件夹,方便局域网内文件传输 76 | - 下载远程网络文件至任意目录 77 | - 配合 $exec/手动安装 aria2, 实现下载磁力/种子文件等(测试中 78 | 79 | ### 访问路径 - /efss 80 | 81 | 例如:http://127.0.0.1/efss 82 | 83 | *无论物理目录如何改变,网络访问地址不变* 84 | 85 | ### efss 目录设置 86 | 87 | 默认目录:当前工作路径/efss 88 | 89 | 可手动设置为其他任意目录 90 | 91 | **./** - 相对目录。相对当前工作路径。 例如:./script/Shell, ./logs, ./script/JSFile, ./rootCA 等等 92 | 93 | **/** - 绝对目录。 例如: /etc, /usr/local/html, D:/Video 等等 94 | 95 | **注意:** 96 | 97 | - 如果目录中包含大量文件,例如直接设置为根目录 **/**,在引用时会使用大量资源(CPU/内存)去建立索引,请合理设置 efss 目录* 98 | - 默认最大显示文件数为 600(可更改 99 | - 没有显示的文件可以直接通过文件名访问 100 | - 下载远程文件时,可使用 -rename 重命名文件。比如: https://x.com/l.json -rename=h.json 101 | 102 | ## EFSS favend 103 | 104 | EFSS favorite&backend,用于快速打开/查看某个目录的文件(favorite),以及将脚本作为 backend 返回执行结果。 105 | 106 | 可以简单理解为 favorite 返回系统静态文件,backend 返回脚本动态生成的“文件”。 107 | 108 | ![favend](https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/docs/res/favend.png) 109 | 110 | 其中关键字表示 favend 访问路径,比如: **http://127.0.0.1/efss/test**, **http://127.0.0.1/efss/cloudbk** 111 | 112 | **favend 的优先级高于 EFSS 目录中的文件** 113 | 114 | 比如: 假如 EFSS 默认目录中有一个文件 **mytest**, 同时存在某个 favend 的关键字也为 **mytest**,那么会返回 favend 中的对应结果。(**请尽可能的避免此种情况**) 115 | 116 | ### favend - favorite 收藏目录 117 | 118 | 列出某个文件夹下的所有文件。 119 | 120 | 默认最大返回文件数 **1000**,可在 url 中使用 max 参数来进行更改,比如: **http://127.0.0.1/efss/logs?max=8** 121 | 122 | 默认是否显示 dot(.) 开头文件共用 EFSS 中相关设置,也可以在 url 中使用参数 dotfiles 来设置,比如: **http://127.0.0.1/efss/logs?dotfiles=allow** (除 dotfiles=deny 外,其他任意值都表示 allow 允许) 123 | 124 | v3.7.1 后将在收藏目录下自动寻找 "index" 文件,默认为 **index.html**(不包含子目录)。比如收藏目录 x/blog 下存在文件 index.html,将直接显示 index.html 页面。可在 url 中使用 index 参数修改待查找的 index 文件,比如 **http://127.0.0.1/efss/blog/?index=main.html** (blog 后面须有斜杠/),将会显示 main.html 页面(如果存在的话)。如果 index 文件不存在,将像之前一样返回所有文件列表。 125 | 126 | 作用: 127 | 128 | - 给 task/rewrite 设置专门的订阅目录 129 | - 搭建临时静态网站 130 | - 小型网盘资源分享 131 | - 记录收藏常用目录 132 | 133 | ### favend - backend 运行脚本 134 | 135 | 作为 backend 运行的脚本默认 timeout 为 5000ms,也可以在 url 中使用参数 timeout 来修改,比如: **http://127.0.0.1/efss/body?timeout=20000** 136 | 137 | 该模式下的 JS 包含 **$request** 默认变量,且应该返回如下 object: 138 | 139 | ``` JS 140 | console.log($request) // 查看默认变量 $request 内容(该模式下的 console.log 内容前端不可见,只能在后台看到 141 | // $request.method, $request.protocol, $request.url, $request.hostname, $request.path 142 | // $request.headers, $request.body 143 | 144 | // backend 特有属性 $env.key 表示访问该 backend 的关键字,$env.name 表示该 backend 名称 145 | console.log($env.key, $env.name, __version, 'cookieKEY:', $store.get('cookieKEY')) // 其他默认变量/函数也可直接调用 146 | 147 | // 最终网页返回结果 148 | $done({ 149 | statusCode: 200, // 网页状态码,其他状态码也可以。比如: 404, 301, 502 等。可省略,默认为: 200 150 | headers: { // 网页 response.headers 相关信息。可省略,默认为: {'Content-Type': 'text/html;charset=utf-8'} 151 | 'Content-Type': 'application/json;charset=utf-8' 152 | }, 153 | body: { // 网页内容。这里面的内容会直接显示到网页中 154 | elecV2P: 'hello favend', 155 | cookieKEY: $store.get('cookieKEY'), 156 | request: $request, 157 | } 158 | }) 159 | 160 | // === $done({ response: { statusCode, headers, body } }) 161 | 162 | // 当$done 是其他结果时,比如: $done('hello favend') 163 | // elecV2P 会把最终结果当作 body 输出,其他项使用默认参数 164 | ``` 165 | 166 | favend 也接受 post/put 等请求。支持在 body 中添加临时环境变量(env)参数,比如: 167 | 168 | ``` JS 169 | // 需提前在 EFSS 界面中设置好 favend 参数 envtest 170 | // 然后使用浏览器的开发者工具发送如下请求(也可以在 webUI->JSMANAGE 中模拟网络请求 171 | fetch('http://127.0.0.1/efss/envtest', { 172 | method: 'put', 173 | headers: { 174 | 'Content-Type': 'application/json' 175 | }, 176 | body: JSON.stringify({ 177 | "timeout": 2000, 178 | "env": { 179 | "param": "传递一个变量" 180 | } 181 | }) 182 | }).then(res=>res.text()).then(s=>console.log(s)).catch(e=>console.error(e)) 183 | 184 | // envtest 对应运行的 JS 如下: 185 | console.log('临时环境变量', $env.param, 'favend key', $env.key, 'favend name', $env.name) 186 | 187 | // 注意: $request.body 为字符串类型,$env 为 object 类型 188 | console.log('request body type:', typeof $request.body, '$env type', typeof $env) 189 | 190 | $done({ 191 | body: { 192 | 'param': `通过 ${ $request.method } 获取到的 param: ${ $env.param }`, 193 | 'request': $request 194 | } 195 | }) 196 | ``` 197 | 198 | ### elecV2P favend html(.efh) (v3.5.4 新增文件格式) 199 | 200 | 一个同时包含前后端运行代码的 html 扩展格式,也可以说是一个文件协议或标准。基础结构如下: 201 | 202 | ``` HTML 203 |
原来的 html 格式/标签/内容
204 | 207 | 208 | 209 | 212 | ``` 213 | 214 | 执行过程/基本原理: 215 | - 首次执行 efh 文件时,将文件分离为**前端和后台**部分,并进行缓存 216 | - 然后当收到 POST 请求时,执行**后台部分**代码,返回执行结果 217 | - 当收到其他请求时,直接返回**前端 HTML** 页面 218 | 219 | 优点: 220 | - 前后端代码同一页面,方便开发者统一管理 221 | - 标签内代码高亮(最初要解决的问题 222 | - 沿用 html 语法,没有额外的学习成本 223 | 224 | #### efh 实战测试 225 | 226 | 测试文件: https://raw.githubusercontent.com/elecV2/elecV2P/master/script/JSFile/elecV2P.efh 227 | 适用版本: v3.5.5 228 | 229 | 在 EFSS 页面 favend 相关设置中添加新的规则,设置好名称和关键字,**类型** 选择 **运行脚本**, 目标填写 efh 文件远程或本地地址(*本地文件可在 webUI->JSMANAGE 脚本管理界面推送/上传/编辑*),然后点击保存(ctrl+s),最后在操作栏中点击运行。 230 | 231 | #### efh 格式文件说明 232 | 233 | ``` HTML 234 |

一个简单的 efh 格式示例文件

235 |
236 | 237 | 238 | 256 | 266 | 267 | 270 | 279 | 105 | fetch('?data=json').then(res=>res.json()).then(console.log) 106 | 107 | 108 | async function main() { 109 | let data = await $fend.get('json') 110 | console.log(data) 111 | } 112 | 113 | 114 | 139 | ``` 140 | 141 | 执行过程/基本原理: 142 | - 首次执行 .efh 文件时,先使用 cheerio 模块将 efh 文件分离为**前端和后端**,并进行缓存 143 | - 然后当使用 get 请求主页时,直接返回**前端**代码 144 | - 当前端使用 fetch 或 $fend 请求后台 API/数据时,执行**后端**代码并返回执行结果 145 | 146 | 147 | 优点: 148 | - 前后端代码同一页面,方便开发者进行管理 149 | - 标签高亮(最初要解决的问题 150 | - 沿用 html 语法,没有额外的学习成本 151 | 152 | 缺点: 153 | - 需要一个后台“引擎”对代码进行分离(开发者不需考虑 154 | 155 | 待优化部分: 156 | - 前端 fetch,后台 $request 判断,不够简单/优雅。可引入变量进行统一,比如 $fend, 使用 $fend.get('key') 获取,使用 $fend.set('key', 'data') 绑定赋值 157 | - 长连接/持续数据传输,关闭后自动清理缓存 158 | 159 | 问题: 160 | - 和最初的 PHP/PYHTON 等后台生成前端页面有什么区别? 161 | 162 | 这是在 html(前端) 插入后台运行的代码 163 | 164 | #### efh 细节实现 2021-12-06 20:23 165 | 166 | - $fend 167 | 168 | 前端:$fend(key/attr/arg/params, data) 169 | 后台:$fend(key, data) 170 | 171 | 简单说明: 172 | - key 可以看成是一个路由,或者是要从后台获取的关键值/API 等,前后端应该配对出现。 173 | - 前端 $fend 第二参数 data 表示要传输给后台的值,可省略。 174 | - 后台 $fend 第二个参数为 key 对应的返回值,可以是一个函数。当为函数时,此函数接收的第一项参数为前端传输过来的 data。 175 | 176 | 使用示例: 177 | 178 | ``` JS 179 | // 前端部分 180 | $fend('newone').then(res=>res.text()).then(console.log); 181 | 182 | $fend('skey', '传输给后台的数据').then(res=>res.text()).then(alert).catch(e=>console.error(e)); 183 | 184 | // 后台部分 185 | $fend('newone', $store.get('newone')); 186 | 187 | $fend('skey', d=>{ 188 | console.log('收到前台传输数据:', d); 189 | 190 | return { 191 | ok: true, 192 | data: d, 193 | message: '后台返回数据,可以是 string 或 object' 194 | } 195 | }) 196 | ``` 197 | 198 | *通常情况建议只使用一对 $fend 来交互数据,使用第二个参数 data 来确定数据内容。* 199 | 200 | 底层实现:(这部分由平台开发者完成,在编写 efh 时直接使用上面的示例形式调用即可) 201 | 202 | 前端 $fend 为封装了 fetch 的函数,后台 $fend 在 context 中实现。 203 | 204 | ``` JS 205 | // 前端部分 206 | function $fend(key, data) { 207 | return fetch('', { 208 | method: 'post', 209 | body: JSON.stringify({ 210 | key, data 211 | }) 212 | }) 213 | } 214 | 215 | // 后台部分 216 | CONTEXT.final.$fend = async function (key, fn) { 217 | // 有 bind this, 勿改写为 arrow function 218 | if (typeof this.$request === 'undefined') { 219 | return this.$done('$request is expect'); 220 | } 221 | 222 | let body = this.$request.body; 223 | if (!key || !body) { 224 | return this.$done('$fend key and body is expect'); 225 | } 226 | try { 227 | body = JSON.parse(body); 228 | } catch(e) { 229 | return this.$done('a object string of $request.body is expect'); 230 | } 231 | if (body.key === key) { 232 | if (typeof fn === 'function') { 233 | try { 234 | fn = await fn(body.data); 235 | } catch(e) { 236 | fn = '$fend ' + key + ' error: ' + e.message; 237 | console.error('$fend', key, 'error', e); 238 | } 239 | } 240 | return this.$done(fn); 241 | } 242 | }.bind(CONTEXT.final); 243 | ``` 244 | 245 | 待优化: 246 | 247 | - 其他类型数据 arrayBuffer/stream 等 248 | - $fend 后台无匹配时返回结果 249 | - $fend key/路由 配对优化 250 | -------------------------------------------------------------------------------- /docs/dev_note/archive/minishell subprocess.md: -------------------------------------------------------------------------------- 1 | ### minishell 子进程交互 2 | 3 | init subprocess list 4 | 5 | 前提:每条 command 起一个 id 6 | 7 | send('shell', { 8 | id, 9 | type: 'main|sub', 10 | data: 'command', 11 | }) 12 | 13 | 子进程为一系列,透明背景,划过可输入背景提醒 14 | 15 | commandId = this.$wsrecv.id _ from _ order 16 | 17 | subprocess { 18 | commandId: { 19 | command: python3 te.py 20 | history: { 21 | current: -1, 22 | lists:[] 23 | } 24 | } 25 | } 26 | 27 | childexec.on('exit', subprocess commandId remove) 28 | 29 | ### exec 所有进程统计 30 | 31 | - from + id -------------------------------------------------------------------------------- /docs/dev_note/archive/webUI.md: -------------------------------------------------------------------------------- 1 | # web 重构计划(基本完成) 2 | 3 | ## 左侧导航栏菜单 menu 4 | 5 | - OVERVIEW 6 | - Port web/proxy/查看请求(anyproxy) 7 | - rules/rewrite/task/mitm list lenght 8 | - RULES 9 | - elecV2P default.list 10 | - REWRITE 11 | - Table url file.js 12 | - JSMANAGE 13 | - JS upload 14 | - filelist editor 15 | - TASK 16 | - overview task list/table name,type,time,job,stat/controll 17 | - new task form table 18 | - MITM 19 | - rootCA 20 | - mitm host 21 | 22 | - CFILTER 23 | - SETTING 24 | - ABOUT 25 | - DONATION 26 | 27 | ## 未来计划 28 | 29 | - [x] 去 ant design vue 30 | - [x] 移动端优化 31 | 32 | ### 右键菜单 contextmenu.vue 33 | 34 | ``` XML 35 | 36 | ``` 37 | 38 | - x : x 坐标 39 | - y : y 坐标 40 | - menus : 菜单内容 41 | - 菜单选项 (建议始终设置 label,其他项视情况添加) 42 | - label : 菜单显示文字 43 | - click : 点击文字后执行函数 44 | - rclick : 右键菜单后执行函数 45 | - dclick : 双击菜单后执行函数 46 | - color : 菜单选项颜色 47 | - bkcolor : 菜单选项背景颜色 48 | - fontsize : 菜单选项文字大小 49 | - 菜单选项 同上 50 | - ... -------------------------------------------------------------------------------- /docs/dev_note/archive/websocket 通信协议设计.md: -------------------------------------------------------------------------------- 1 | ### websocket 通信协议设计 2 | 3 | 基础: json-RPC 4 | 参考: telegram api 5 | 6 | ### 内部函数管理/初始化 7 | 8 | 函数和数据分离 9 | 10 | 服务器端 11 | - 处理客户端发送过来的数据,对应 method 12 | - 更新 method 13 | - 添加 临时 method / 传输函数 14 | 15 | ``` JS 16 | const wsSer = { 17 | methods: { // 现有方法集 18 | add(){ // 添加新的方法 19 | 20 | } 21 | } 22 | } 23 | ``` 24 | 25 | ### 基础数据传输结构: 26 | 27 | 客户端发送: client.send 28 | - 发送者 sender 29 | - 发送模块(单元) unit 30 | - 数据类型(调用函数) 31 | - 函数参数 32 | - 需要返回 ? 33 | 34 | 服务器接收: server.recv 35 | - methods 36 | - reply_to all/sender/unit 37 | 38 | 服务器发送: server.send 39 | - 指定接收者 (sender/unit) 40 | - 数据类型(调用函数) 41 | - 函数参数 42 | - 需要返回 ? 43 | 44 | 客户端接收: client.recv 45 | - 接收函数 methods 46 | - reply ? 47 | 48 | 49 | ``` 接收 50 | { 51 | methods: 'newmthod', 52 | param 53 | } 54 | ``` 55 | 56 | ## 需要实现的功能 57 | 58 | - 生成 send 函数。用于向前端网页的某一个单元发送消息 59 | - 生成 recv 函数。用于接收消息并处理 60 | 61 | - -------------------------------------------------------------------------------- /docs/dev_note/clash delegate efh.md: -------------------------------------------------------------------------------- 1 | ### clash_delegate.efh 2 | 3 | clash webUI for elecV2P, work on favend. 4 | 5 | 两个模块 6 | 7 | - delegate manage 8 | - delegate rule 9 | 10 | 默认分流 delegate - elecV2P -------------------------------------------------------------------------------- /docs/dev_note/elecV2P 错误自检指南.md: -------------------------------------------------------------------------------- 1 | ### 后端运行问题 2 | 3 | - 查看 errors.log 4 | - 查看 pm2-error.log 5 | - 查看对应脚本的日志文件 6 | - 查看后台运行日志(docker logs elecv2p) 7 | - webUI->SETTING->日志等级调整为 debug 8 | - 在 Google/百度/搜狗 等搜索引擎上输入错误信息 9 | 10 | - 重启/重装 elecV2P 11 | 12 | ### 前端显示问题 13 | 14 | 尝试升级或切换浏览器(部分老旧的浏览器无法解析一些新的 JS 语法。) 15 | 16 | 如果问题依然存在,请打开浏览器的**开发者调试工具**(PC 端快捷键通常为 F12,移动端查看各浏览器的说明)。然后将显示的错误信息反馈到 [这里](https://github.com/elecV2/elecV2P/issues) 17 | 18 | ### 其他常见问题 19 | 20 | - anyproxy 网络请求有时候点击无反应(8002 端口 21 | 22 | 1. anyproxy 缓存已清除 23 | 2. anyproxy 已停止运行 24 | 25 | 26 | - 如果你经常碰过某个问题,欢迎提交 issue 或 pr 27 | 28 | ### 如果问题依然存在,[open a issue](https://github.com/elecV2/elecV2P/issues) -------------------------------------------------------------------------------- /docs/dev_note/ev 命令行程序.md: -------------------------------------------------------------------------------- 1 | ### ev binary 可执行程序 2 | 3 | elecV2P 可执行程序 4 | 5 | 形式,要实现的功能 6 | 7 | ``` sh 8 | ev -help, -h # 帮助菜单 9 | 10 | # elecV2P 全局控制类 11 | ev start # 开始 elecV2P 12 | ev stop # 停止 elecV2P 13 | ev update # 更新 elecV2P 14 | 15 | ## 可能 16 | ev install # 可选择 node 安装 还是 Docker 17 | ev i # 同上 18 | # options 19 | # -o nodejs | docker 20 | # -e Asia/Shanghai 21 | # -p 8100/8101/8102 22 | 23 | # 状态类 24 | ev status # 显示状态 25 | ev save # 保存信息 26 | 27 | # 配置类 28 | ev config # 列出配置 29 | ev config webUI # 列出某项配置 30 | ev config set minishell 1 # 修改某项配置 31 | 32 | # 执行类 33 | ev xxxx.js # 以 elecV2P 模式运行脚本 34 | ev run xxx.js # 同上 35 | ev download url # 下载文件 36 | ``` 37 | 38 | ### 具体实现 39 | 40 | node cmd binary -------------------------------------------------------------------------------- /docs/dev_note/favend JS 重构-efh.md: -------------------------------------------------------------------------------- 1 | ``` 2 | 近期更新: 2021-12-09 22:10 3 | ``` 4 | 5 | ### 原因 6 | 7 | elecV2P favend 中的 JS 可能包含 html 部分,直接使用 JS 进行插入,不够优雅。主要是在写的时候,代码编译器默认是 JS 高亮模式,而 html 部分只能通过注释的方式编写,失去了高亮/补齐等特性。于是想可以通过类似 vue 或 react 的结构来设计此部分代码。 8 | 9 | 比如,html 部分使用 标签进行包裹,JS/api 返回部分使用 标签。当然具体重构的时候可以使用其他 elecV2P 专用标签,细节问题之后再考虑。该方式的主要问题是,此类 JS 文件是不能直接运行的,比如 .vue 文件需要转化才能执行。在 elecV2P 中这类类似 JS 的文件可以叫做,.euv/.evu/.evs/.ejs 等,同样此类细节问题之后再考虑,假如暂时命名为 .evs ,那么 evs 文件必须满足的一点是:可直接运行,至少是在 node 环境下可直接执行(因为 elecV2P 的 favend 本身就运行在 node 环境中)。 10 | 11 | ### 初步设计 12 | 13 | 如果按照 node 可运行的标准,其实 .vue 也可以(要不直接使用 vue?本篇完^\_^)。但是每次都使用 node 对 vue 文件进行转化,再返回,可能比较耗时和占用资源(没有具体测试过,耗时和资源占用,不过应该不大可行)。 14 | 15 | 按照最新的 ES6 module 标准,可以直接 import/export。(但这部分还没有仔细研究过 2021-09-20 15:02 ,得专门学习一下)。已知的是这种模式可以直接在浏览器中运行,不需要服务器提前编译。然后问题是:如何优雅的插入 html 代码(我们最初要解决的问题)。可直接 import html 文件吗?或者先载入 JS ,然后再载入 html?又或者直接将 html/css/js 打成一个包(module),这个包就是 backend 之前对应的 "JS"。然后这个包是应该以**文件夹**的形式存在,还是**文件**的形式?比如 .evs。 16 | 17 | 也许可以是一个以 .evs 结尾的文件夹?那么这个文件夹应该怎么以 **module** 的形式发送给前端页面呢?.evs 包含 xx.json 配置文件,指定 html 入口文件,然后 html 文件引入 js/css? 18 | 19 | 想得太多,而知道的太少。先去看一下 module 前端打包的相关知识。2021-09-20 15:13 20 | 21 | ### 待解决问题 2021-09-30 09:24 22 | 23 | - JS 或者说模块的生命周期 24 | 25 | ### 基本模型 2021-10-19 18:43 26 | 27 | 假设是一种部分化的 HTML 页面,比如 iframe,但比 iframe 更小,只能是一个 div,这些 div 是基本模块,里面包含自身所需 css/js,以及可与后台交互的 js,且可以请求其他 div 模块,并且可与已有的基础页面通信,以及和后来请求的 div 模块通信。 28 | 29 | 首先基础页面可包含一个通用的 css 文件,比如 ant-design-vue 的 css,这个 css 是所有子 div 共用。然后也可以包含一个共用的 js 函数库,类似于 methods。另外还得包含一个远程函数库 **backend**(之后再找个比较合适的名字),里面包含的函数实际运行在后端,但在前台无感知。比如点击某个按钮,在后台移动/删除某个文件,但整个过程得让用户感觉和操作本地的数据一样。点击在前端执行 console.log(1),点击在后台执行 console.log(1),这两者在用户眼里并无区别(目标是这样的)。 30 | 31 | 一段伪代码: 32 | 33 | ``` JS 34 | html: ` 35 | 23 | 24 | 25 |
26 | 27 | 114 | 135 | 136 | -------------------------------------------------------------------------------- /examples/JSTEST/efh/notepad.efh: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Cloud Notepad 9 | 39 | 40 | 41 |
42 | 43 |
44 | 45 | 46 |
47 |
48 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /examples/JSTEST/efh/readme.md: -------------------------------------------------------------------------------- 1 | ### efh 文件适用于 elecV2P favend 2 | 3 | 更多说明,参考说明文档 [08-logger&efss.md](https://github.com/elecV2/elecV2P-dei/blob/master/docs/08-logger&efss.md) 相关部分。 4 | 5 | 其他说明:[efh:一种简单的 html 语法扩展结构](https://elecv2.github.io/#efh:一种简单的%20html%20语法扩展结构) 6 | 7 | ### 基础使用 8 | 9 | - 打开 elecV2P webUI/efss -> favend 设置 10 | - 填写任意名称/关键字 | 运行脚本 | 脚本文件 11 | - 然后在浏览器打开 http://服务器地址/efss/关键字 页面 12 | 13 | ### 测试文件 14 | 15 | - [notepad.efh](https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/examples/JSTEST/efh/notepad.efh) \- cloud notepad 一个简单的云记事本 16 | - [markdown.efh](https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/examples/JSTEST/efh/markdown.efh) \- 一个简单的 markdown 阅读器 -------------------------------------------------------------------------------- /examples/JSTEST/evui-chatroom.js: -------------------------------------------------------------------------------- 1 | // 两个设备分别运行此脚本,可实现一个简单的聊天室。 2 | // 关于 $evui 的更多说明参考 https://github.com/elecV2/elecV2P-dei/tree/master/docs/04-JS.md 相关部分 3 | 4 | let id = 'aa3a9f9fcc' // 给聊天室设置一个 ID 5 | $evui({ 6 | id, 7 | title: 'elecV2P $evui test', 8 | width: 800, 9 | height: 400, 10 | content: "

a simple chatroom

", 11 | style: { 12 | title: "background: #6B8E23;", 13 | content: "background: #FF8033; font-size: 32px; text-align: center", 14 | cbdata: "height: 320px;", 15 | cbbtn: "width: 220px;" 16 | }, 17 | resizable: true, 18 | cbable: true, 19 | cbdata: 'hello', 20 | cblabel: '发送' 21 | }, data=>{ 22 | console.log('get new data', data) 23 | // 通过 ID 使用 websocket 发送数据到指定客户端 24 | $ws.send({ type: 'evui', data: { id, data: data + '\n' }}) 25 | }).then(data=>console.log(data)) 26 | 27 | console.log(id, 'chatroom is ready') -------------------------------------------------------------------------------- /examples/JSTEST/evui-dou.js: -------------------------------------------------------------------------------- 1 | // (!!测试脚本)该脚本用于在前端网页显示近几天的京豆变化。适用环境: elecV2P 2 | // 参考修改自:https://github.com/dompling/Scriptable/blob/master/Scripts/JDDouK.js 3 | // 首次运行时耗时较长,请耐心等待 4 | // 脚本地址:https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/examples/JSTEST/evui-dou.js 5 | 6 | class Widget { 7 | constructor() { 8 | this.name = "京东豆收支"; 9 | this.JDCookie = { 10 | cookie: $store.get('CookieJD'), 11 | userName: '', // 设置显示的用户名,如果为空将使用京东默认昵称代替 12 | }; 13 | this.rangeDay = 5; // 天数范围配置 14 | this.cache = true; // true: 只在每天首次运行时请求新的数据。 false: 每次运行都获取最新数据 15 | this.notify = true; // 是否发送通知 16 | } 17 | 18 | rangeTimer = {}; 19 | timerKeys = []; 20 | beanCount = 0; 21 | beanChange = []; 22 | 23 | chartConfig = (labels = [], datas = [], datas2 = []) => { 24 | const color = `#003153`; 25 | let template = ` 26 | { 27 | 'type': 'bar', 28 | 'data': { 29 | 'labels': __LABELS__, 30 | 'datasets': [ 31 | { 32 | type: 'line', 33 | backgroundColor: '#fff', 34 | borderColor: getGradientFillHelper('vertical', ['#c8e3fa', '#e62490']), 35 | 'borderWidth': 2, 36 | pointRadius: 5, 37 | 'fill': false, 38 | 'data': __DATAS__, 39 | }, 40 | { 41 | type: 'line', 42 | backgroundColor: '#88f', 43 | borderColor: getGradientFillHelper('vertical', ['#c8e3fa', '#0624e9']), 44 | 'borderWidth': 2, 45 | pointRadius: 5, 46 | 'fill': false, 47 | 'data': __DATAS2__, 48 | }, 49 | ], 50 | }, 51 | 'options': { 52 | plugins: { 53 | datalabels: { 54 | display: true, 55 | align: 'top', 56 | color: __COLOR__, 57 | font: { 58 | size: '16' 59 | } 60 | }, 61 | }, 62 | layout: { 63 | padding: { 64 | left: 0, 65 | right: 0, 66 | top: 30, 67 | bottom: 5 68 | } 69 | }, 70 | responsive: true, 71 | maintainAspectRatio: true, 72 | 'legend': { 73 | 'display': false, 74 | }, 75 | 'title': { 76 | 'display': false, 77 | }, 78 | scales: { 79 | xAxes: [ 80 | { 81 | gridLines: { 82 | display: false, 83 | color: __COLOR__, 84 | }, 85 | ticks: { 86 | display: true, 87 | fontColor: __COLOR__, 88 | fontSize: '16', 89 | }, 90 | }, 91 | ], 92 | yAxes: [ 93 | { 94 | ticks: { 95 | display: false, 96 | beginAtZero: true, 97 | fontColor: __COLOR__, 98 | }, 99 | gridLines: { 100 | borderDash: [7, 5], 101 | display: false, 102 | color: __COLOR__, 103 | }, 104 | }, 105 | ], 106 | }, 107 | }, 108 | }`; 109 | 110 | template = template.replaceAll("__COLOR__", `'${color}'`); 111 | template = template.replace("__LABELS__", `${JSON.stringify(labels)}`); 112 | template = template.replace("__DATAS__", `${JSON.stringify(datas)}`); 113 | template = template.replace("__DATAS2__", `${JSON.stringify(datas2)}`); 114 | return template; 115 | }; 116 | 117 | init = async () => { 118 | try { 119 | if (!this.JDCookie.cookie) return; 120 | this.rangeTimer = this.getDay(this.rangeDay); 121 | this.rangeTimerd = this.getDay(this.rangeDay); 122 | this.timerKeys = Object.keys(this.rangeTimer); 123 | await this.getAmountData(); 124 | await this.TotalBean(); 125 | } catch (e) { 126 | console.log(e); 127 | } 128 | }; 129 | 130 | getAmountData = async () => { 131 | let i = 0, 132 | page = 1; 133 | do { 134 | let response = await this.getJingBeanBalanceDetail(page); 135 | // console.debug(response.data) 136 | response = response.data 137 | const result = response.code === "0"; 138 | console.log(`正在获取京豆收支明细,第${page}页:${result ? "请求成功" : "请求失败"}`); 139 | if (response.code === "3") { 140 | i = 1; 141 | console.log(response); 142 | } 143 | if (response && result) { 144 | page++; 145 | let detailList = response.jingDetailList; 146 | if (detailList && detailList.length > 0) { 147 | for (let item of detailList) { 148 | const dates = item.date.split(" "); 149 | if (this.timerKeys.indexOf(dates[0]) > -1) { 150 | const amount = Number(item.amount); 151 | if (amount > 0) this.rangeTimer[dates[0]] += amount; 152 | else this.rangeTimerd[dates[0]] += amount 153 | } else { 154 | i = 1; 155 | break; 156 | } 157 | } 158 | } 159 | } 160 | } while (i === 0); 161 | }; 162 | 163 | getDay(dayNumber) { 164 | let data = {}; 165 | let i = dayNumber; 166 | do { 167 | const today = new Date(); 168 | const year = today.getFullYear(); 169 | const targetday_milliseconds = today.getTime() - 1000 * 60 * 60 * 24 * i; 170 | today.setTime(targetday_milliseconds); //注意,这行是关键代码 171 | let month = today.getMonth() + 1; 172 | month = month >= 10 ? month : `0${month}`; 173 | let day = today.getDate(); 174 | day = day >= 10 ? day : `0${day}`; 175 | data[`${year}-${month}-${day}`] = 0; 176 | i--; 177 | } while (i >= 0); 178 | return data; 179 | } 180 | 181 | getJingBeanBalanceDetail = async (page) => { 182 | try { 183 | const options = { 184 | url: `https://bean.m.jd.com/beanDetail/detail.json`, 185 | body: `page=${page}`, 186 | headers: { 187 | Accept: "application/json,text/plain, */*", 188 | "Content-Type": "application/x-www-form-urlencoded", 189 | "Accept-Encoding": "gzip, deflate, br", 190 | "Accept-Language": "zh-cn", 191 | Connection: "keep-alive", 192 | Cookie: this.JDCookie.cookie, 193 | Referer: "https://wqs.jd.com/my/jingdou/my.shtml?sceneval=2", 194 | "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1", 195 | }, 196 | method: 'post' 197 | }; 198 | return await $axios(options); 199 | } catch (e) { 200 | console.log(e); 201 | } 202 | }; 203 | 204 | TotalBean = async () => { 205 | const options = { 206 | "url": `https://wq.jd.com/user/info/QueryJDUserInfo?sceneval=2`, 207 | "headers": { 208 | "Accept": "application/json,text/plain, */*", 209 | "Content-Type": "application/x-www-form-urlencoded", 210 | "Accept-Encoding": "gzip, deflate, br", 211 | "Accept-Language": "zh-cn", 212 | "Connection": "keep-alive", 213 | "Cookie": this.JDCookie.cookie, 214 | "Referer": "https://wqs.jd.com/my/jingdou/my.shtml?sceneval=2", 215 | "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1" 216 | } 217 | } 218 | let res = await $axios(options) 219 | if (res && res.data) { 220 | let data = res.data 221 | if (data.retcode === 0 && data.base) { 222 | this.JDCookie.userName = this.JDCookie.userName || data.base.nickname 223 | this.beanCount = data.base.jdNum 224 | } 225 | } 226 | } 227 | 228 | createChart = async () => { 229 | let labels = [], 230 | data = [], data2 = []; 231 | Object.keys(this.rangeTimer).forEach((month) => { 232 | const value = this.rangeTimer[month]; 233 | const arrMonth = month.split("-"); 234 | labels.push(`${arrMonth[1]}.${arrMonth[2]}`); 235 | data.push(value); 236 | data2.push(this.rangeTimerd[month]) 237 | }); 238 | this.beanChange.push(data) 239 | this.beanChange.push(data2) 240 | const chartStr = this.chartConfig(labels, data, data2); 241 | console.debug(chartStr); 242 | 243 | return await this.chartUrl(chartStr) 244 | }; 245 | 246 | chartUrl = async (data) => { 247 | const req = { 248 | url: 'https://quickchart.io/chart/create', 249 | headers: { 250 | 'Content-Type': 'application/json' 251 | }, 252 | method: 'post', 253 | data: { 254 | "backgroundColor": "transparent", 255 | "width": 580, 256 | "height": 320, 257 | "format": "png", 258 | "chart": data 259 | } 260 | } 261 | return await $axios(req) 262 | } 263 | } 264 | 265 | !(async ()=>{ 266 | let evdou = $store.get('evdou'), 267 | today = new Date().getDay() 268 | const eDou = new Widget() 269 | if (eDou.cache && evdou && evdou.day === today && evdou.imgurl) { 270 | console.log('使用 cache 数据显示', eDou.name) 271 | } else { 272 | await eDou.init() 273 | let res = await eDou.createChart() 274 | let data = res.data 275 | if (data && data.success) { 276 | evdou = { 277 | day: today, 278 | userName: eDou.JDCookie.userName, 279 | total: eDou.beanCount, 280 | change: eDou.beanChange, 281 | imgurl: data.url, 282 | } 283 | $store.put(evdou, 'evdou') 284 | } else { 285 | console.log(data) 286 | } 287 | } 288 | 289 | if (evdou.imgurl) { 290 | showChart(evdou.imgurl, evdou.userName, evdou.total, eDou.name) 291 | if (eDou.notify) { 292 | let body = evdou.userName + ': ' + evdou.total 293 | if (evdou.change) { 294 | body += '\n' + '近期收入:' + evdou.change[0].join(', ') 295 | body += '\n' + '近期支出:' + evdou.change[1].join(', ') 296 | } 297 | $feed.push(eDou.name, evdou.userName + ': ' + evdou.total, evdou.imgurl) 298 | } 299 | } 300 | })().catch(e=>console.log(e)) 301 | 302 | function showChart(imgurl, userName, total, title) { 303 | $evui({ 304 | title, 305 | width: 640, 306 | height: 389, 307 | content: `
${userName}: ${total}
`, 308 | style: { 309 | title: "background: #6B8E23;", 310 | content: "text-align: center" 311 | }, 312 | resizable: true, 313 | }).then(data=>console.log(data)).catch(e=>console.log(e)) 314 | } -------------------------------------------------------------------------------- /examples/JSTEST/exam-ahk-send.js: -------------------------------------------------------------------------------- 1 | // 通过 JS 配合 autohotkey 发送文字和按键信息 2 | 3 | $exec('sendkey.ahk "english or 中文 ^v ctrl+v is send"') -------------------------------------------------------------------------------- /examples/JSTEST/exam-ahk.js: -------------------------------------------------------------------------------- 1 | // 一个配合 autohotkey 移动鼠标的小脚本 2 | 3 | $exec('mousemove.ahk left', { 4 | cwd: './script/Shell' 5 | }) -------------------------------------------------------------------------------- /examples/JSTEST/exam-chcp.js: -------------------------------------------------------------------------------- 1 | const command = 'CHCP 65001' 2 | 3 | $exec(command, { 4 | cb(data, error){ 5 | error ? console.error(error) : console.log(data) 6 | } 7 | }) -------------------------------------------------------------------------------- /examples/JSTEST/exam-clipboard.js: -------------------------------------------------------------------------------- 1 | $exec('powershell -command "Get-Clipboard | echo"', { 2 | cb(data, error){ 3 | error ? console.error(error) : console.log(data) 4 | } 5 | }) -------------------------------------------------------------------------------- /examples/JSTEST/exam-rss.js: -------------------------------------------------------------------------------- 1 | // 使用 cheerio 解析 rss 的小例子 2 | // iOS 限免软件推送。需要先设置好 IFTTT 3 | 4 | const feedurl = 'https://rsshub.app/telegram/channel/BaccanoSoul/%23%E9%99%90%E5%85%8D%E6%9B%B4%E6%96%B0%E6%9D%BFiOS' 5 | // rss 来源: https://docs.rsshub.app/ 6 | 7 | $axios(feedurl).then(res=>{ 8 | const $ = $cheerio.load(res.data, { 9 | xml: { 10 | normalizeWhitespace: true, 11 | xmlMode: true, 12 | }, 13 | }) 14 | const pubDate = $('item pubDate').eq(0).text() 15 | console.log('last item publish date:', pubDate) 16 | const lastdate = new Date(pubDate).getTime() 17 | const laststore = $store.get('lastrss') 18 | if (laststore && laststore >= lastdate) { 19 | console.log('no new item') 20 | return 21 | } 22 | $store.put(lastdate, 'lastrss') 23 | const items = $('item') 24 | for (var i = 0; i < items.length; i++) { 25 | const itemdate = new Date($('pubDate', items[i]).text()).getTime() 26 | if (laststore && laststore >= itemdate) { 27 | return 28 | } 29 | const title = $('title', items[i]).text().split(' ¥') 30 | console.log('new item', title) 31 | const description = $('description', items[i]).text() 32 | const content = $cheerio.load(description) 33 | const link = content('a[href*=apple]').attr('href') 34 | $feed.ifttt(title[0], title[1], link) 35 | console.log(content.text()) 36 | } 37 | console.log('all new item pushed') 38 | }).catch(e=>console.error(e.stack)) -------------------------------------------------------------------------------- /examples/JSTEST/exam-tasksub.js: -------------------------------------------------------------------------------- 1 | // 通过 webhook 添加定时任务订阅。运行前根据具体情况修改 suburl 和 webhook 里面的内容 2 | // 每次运行都会添加新任务,请不要多次运行 3 | // 这只是一个简单的范例,如果出现未知问题,手动修正一下代码 4 | 5 | const suburl = 'https://raw.githubusercontent.com/nzw9314/QuantumultX/master/Task_Remote.conf' 6 | 7 | const webhook = { 8 | url: '/webhook', // 远程: http://sss.xxxx.com/webhook 9 | token: 'a8c259b2-67fe-4c64-8700-7bfdf1f55cb3', // 在 webUI->SETTING 界面查找 10 | } 11 | 12 | $axios(suburl).then(res=>{ 13 | const body = res.data 14 | const mastr = body.matchAll(/([0-9\-\*\/]+ [0-9\-\*\/]+ [0-9\-\*\/]+ [0-9\-\*\/]+ [0-9\-\*\/]+( [0-9\-\*\/]+)?) ([^ ,]+), ?tag=([^, \n\r]+)/g) 15 | 16 | ;[...mastr].forEach(mr=>{ 17 | if (mr[3] && mr[1]) { 18 | $axios({ 19 | url: webhook.url, 20 | method: 'post', 21 | data: { 22 | token: webhook.token, 23 | type: 'taskadd', 24 | task: { 25 | name: mr[4] || 'tasksub-新的任务', 26 | type: 'cron', 27 | job: { 28 | type: 'runjs', 29 | target: mr[3], 30 | }, 31 | time: mr[1], 32 | running: true // 是否自动执行添加的任务 33 | } 34 | } 35 | }).then(res=>console.log(res.data)) 36 | } 37 | }) 38 | }).catch(e=>console.error(e)) -------------------------------------------------------------------------------- /examples/JSTEST/example-cheerio.js: -------------------------------------------------------------------------------- 1 | // a simply $cheerio eaxmple. modify from cheerio readme.md 2 | 3 | const $ = $cheerio.load(`
    4 |
  • Apple
  • 5 |
  • Orange
  • 6 |
  • Pear
  • 7 |
`); 8 | 9 | const apple = $('.apple', '#fruits').text() 10 | console.log(apple) 11 | 12 | const attr = $('ul .pear').attr('class'); 13 | console.log(attr) 14 | 15 | const html = $('#fruits').html(); 16 | console.log(html) 17 | 18 | $done($('.pear').text()) -------------------------------------------------------------------------------- /examples/JSTEST/example-rule.js: -------------------------------------------------------------------------------- 1 | // a example for rule 2 | 3 | // $request.headers, $request.body, $request.method, $request.hostname, $request.port, $request.path, $request.url 4 | // $response.headers, $response.body, $response.statusCode 5 | 6 | let body = $response.body 7 | // let obj = JSON.parse(body) 8 | if (/httpbin/.test($request.url)) { 9 | body += 'change by elecV2P' + body 10 | } 11 | $done({ body }) -------------------------------------------------------------------------------- /examples/JSTEST/fendtest.efh: -------------------------------------------------------------------------------- 1 | efh fend 测试 2 |

efh - elecV2P favend html, 一个同时包含前后端运行代码的 html 扩展格式。

3 |

目前仅可运行于 elecV2P favend, 相关说明参考:elecV2P-dei/efss.md 相关部分

4 |
5 | 6 | 7 | 8 |
9 |

10 | 11 | https://raw.githubusercontent.com/elecV2/elecV2P/master/script/JSFile/elecV2P.efh 12 |

13 | 14 | 26 | 27 | -------------------------------------------------------------------------------- /examples/JSTEST/github-subdownload.js: -------------------------------------------------------------------------------- 1 | // 功能: github 子目录文件下载(仅适用于 elecV2P 2 | // 作者: https://t.me/elecV2 3 | // 文件地址: https://raw.githubusercontent.com/elecV2/elecV2P/master/script/JSFile/github-subdownload.js 4 | // 最近更新: 2022-10-05 5 | 6 | const config = { 7 | repos: $env.repos || 'elecV2/elecV2P-dei', // github 仓库名。比如 elecV2/elecV2P 8 | folder: $env.folder || 'examples/JSTEST', // 子目录。比如 script/JSFile 9 | dest: $env.dest || 'script/JSFile', // 下载到此目录。 10 | options: { 11 | recursive: $env.recursive ?? true, // 是否下载 folder 下的子目录文件 12 | onlyreg: $env.onlyreg || '', // 只下载文件名满足该正则表达式的文件 13 | skipreg: $env.skipreg || '', // 跳过下载文件名满足该正则表达式的文件 14 | sizemax: $env.sizemax || 0, // 当文件大小超过此设置值时,不下载。0: 表示不限制 15 | } 16 | } 17 | 18 | getTree(`https://api.github.com/repos/${config.repos}/contents/${config.folder}`).then(tree=>{ 19 | main(tree, config.dest, config.options) 20 | }).catch(e=>console.error(e.message)) 21 | 22 | async function getTree(apigit) { 23 | try { 24 | console.log('start get', apigit, 'tree') 25 | return await $axios(apigit).then(res=>res.data) 26 | } catch(e) { 27 | console.error('get', apigit, 'error', e.message) 28 | return [] 29 | } 30 | } 31 | 32 | async function main(tree, dest, options = { recursive: true, onlyreg: '', skipreg: '', sizemax: 0 }) { 33 | if (!(typeof tree === 'object' && tree.length > 0 && typeof dest === 'string')) { 34 | console.log('输入参数有误', tree, dest) 35 | return 36 | } 37 | const onlyreg = new RegExp(options.onlyreg), skipreg = new RegExp(options.skipreg) 38 | for (let file of tree) { 39 | if (file.type === 'file') { 40 | if (options.sizemax > 0 && file.size > options.sizemax) { 41 | console.log('skip download', file.name, 'file size:', file.size, 'is big than', options.sizemax) 42 | continue 43 | } 44 | if (options.onlyreg) { 45 | if (!onlyreg.test(file.name)) { 46 | console.log('skip download', file.name, 'for onlyreg', onlyreg) 47 | continue 48 | } 49 | } 50 | if (options.skipreg) { 51 | if (skipreg.test(file.name)) { 52 | console.log('skip download', file.name, 'for skipreg', skipreg) 53 | continue 54 | } 55 | } 56 | 57 | mulDownload(file['download_url'], dest, file.name) 58 | } else { 59 | if (options.recursive) { 60 | await main(await getTree(file.url), dest + '/' + file.name, options) 61 | } else { 62 | console.log(`不下载 ${file.name}, 类型:${file.type}`) 63 | } 64 | } 65 | } 66 | } 67 | 68 | // 简异版多线程下载 69 | let count = 0, todownlist = []; 70 | function mulDownload(url, dest, name) { 71 | if (count > 5) { 72 | todownlist.push([url, dest, name]) 73 | return 74 | } 75 | count++ 76 | console.log('当前下载文件数:', count, '等待下载数:', todownlist.length) 77 | $download(url, { 78 | folder: dest, 79 | name, existskip: true, 80 | }, (d) => { 81 | if (d.progress) { 82 | console.log(d.progress + '\r\x1b[F') 83 | } 84 | }).then(res=>{ 85 | console.log(name, '下载结果', res) 86 | }).catch(e=>{ 87 | console.error(name, '下载错误', e.message || e) 88 | }).finally(()=>{ 89 | count-- 90 | if (todownlist.length) { 91 | mulDownload(...todownlist.shift()) 92 | } else if (count === 0) { 93 | console.log('所有文件下载完成(如有错误或漏下,可以重新运行一次脚本)') 94 | } else { 95 | console.log('当前下载文件数:', count) 96 | } 97 | }) 98 | } -------------------------------------------------------------------------------- /examples/JSTEST/markdown.efh: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | a simple markdown reader 12 | 15 | 16 | 17 |
18 | 19 | 20 | 21 |
22 |
23 | 24 | 88 | 94 | 95 | -------------------------------------------------------------------------------- /examples/JSTEST/reboot.js: -------------------------------------------------------------------------------- 1 | // 系统重启脚本,谨慎使用,无法取消 2 | 3 | const countdown = 30 // 重启等待时间,单位:秒 4 | console.log('操作系统将在', countdown, '后重启') 5 | 6 | setTimeout(()=>{ 7 | $exec('reboot', data=>console.log(data)) 8 | }, countdown*1000) -------------------------------------------------------------------------------- /examples/JSTEST/simple.efh: -------------------------------------------------------------------------------- 1 |

一个简单的 efh 格式示例文件

2 |
3 | 4 | 19 | 20 | -------------------------------------------------------------------------------- /examples/JSTEST/starturl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * windows 上通过默认浏览器打开对应 url. 3 | */ 4 | 5 | $exec('start https://github.com/elecV2/elecV2P', {}) -------------------------------------------------------------------------------- /examples/JSTEST/tgbotmessage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 功能:使用TG bot 给频道或他人发信息 3 | * 使用方法: 4 | * 先使用 https://t.me/BotFather 创建一个机器人,获取 bot token 5 | * 然后获取目标用户的 chatid,填写到下面对应位置。 然后start bot 6 | * 7 | * 如果要发送到频道,先将机器人拉到频道并给予管理员权限 8 | * 9 | * cron 8 8 8 * * * https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/examples/JSTEST/tgbotmessage.js 10 | */ 11 | 12 | 13 | const CONFIG = { 14 | chatid: '8xxxxxxxxxx', // 接受信息的用户 id 15 | token: '8161xxx-xxxxxx' // tg bot took 16 | } 17 | 18 | // message 可根据自己的需求进行修改,支持 markdown 语法 19 | let message = `[必应随机壁纸](https://bing.ioliu.cn/v1/rand?${Date.now()})` // api 来源: https://github.com/xCss/bing 20 | 21 | 22 | const payload = { 23 | "method": "sendMessage", 24 | "chat_id": CONFIG.chatid, 25 | "parse_mode": "markdown", 26 | "disable_web_page_preview": false, 27 | "text": 'hello world!' 28 | } 29 | 30 | payload.text = message 31 | 32 | const myRequest = { 33 | url: `https://api.telegram.org/bot${CONFIG.token}/`, 34 | method: 'POST', 35 | headers: { 36 | 'Content-Type': 'application/json;charset=UTF-8' 37 | }, 38 | body: JSON.stringify(payload) 39 | } 40 | 41 | $task.fetch(myRequest).then(res => { 42 | try { 43 | let body = JSON.parse(res.body) 44 | if (body.ok) { 45 | let result = body.result 46 | console.log('send', result.chat.username, result.chat.first_name, result.chat.last_name, 'message:', result.text) 47 | } else { 48 | console.log(body) 49 | } 50 | } catch { 51 | console.log(res.body) 52 | } 53 | }, error => { 54 | console.log(error) 55 | }) -------------------------------------------------------------------------------- /examples/JSTEST/webonlinetest.js: -------------------------------------------------------------------------------- 1 | // 网站是否在线监控 2 | 3 | url = 'https://github.com/favicon.ico' // 监控网址 4 | 5 | new Promise(resolve => { 6 | let note = '' 7 | $axios(url).then(res=>{ 8 | if (res.status !== 200) { 9 | $feed.ifttt('网站下线 - ' + res.status, '网址:' + url) 10 | console.log('网站下线', url, res.status) 11 | note = `网站下线 - ${res.status} ${url}` 12 | } else { 13 | console.log(url, '稳定运行中') 14 | note = url + ' 稳定运行中' 15 | } 16 | }).catch(e=>{ 17 | $feed.ifttt(e.message, '无法访问网站: ' + url) 18 | console.log('无法访问网站', url, e.message) 19 | note = '无法访问网站: ' + url + e.message 20 | }).finally(()=>{ 21 | resolve(note) 22 | }) 23 | }) -------------------------------------------------------------------------------- /examples/Readme.md: -------------------------------------------------------------------------------- 1 | ## 主要用于一些测试和备份(仅供参考) 2 | 3 | ### [JSTEST](https://github.com/elecV2/elecV2P-dei/tree/master/examples/JSTEST) 4 | 5 | 一些测试 JS 文件,比如: 6 | 7 | - [boxjs.ev.js](https://github.com/elecV2/elecV2P-dei/blob/master/examples/JSTEST/boxjs.ev.js) \- boxjs elecV2P 兼容版 (v3.2.3 版本后可直接使用 chavyleung 的原版) 8 | 9 | ![](https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/examples/res/boxjs-test.png) 10 | 11 | - [github-subdownload.js](https://github.com/elecV2/elecV2P-dei/blob/master/examples/JSTEST/github-subdownload.js) \- github 子目录文件下载 12 | - [exam-rss.js](https://github.com/elecV2/elecV2P-dei/blob/master/examples/JSTEST/exam-rss.js) \- 使用 cheerio 解析 rss 实现限免软件推送 13 | - [reboot.js](https://github.com/elecV2/elecV2P-dei/blob/master/examples/JSTEST/reboot.js) \- 通过 JS 重启服务器 14 | - [evui-dou.js](https://github.com/elecV2/elecV2P-dei/blob/master/examples/JSTEST/evui-dou.js) \- 在前端网页显示京东豆收支图表 15 | 16 | ![](https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/examples/res/evuidou.png) 17 | 18 | 等等 19 | 20 | *如果有其他比较好玩或有用的脚本,欢迎 Pull Request* 21 | 22 | ### efh 实际应用系列 23 | 24 | 关于 efh 格式文件的说明,参考说明文档 [08-logger&efss.md](https://github.com/elecV2/elecV2P-dei/blob/master/docs/08-logger&efss.md) 中的相关部分。 25 | 26 | - [markdown.efh](https://github.com/elecV2/elecV2P-dei/blob/master/examples/JSTEST/efh/markdown.efh) \- 一个简单的 markdown 阅读器 27 | 28 | - [notepad.efh](https://github.com/elecV2/elecV2P-dei/blob/master/examples/JSTEST/efh/notepad.efh) \- 一个简单的云端记事本 29 | - [kuwo-music.efh](https://github.com/elecV2/elecV2P-dei/blob/master/examples/JSTEST/efh/kuwo-music.efh) \- 酷我音乐下载 30 | 31 | - [其他 efh 脚本](https://github.com/elecV2/elecV2P-dei/tree/master/examples/JSTEST/efh) 32 | 33 | ### [TGbotonCFworker.js](https://github.com/elecV2/elecV2P-dei/blob/master/examples/TGbotonCFworker.js) - 通过 TG bot 控制 elecV2P 34 | 35 | 2.0 版本(新增上下文执行环境): https://github.com/elecV2/elecV2P-dei/blob/master/examples/TGbotonCFworker2.0.js 36 | 37 | ![](https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/examples/res/tgbot.png) 38 | 39 | 可实现功能:(所有操作可在 telegram 上完成) 40 | - 运行 JS 41 | - 获取/删除 日志 42 | - 获取服务内存占用信息 43 | - 获取定时任务信息 44 | - 开始/暂停 定时任务 45 | - 删除/保存 定时任务 46 | - 执行 shell 指令 47 | - store/cookie 常量管理 48 | 49 | 前提: elecV2P 服务器可通过外网访问 50 | 51 | 具体使用见脚本内注释内容 -------------------------------------------------------------------------------- /examples/Shell/aria2c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elecV2/elecV2P-dei/6b4673acd0c0aae76e5e84efd23d73b63d35f3d9/examples/Shell/aria2c -------------------------------------------------------------------------------- /examples/Shell/elecV2P-runjs.ahk: -------------------------------------------------------------------------------- 1 | ; 功能: 2 | ; 使用 win + j 快捷键快速执行选择代码或远程 JS 3 | ; 使用: (提前安装好 autohotkey) 4 | ; 1. 修改 webhook url 和 token 为 elecV2P 实际运行值 5 | ; 2. 通过 autohotkey 运行该脚本 6 | ; 3. 选择一段 JS 代码(比如:console.log("a autokey test");$result="hello ahk"),然后按 win+j。 相关代码会上传到 elecV2P 并执行,并返回相关结果。 7 | ; -. 也可以选择一个远程 JS 链接(比如:https://raw.githubusercontent.com/elecV2/elecV2P/master/script/JSFile/webhook.js),然后按 win+j。 elecV2P 会自动执行远程 JS,并返回相关结果 8 | 9 | #j:: 10 | webhook := "http://127.0.0.1/webhook" ; or https://remote.xxxx.com/webhook 11 | token := "a8c259b2-67fe-4c64-8700-7bfdf1f55cb3" 12 | 13 | Send, ^c ; 复制选择内容 14 | if clipboard = "" 15 | return 16 | clipboard := RegExReplace(clipboard, """", "\""") 17 | clipboard := RegExReplace(clipboard, "`r`n|`r|`n", "\n") 18 | if (RegExMatch(url, "^http")){ 19 | body = {"token":"%token%", "type":"runjs", "fn":"%clipboard%"} 20 | } else { 21 | body = {"token":"%token%", "type":"runjs", "rawcode":"%clipboard%"} 22 | } 23 | req(webhook, "POST", body) 24 | Return 25 | 26 | Req(url, method, body) { 27 | WinHTTP := ComObjCreate("WinHTTP.WinHttpRequest.5.1") 28 | ;~ WinHTTP.SetProxy(0) 29 | ; MsgBox % body 30 | WinHTTP.Open(method, url) 31 | WinHTTP.SetRequestHeader("Content-Type", "application/json;charset=utf-8") 32 | WinHTTP.Send(body) 33 | Result := WinHTTP.ResponseText 34 | Status := WinHTTP.Status 35 | 36 | msgbox % "status: " status "`n`nresult: " result 37 | } -------------------------------------------------------------------------------- /examples/Shell/exam-request.py: -------------------------------------------------------------------------------- 1 | import requests, json 2 | 3 | re = requests.get("http://httpbin.org/json") 4 | # re.encoding = 'UTF-8' 5 | 6 | jsre = json.loads(re.text) 7 | print(jsre) -------------------------------------------------------------------------------- /examples/Shell/mousemove.ahk: -------------------------------------------------------------------------------- 1 | ; 通过附带参数移动鼠标。 windows 平台使用,且已安装好 autohotkey 2 | ; 示例: 3 | ; mousemove.ahk left 400 ; 鼠标左移 400 Pixel 4 | ; mousemove.ahk click 300 400 4 ; 在屏幕 300,400 的位置点击鼠标 4 次 5 | 6 | ; MsgBox Parameter number %1% 7 | 8 | if %1% 9 | direction = %1% 10 | else 11 | direction := "left" 12 | 13 | if %2% 14 | movestep = %2% 15 | else 16 | movestep := 30 17 | 18 | if (direction = "left") 19 | MouseMove, -movestep, 0, 0, R 20 | else if (direction = "right") 21 | MouseMove, movestep, 0, 0, R 22 | else if (direction = "up") 23 | MouseMove, 0, -movestep, 0, R 24 | else if (direction = "down") 25 | MouseMove, 0, movestep, 0, R 26 | else if (direction = "click") 27 | MouseClick, left, %2%, %3%, %4% -------------------------------------------------------------------------------- /examples/Shell/sendkey.ahk: -------------------------------------------------------------------------------- 1 | #NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases. 2 | ; #Warn ; Enable warnings to assist with detecting common errors. 3 | SendMode Input ; Recommended for new scripts due to its superior speed and reliability. 4 | SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory. 5 | 6 | ; 发送按键的小脚本 7 | ; senkey.ahk "english or 中文 ^v ctrl+v is send" 8 | 9 | Send, %1% -------------------------------------------------------------------------------- /examples/TGbotonCFworker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 说明:可部署到 cloudfalre worker 的 TGbot 后台代码,用于通过 telegram 查看/控制 elecV2P 3 | * 地址:https://github.com/elecV2/elecV2P-dei/blob/master/examples/TGbotonCFworker.js 4 | * (该版本基本不再更新,最新功能见 2.0 版本 https://github.com/elecV2/elecV2P-dei/blob/master/examples/TGbotonCFworker2.0.js) 5 | * 6 | * 使用方式: 7 | * 先申请好 TG BOT(https://t.me/botfather),然后设置好 CONFIG 内容 8 | * tgbot token: 在 telegram botfather 中找到 api token, 然后填写到相应位置 9 | * 然后把修改后的整个 JS 内容粘贴到 cloudfalre worker 代码框,保存即可。得到一个类似 https://xx.xxxxx.workers.dev 的网址 10 | * 接着使用 https://api.telegram.org/bot(你的 tgbot token)/setWebhook?url=https://xx.xxxxx.workers.dev 给 tg bot 添加 webhook,部署完成 11 | * 最后,打开 tgbot 对话框,输入下面的相关指令,测试 TGbot 是否成功 12 | * 13 | * *假如返回数据有问题,先直接访问 elecV2P webhook 看是否正常。http://你的 elecV2P 服务器地址/webhook?token=你的webhook token&type=status* 14 | * 15 | * 实现功能及相关指令: 16 | * 查看服务器资源使用状态 17 | * status === /status ;任何包含 status 关键字的指令 18 | * 19 | * 删除 log 文件 20 | * /delete file === /delete file.js.log === /del file 21 | * /delete all ;删除使用 log 文件 22 | * 23 | * 查看 log 文件 24 | * /log file === file === file.js.log 25 | * all ;返回所有 log 文件列表 26 | * 27 | * 任务相关 28 | * /taskinfo taskid ;获取任务信息 29 | * /taskinfo all ;获取所有任务信息 30 | * /taskstart taskid ;开始任务 31 | * /taskstop taskid ;停止任务 32 | * /taskdel taskid ;删除任务 33 | * /tasksave ;保存当前任务列表 34 | * 35 | * 脚本相关 36 | * /listjs ;列出所有 JS 脚本。 37 | * /runjs file.js ;运行脚本 38 | * /runjs https://raw.githubusercontent.com/elecV2/elecV2P/master/script/JSFile/webhook.js 39 | * /deljs file.js ;删除脚本 40 | * 41 | * bot commands 42 | runjs - runjs 43 | deljs - delete js 44 | listjs - list all js 45 | status - memory usage status 46 | tasksave - save task 47 | taskinfo - get task info 48 | taskstop - stop a task 49 | taskstart - start a task 50 | taskdel - delete a task 51 | delete - delete logs 52 | log - get log file 53 | **/ 54 | 55 | const CONFIG_EV2P = { 56 | url: "http://你的 elecV2P 服务器地址/", // elecV2P 服务器地址(必须是域名,cf worker 不支持 IP 直接访问) 57 | wbrtoken: 'xxxxxx-xxxxxxxxxxxx-xxxx', // elecV2P 服务器 webhook token(在 webUI->SETTING 界面查看) 58 | token: "xxxxxxxx:xxxxxxxxxxxxxxxxxxx", // teleram bot token 59 | slice: -800, // 截取日志最后 800 个字符,以防太长无法传输(可自行调整) 60 | userid: null // 只对该 userid 发出的指令进行回应。null:回应所有用户的指令 61 | } 62 | 63 | if (!CONFIG_EV2P.url.endsWith('/')) { 64 | CONFIG_EV2P.url = CONFIG_EV2P.url + '/' 65 | } 66 | 67 | function getLogs(s){ 68 | return new Promise((resolve,reject)=>{ 69 | fetch(CONFIG_EV2P.url + 'webhook?token=' + CONFIG_EV2P.wbrtoken + '&type=getlog&fn=' + s).then(res=>res.text()).then(r=>{ 70 | resolve(r) 71 | }).catch(e=>{ 72 | reject(e) 73 | }) 74 | }) 75 | } 76 | 77 | function delLogs(logn) { 78 | return new Promise((resolve,reject)=>{ 79 | fetch(CONFIG_EV2P.url + 'webhook?token=' + CONFIG_EV2P.wbrtoken + '&type=deletelog&fn=' + logn).then(res=>res.text()).then(r=>{ 80 | resolve(r) 81 | }).catch(e=>{ 82 | reject(e) 83 | }) 84 | }) 85 | } 86 | 87 | function getStatus() { 88 | return new Promise((resolve,reject)=>{ 89 | fetch(CONFIG_EV2P.url + 'webhook?type=status&token=' + CONFIG_EV2P.wbrtoken).then(res=>res.text()).then(r=>{ 90 | resolve(r) 91 | }).catch(e=>{ 92 | reject(e) 93 | }) 94 | }) 95 | } 96 | 97 | function getTaskinfo(tid) { 98 | return new Promise((resolve,reject)=>{ 99 | fetch(CONFIG_EV2P.url + 'webhook?token=' + CONFIG_EV2P.wbrtoken + '&type=taskinfo&tid=' + tid).then(res=>res.text()).then(r=>{ 100 | resolve(r) 101 | }).catch(e=>{ 102 | reject(e) 103 | }) 104 | }) 105 | } 106 | 107 | function opTask(tid, op) { 108 | if (!/start|stop|del|delete/.test(op)) { 109 | return 'unknow operation' + op 110 | } 111 | return new Promise((resolve,reject)=>{ 112 | fetch(CONFIG_EV2P.url + 'webhook?token=' + CONFIG_EV2P.wbrtoken + '&type=task' + op + '&tid=' + tid).then(res=>res.text()).then(r=>{ 113 | resolve(r) 114 | }).catch(e=>{ 115 | reject(e) 116 | }) 117 | }) 118 | } 119 | 120 | function saveTask() { 121 | return new Promise((resolve,reject)=>{ 122 | fetch(CONFIG_EV2P.url + 'webhook?token=' + CONFIG_EV2P.wbrtoken + '&type=tasksave').then(res=>res.text()).then(r=>{ 123 | resolve(r) 124 | }).catch(e=>{ 125 | reject(e) 126 | }) 127 | }) 128 | } 129 | 130 | function jsRun(fn) { 131 | if (!fn.startsWith('http') && !/\.js$/.test(fn)) fn += '.js' 132 | return new Promise((resolve,reject)=>{ 133 | fetch(CONFIG_EV2P.url + 'webhook?token=' + CONFIG_EV2P.wbrtoken + '&type=runjs&fn=' + fn).then(res=>res.text()).then(r=>{ 134 | resolve(r) 135 | }).catch(e=>{ 136 | reject(e) 137 | }) 138 | }) 139 | } 140 | 141 | function getJsLists() { 142 | return new Promise((resolve,reject)=>{ 143 | fetch(CONFIG_EV2P.url + 'jsmanage?token=' + CONFIG_EV2P.wbrtoken).then(res=>res.json()).then(r=>{ 144 | resolve(r.jslists.join(' ') + '\ntotal: ' + r.jslists.length) 145 | }).catch(e=>{ 146 | reject(e) 147 | }) 148 | }) 149 | } 150 | 151 | function deleteJS(name) { 152 | return new Promise((resolve,reject)=>{ 153 | fetch(CONFIG_EV2P.url + 'jsfile?token=' + CONFIG_EV2P.wbrtoken, { 154 | method: 'DELETE', 155 | headers: { 156 | 'Content-Type': 'application/json' 157 | }, 158 | body: JSON.stringify({ 159 | jsfn: name 160 | }) 161 | }).then(res=>res.text()).then(r=>{ 162 | resolve(r) 163 | }).catch(e=>{ 164 | reject(e) 165 | }) 166 | }) 167 | } 168 | 169 | async function handlePostRequest(request) { 170 | let bodyString = await readRequestBody(request) 171 | 172 | try { 173 | let body = JSON.parse(bodyString); 174 | 175 | if (body.message) { 176 | let payload = { 177 | "method": "sendMessage", 178 | "chat_id": body.message.chat.id, 179 | "parse_mode": "html", 180 | "disable_web_page_preview": true, 181 | }; 182 | if (body.message.text) { 183 | let bodytext = body.message.text 184 | if (CONFIG_EV2P.userid && body.message.chat.id !== CONFIG_EV2P.userid ) { 185 | payload.text = "check the project: https://github.com/elecV2/elecV2P" 186 | } else if (/^\/?status/.test(bodytext)) { 187 | payload.text = await getStatus() 188 | } else if (/^\/?(del|delete) /.test(bodytext)) { 189 | let cont = bodytext.split(' ').pop() 190 | if (!(cont === 'all' || /\.log$/.test(cont))) cont = cont + '.js.log' 191 | payload.text = await delLogs(cont) 192 | } else if (/^\/?taskinfo /.test(bodytext)) { 193 | let cont = bodytext.split(' ').pop() 194 | payload.text = await getTaskinfo(cont) 195 | } else if (/\.log$/.test(bodytext) || /^\/?log /.test(bodytext)) { 196 | let cont = bodytext.split(' ').pop() 197 | if (!/\.log$/.test(cont)) cont = cont + '.js.log' 198 | payload.text = await getLogs(cont) 199 | } else if (/^\/?taskstart /.test(bodytext)) { 200 | let cont = bodytext.split(' ').pop() 201 | payload.text = await opTask(cont, 'start') 202 | } else if (/^\/?taskstop /.test(bodytext)) { 203 | let cont = bodytext.split(' ').pop() 204 | payload.text = await opTask(cont, 'stop') 205 | } else if (/^\/?taskdel /.test(bodytext)) { 206 | let cont = bodytext.split(' ').pop() 207 | payload.text = await opTask(cont, 'del') 208 | } else if (/^\/?tasksave/.test(bodytext)) { 209 | payload.text = await saveTask() 210 | } else if (/^\/?listjs/.test(bodytext)) { 211 | payload.text = await getJsLists() 212 | } else if (/^\/?deljs /.test(bodytext)) { 213 | let cont = bodytext.split(' ').pop() 214 | payload.text = await deleteJS(cont) 215 | } else if (/^\/?runjs /.test(bodytext)) { 216 | let cont = bodytext.split(' ').pop() 217 | payload.text = await jsRun(cont) 218 | } else if (/^\/?all/.test(bodytext)) { 219 | bodytext = 'all' 220 | let res = await getLogs(bodytext) 221 | let map = JSON.parse(res) 222 | let keyb = { 223 | keyboard:[ 224 | [ 225 | { text: 'all - ' + map.length }, 226 | { text: 'status' } 227 | ] 228 | ], 229 | resize_keyboard: false, 230 | one_time_keyboard: true, 231 | selective: true 232 | } 233 | 234 | map.forEach((s, ind)=> { 235 | let row = parseInt(ind/2) + 1 236 | keyb.keyboard[row] 237 | ? keyb.keyboard[row].push({ 238 | text: s.replace(/\.js\.log$/g, '') 239 | }) 240 | : keyb.keyboard[row] = [{ 241 | text: s.replace(/\.js\.log$/g, '') 242 | }] 243 | }) 244 | payload.text = "点击查看日志" 245 | payload.reply_markup = keyb 246 | } else { 247 | payload.text = 'TGbot 部署成功,可以使用相关指令和 elecV2P 服务器进行交互了\nPowered By: https://github.com/elecV2/elecV2P\n\n频道: @elecV2 | 群组: @elecV2G' 248 | } 249 | 250 | const myInit = { 251 | method: 'POST', 252 | headers: { 253 | 'Content-Type': 'application/json;charset=UTF-8' 254 | }, 255 | body: JSON.stringify(payload) 256 | }; 257 | 258 | let myRequest = new Request(`https://api.telegram.org/bot${CONFIG_EV2P.token}/`, myInit) 259 | 260 | fetch(myRequest).then(function(x) { 261 | console.log(x); 262 | }); 263 | return new Response("OK") 264 | } else { 265 | return new Response("OK") 266 | } 267 | } else { 268 | return new Response(JSON.stringify(body), { 269 | headers: { 'content-type': 'application/json' }, 270 | }) 271 | } 272 | } catch(e) { 273 | return new Response(e) 274 | } 275 | } 276 | 277 | async function handleRequest(request) { 278 | let retBody = `The request was a GET ` 279 | return new Response(retBody) 280 | } 281 | 282 | addEventListener('fetch', event => { 283 | const { request } = event 284 | if (request.method === 'POST') { 285 | return event.respondWith(handlePostRequest(request)) 286 | } else if (request.method === 'GET') { 287 | return event.respondWith(handleRequest(request)) 288 | } 289 | }) 290 | 291 | /** 292 | * readRequestBody reads in the incoming request body 293 | * Use await readRequestBody(..) in an async function to get the string 294 | * @param {Request} request the incoming request to read from 295 | */ 296 | async function readRequestBody(request) { 297 | const { headers } = request 298 | const contentType = headers.get('content-type') 299 | if (contentType.includes('application/json')) { 300 | const body = await request.json() 301 | return JSON.stringify(body) 302 | } else if (contentType.includes('application/text')) { 303 | const body = await request.text() 304 | return body 305 | } else if (contentType.includes('text/html')) { 306 | const body = await request.text() 307 | return body 308 | } else if (contentType.includes('form')) { 309 | const formData = await request.formData() 310 | let body = {} 311 | for (let entry of formData.entries()) { 312 | body[entry[0]] = entry[1] 313 | } 314 | return JSON.stringify(body) 315 | } else { 316 | let myBlob = await request.blob() 317 | var objectURL = URL.createObjectURL(myBlob) 318 | return objectURL 319 | } 320 | } -------------------------------------------------------------------------------- /examples/archive/Caddyfile: -------------------------------------------------------------------------------- 1 | { 2 | http_port 80 3 | } 4 | 5 | http://e2p.xxxxxxx.com { 6 | log stdout 7 | encode gzip 8 | reverse_proxy 127.0.0.1:8100 { 9 | header_up Host {http.reverse_proxy.upstream.hostport} 10 | } 11 | } 12 | 13 | http://dtest.xxxxxxx.com { 14 | log stdout 15 | reverse_proxy 127.0.0.1:8101 { 16 | # header_up Host {http.reverse_proxy.upstream.hostport} 17 | } 18 | } 19 | 20 | http://test.xxxxxxx.com { 21 | log stdout 22 | encode gzip 23 | reverse_proxy * 127.0.0.1:8102 { 24 | # 请求头Host设置 25 | header_up Host {http.reverse_proxy.upstream.hostport} 26 | # 请求头transparent设置 27 | header_up X-Real-IP {http.request.remote.host} 28 | header_up X-Forwarded-For {http.request.remote.host} 29 | header_up X-Forwarded-Port {http.request.port} 30 | header_up X-Forwarded-Proto {http.request.scheme} 31 | } 32 | } -------------------------------------------------------------------------------- /examples/archive/dht.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elecV2/elecV2P-dei/6b4673acd0c0aae76e5e84efd23d73b63d35f3d9/examples/archive/dht.dat -------------------------------------------------------------------------------- /examples/docker-compose-clash.yaml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | services: 3 | elecv2p: 4 | image: elecv2/elecv2p 5 | container_name: elecv2p 6 | restart: always 7 | logging: 8 | driver: "json-file" 9 | options: 10 | max-size: "10m" 11 | max-file: "3" 12 | environment: 13 | - TZ=Asia/Shanghai 14 | ports: 15 | - "8100:80" 16 | - "8101:8001" 17 | - "8102:8002" 18 | volumes: 19 | - "/elecv2p/JSFile:/usr/local/app/script/JSFile" 20 | - "/elecv2p/Lists:/usr/local/app/script/Lists" 21 | - "/elecv2p/Store:/usr/local/app/script/Store" 22 | - "/elecv2p/Shell:/usr/local/app/script/Shell" 23 | - "/elecv2p/rootCA:/usr/local/app/rootCA" 24 | - "/elecv2p/efss:/usr/local/app/efss" 25 | 26 | clash: 27 | image: elecv2/clash 28 | container_name: clash 29 | restart: always 30 | ports: 31 | - "8008:8008" 32 | - "8090:8090" 33 | volumes: 34 | - "/clash/config.yaml:/clash/config.yaml" -------------------------------------------------------------------------------- /examples/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | services: 3 | elecv2p: 4 | image: elecv2/elecv2p 5 | container_name: elecv2p 6 | restart: always 7 | logging: 8 | driver: "json-file" 9 | options: 10 | max-size: "10m" 11 | max-file: "3" 12 | environment: 13 | - TZ=Asia/Shanghai 14 | ports: 15 | - "8100:80" 16 | - "8101:8001" 17 | - "8102:8002" 18 | volumes: 19 | - "/elecv2p/JSFile:/usr/local/app/script/JSFile" 20 | - "/elecv2p/Lists:/usr/local/app/script/Lists" 21 | - "/elecv2p/Store:/usr/local/app/script/Store" 22 | - "/elecv2p/Shell:/usr/local/app/script/Shell" 23 | - "/elecv2p/rootCA:/usr/local/app/rootCA" 24 | - "/elecv2p/efss:/usr/local/app/efss" -------------------------------------------------------------------------------- /examples/ev2p-nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name e2p.xxxxxxx.com; 4 | location / { 5 | proxy_pass http://127.0.0.1:8100; 6 | } 7 | 8 | // websocket 9 | location /elecV2P { 10 | proxy_pass http://127.0.0.1:8100; 11 | proxy_http_version 1.1; 12 | proxy_set_header Upgrade $http_upgrade; 13 | proxy_set_header Connection "upgrade"; 14 | 15 | proxy_connect_timeout 36000s; 16 | proxy_send_timeout 36000s; 17 | proxy_read_timeout 36000s; 18 | } 19 | } 20 | 21 | server { 22 | listen 80; 23 | server_name dtest.xxxxxxx.com; 24 | location / { 25 | proxy_set_header Host $host; 26 | proxy_set_header X-Real-IP $remote_addr; 27 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 28 | proxy_pass http://localhost:8101; 29 | proxy_redirect off; 30 | } 31 | } 32 | 33 | server { 34 | listen 80; 35 | server_name test.xxxxxxx.com; 36 | location / { 37 | proxy_pass http://127.0.0.1:8102; 38 | proxy_set_header Host $host; 39 | proxy_set_header X-Real-IP $remote_addr; 40 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 41 | 42 | # WebSocket support 43 | proxy_http_version 1.1; 44 | proxy_set_header Upgrade $http_upgrade; 45 | proxy_set_header Connection "upgrade"; 46 | } 47 | } -------------------------------------------------------------------------------- /examples/res/boxjs-test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elecV2/elecV2P-dei/6b4673acd0c0aae76e5e84efd23d73b63d35f3d9/examples/res/boxjs-test.jpg -------------------------------------------------------------------------------- /examples/res/cookieadd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elecV2/elecV2P-dei/6b4673acd0c0aae76e5e84efd23d73b63d35f3d9/examples/res/cookieadd.png -------------------------------------------------------------------------------- /examples/res/evuidou.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elecV2/elecV2P-dei/6b4673acd0c0aae76e5e84efd23d73b63d35f3d9/examples/res/evuidou.png -------------------------------------------------------------------------------- /examples/res/evuiplayer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elecV2/elecV2P-dei/6b4673acd0c0aae76e5e84efd23d73b63d35f3d9/examples/res/evuiplayer.png -------------------------------------------------------------------------------- /examples/res/holdrequest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elecV2/elecV2P-dei/6b4673acd0c0aae76e5e84efd23d73b63d35f3d9/examples/res/holdrequest.png -------------------------------------------------------------------------------- /examples/res/holdrespose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elecV2/elecV2P-dei/6b4673acd0c0aae76e5e84efd23d73b63d35f3d9/examples/res/holdrespose.png -------------------------------------------------------------------------------- /examples/res/holdresults.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elecV2/elecV2P-dei/6b4673acd0c0aae76e5e84efd23d73b63d35f3d9/examples/res/holdresults.png -------------------------------------------------------------------------------- /examples/res/ifttt-test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elecV2/elecV2P-dei/6b4673acd0c0aae76e5e84efd23d73b63d35f3d9/examples/res/ifttt-test.jpg -------------------------------------------------------------------------------- /examples/res/jdcookie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elecV2/elecV2P-dei/6b4673acd0c0aae76e5e84efd23d73b63d35f3d9/examples/res/jdcookie.png -------------------------------------------------------------------------------- /examples/res/jdcookie2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elecV2/elecV2P-dei/6b4673acd0c0aae76e5e84efd23d73b63d35f3d9/examples/res/jdcookie2.png -------------------------------------------------------------------------------- /examples/res/rrtv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elecV2/elecV2P-dei/6b4673acd0c0aae76e5e84efd23d73b63d35f3d9/examples/res/rrtv.png -------------------------------------------------------------------------------- /examples/res/taskrun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elecV2/elecV2P-dei/6b4673acd0c0aae76e5e84efd23d73b63d35f3d9/examples/res/taskrun.png -------------------------------------------------------------------------------- /examples/res/tgbot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elecV2/elecV2P-dei/6b4673acd0c0aae76e5e84efd23d73b63d35f3d9/examples/res/tgbot.png -------------------------------------------------------------------------------- /examples/res/tgbotkv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elecV2/elecV2P-dei/6b4673acd0c0aae76e5e84efd23d73b63d35f3d9/examples/res/tgbotkv.png -------------------------------------------------------------------------------- /examples/theme/elecV2P_theme.20220420.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "我的主题", 4 | "mainbk": "#326733dd", 5 | "appbk": "url(https://images.unsplash.com/photo-1646505183416-f3301d2a8127)", 6 | "elebk": "#0006", 7 | "style": "" 8 | }, 9 | { 10 | "name": "主题常用", 11 | "mainbk": "#326733DD", 12 | "appbk": "url(https://cdn.pixabay.com/photo/2022/03/01/20/58/peace-genius-7042013_960_720.jpg)", 13 | "elebk": "#0003", 14 | "style": ".header, .footer {background: #3338;}" 15 | }, 16 | { 17 | "name": "暗黑简单", 18 | "mainbk": "#2E3784", 19 | "appbk": "", 20 | "elebk": "#000C", 21 | "style": "" 22 | }, 23 | { 24 | "name": "常用2", 25 | "mainbk": "#2E3784", 26 | "appbk": "url(https://images.unsplash.com/photo-1646505183416-f3301d2a8127)", 27 | "elebk": "#0000", 28 | "style": ".header, .footer {background: #3338;}" 29 | }, 30 | { 31 | "name": "椰树背景", 32 | "mainbk": "#2E3784", 33 | "appbk": "url(https://images.unsplash.com/photo-1649256651398-46408de2f095?auto=format&fit=crop&w=1964)", 34 | "elebk": "#0000", 35 | "style": "" 36 | }, 37 | { 38 | "name": "透明主题", 39 | "mainbk": "#0000", 40 | "appbk": "url(https://images.unsplash.com/photo-1646505183416-f3301d2a8127?auto=format)", 41 | "elebk": "#0000", 42 | "style": ".content>div,.elecBtn--long,.efssset_container,.efsslist{border: 1px solid var(--tras-bk);}.header,.footer,.efsslist_content .efssa{color: var(--main-cl);}.content .about,.content .donation{color: var(--main-fc)}.loginfo.loginfo--full{background: var(--secd-fc);}.logs_item{border: 1px solid;}" 43 | } 44 | ] -------------------------------------------------------------------------------- /examples/theme/readme.md: -------------------------------------------------------------------------------- 1 | ### elecV2P 测试主题 2 | 3 | ![elecV2P 测试主题](https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/docs/res/theme_preview_01.jpg) 4 | ![elecV2P 测试主题](https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/docs/res/theme_preview_02.png) 5 | ![elecV2P 测试主题](https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/docs/res/theme_preview_03.png) 6 | 7 | 一些用于 elecV2P 的测试主题。 8 | 9 | 使用方式 10 | 11 | 1. 下载该目录下的主题文件,比如 elecV2P_theme.json 12 | 2. 打开 elecV2P webUI,SETTING/设置->webUI 相关设置->导入常用主题,选择下载的主题文件 13 | 3. 点击**预览**进行查看,确定后点击**保存**正式启用 14 | 15 | *主题功能仅部分用户可用* -------------------------------------------------------------------------------- /information/readme.md: -------------------------------------------------------------------------------- 1 | ## elecV2P 活动详情 2 | 3 | 用于发布一些 elecV2P 活动规则 4 | 5 | [广告位招租](https://github.com/elecV2/elecV2P-dei/blob/master/information/广告位招租.md) 6 | 7 | [开发者激励计划](https://github.com/elecV2/elecV2P-dei/blob/master/information/开发者激励计划.md) -------------------------------------------------------------------------------- /information/res/dev_sponse_844x50t.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elecV2/elecV2P-dei/6b4673acd0c0aae76e5e84efd23d73b63d35f3d9/information/res/dev_sponse_844x50t.png -------------------------------------------------------------------------------- /information/res/gp_promo_844x50t.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elecV2/elecV2P-dei/6b4673acd0c0aae76e5e84efd23d73b63d35f3d9/information/res/gp_promo_844x50t.png -------------------------------------------------------------------------------- /information/res/sponse_alipay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elecV2/elecV2P-dei/6b4673acd0c0aae76e5e84efd23d73b63d35f3d9/information/res/sponse_alipay.png -------------------------------------------------------------------------------- /information/res/sponser_freebitco.in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elecV2/elecV2P-dei/6b4673acd0c0aae76e5e84efd23d73b63d35f3d9/information/res/sponser_freebitco.in.png -------------------------------------------------------------------------------- /information/res/sponsors_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elecV2/elecV2P-dei/6b4673acd0c0aae76e5e84efd23d73b63d35f3d9/information/res/sponsors_overview.png -------------------------------------------------------------------------------- /information/广告位招租.md: -------------------------------------------------------------------------------- 1 | ### 预览图 2 | 3 | ![elecV2P 广告位](https://raw.githubusercontent.com/elecV2/elecV2P-dei/master/information/res/sponsors_overview.png) 4 | 5 | ### 价格 6 | 7 | 平常价位: 8 | 9 | - a1 图片广告位 1800 元/月 10 | - a2 文字广告位 600 元/月 11 | 12 | 测试阶段(进行中...): 13 | 14 | - a1 图片广告位 600 元/月 15 | - a2 文字广告位 200 元/月 16 | 17 | **测试阶段最多租用 3 个月,开始时间:2022 年 4 月 1 日,结束时间待定** 18 | 19 | ### 广告展示时间 20 | 21 | 以北京时间为准,以月为单位。 22 | 23 | 比如 2022-04-01 开始展示广告,则展示的具体时间为 2022-04-01 00:00:00 到 2022-04-30 23:59:59。 24 | 如果 2022-05-14 开始,则展示的具体时间为 2022-05-14 00:00:00 到 2022-06-13 23:59:59。 25 | 26 | *假如出现特殊情况,导致广告掉线,将以天为单位补偿展示时间。* 27 | 28 | ### 需要提供的内容 29 | 30 | - 广告性质及简单说明 31 | - 显示图片或文字 32 | - 图片要求:长 600-1000 高 40-60 推荐 844x50 33 | - 文字要求:文字数不超过 20 34 | - 落地页链接 35 | 36 | ### 联系方式 37 | 38 | E-mail: elecV2#icloud.com (#->@) 39 | Telegram: @elecv7 40 | 41 | ### 其他说明 42 | 43 | - 落地页不可包含病毒类脚本 44 | - 落地页不可包含黄赌毒类非法内容 45 | - 广告推广期间,假如落地页内容有较大变更,请提前通知。如果在没有通知的情况,擅自大幅度更改落地页内容,开发者有权利直接下线广告,且费用不退 46 | - 长期优质赞助商可展示在 elecV2P 项目首页(Github) 47 | - 最终解释权归 elecV2P 开发者所有 48 | 49 | Telegram 通知频道:https://t.me/elecV2 -------------------------------------------------------------------------------- /information/开发者激励计划.md: -------------------------------------------------------------------------------- 1 | ## 简单说明 2 | 3 | 每个兼容 elecV2P 的脚本,给予脚本作者 10-100 元不等的人民币奖励。首期总金额 10000 元,发完即止。 4 | 5 | 截止时间:2022 年 6 月 30 号 6 | 7 | 本次活动每个作者最高奖励 200 元,可以把机会留给更多的人。 8 | 9 | *最终解释权归 elecV2P 开发者所有* 10 | 11 | ### 示例脚本 12 | 13 | elecV2P 默认自带的脚本:[elecV2P 默认脚本](https://github.com/elecV2/elecV2P/tree/master/script/JSFile) 14 | 15 | JS 脚本编写参考:[说明文档 04-JS.md](https://github.com/elecV2/elecV2P-dei/blob/master/docs/04-JS.md) 16 | 17 | 推荐编写 efh 脚本。 18 | 文档参考:[efss.md](https://github.com/elecV2/elecV2P-dei/blob/master/docs/08-logger&efss.md) 中 efh 相关部分。 19 | 实例脚本:[efh 测试脚本](https://github.com/elecV2/elecV2P-dei/tree/master/examples/JSTEST/efh) 20 | 21 | ### 脚本要求 22 | 23 | - 不可加密 24 | - 长期可用(至少一个月内有效,特殊情况下可放宽此限制) 25 | - 非 VIP 破解类 26 | - 脚本内注明:兼容 elecV2P 27 | 28 | ## 提交脚本 29 | 30 | - Github PR(推荐 31 | - https://github.com/elecV2/elecV2P-scripts 32 | - 提交格式/内容参考仓库 readme 中的相关说明 33 | - E-mail 提交 34 | - elecV2#icloud.com (#->@) 35 | - 标题格式:elecV2P 脚本提交-脚本名称-分类 36 | - 为避免冒领,请务必附带一张后台截图 37 | 38 | **暂时只接受远程脚本,假如脚本只有本地版本,请先 PR 到 https://github.com/elecV2/elecV2P-scripts scripts 目录** 39 | 40 | ## 奖励发放时间 41 | 42 | 脚本正式收录时间的下一个周五前。 43 | 比如这周星期一到星期日正式收录到仓库的脚本,将在下周五前发送奖励到指定账号。 44 | 45 | ### 其他说明 46 | 47 | - 最终解释权归 elecV2P 开发者所有 48 | - Telegram 通知频道:https://t.me/elecV2 --------------------------------------------------------------------------------