├── .github └── ISSUE_TEMPLATE │ ├── 🐛-错误报告---bug-report.md │ ├── 🙋-问题交流---question-report.md │ └── 🚀-功能请求---feature-request.md ├── LICENSE ├── Makefile ├── README.md ├── README_en.md ├── htdocs └── luci-static │ └── resources │ └── view │ └── wechatpush │ ├── advanced.js │ ├── client.js │ ├── config.js │ ├── log.js │ └── status.js ├── po └── zh_Hans │ └── wechatpush.po └── root ├── etc ├── config │ └── wechatpush ├── init.d │ └── wechatpush └── uci-defaults │ └── luci-wechatpush └── usr ├── libexec └── wechatpush-call └── share ├── luci └── menu.d │ └── luci-app-wechatpush.json ├── rpcd └── acl.d │ └── luci-app-wechatpush.json └── wechatpush ├── api ├── device_aliases.list ├── diy.json ├── ip_attribution.list ├── ip_blacklist ├── ipv4.list ├── ipv6.list ├── logo.jpg ├── msmtp.json ├── pushplus.json ├── qywx_markdown.json ├── qywx_mpnews.json ├── serverchan.json ├── serverchan3.json ├── telegram.json └── wxpusher.json └── wechatpush /.github/ISSUE_TEMPLATE/🐛-错误报告---bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B 错误报告 | Bug Report" 3 | about: 请详细描述您使用过程中遇到的问题。| Please describe in detail the problems you encountered in 4 | the process of using. 5 | title: "\"\U0001F41B 一些问题。。。 | [Bug] Some problem...\"" 6 | labels: bug 7 | assignees: '' 8 | 9 | --- 10 | 11 | 12 | 13 | #### 您使用的版本? | Your usage version? 14 | 15 | #### 您使用的场景? | Your usage scenarios? 16 | 17 | #### 您遇到了什么问题? | What are your problems? 18 | 19 | #### 您期望的结果是怎样的? | What is your expected outcome? 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/🙋-问题交流---question-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F64B 问题交流 | Question Report" 3 | about: 在文档或讨论中没有回答的使用问题 | Usage question that isn't answered in docs or discussion 4 | title: "\"\U0001F64B 问题交流。。。 | [Question] Some question...\"" 5 | labels: help wanted 6 | assignees: '' 7 | 8 | --- 9 | 10 | - 搜索打开和关闭的 [GitHub 问题](https://github.com/eryajf/go-ldap-admin/issues) 11 | 12 | 请在提交问题之前回答这些问题,谢谢。 | Please answer these questions before submitting them. Thank you. 13 | 14 | ### 你使用了哪个版本? | Which version did you use? 15 | 16 | ### 预期行为 | Expected behavior 17 | 18 | ### 实际行为 | Actual behavior 19 | 20 | ### 原因分析(如果可以) | Cause analysis (if possible) 21 | 22 | ### 问题重现步骤 | Steps to reproduce the problem 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/🚀-功能请求---feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F680 功能请求 | Feature Request" 3 | about: 请详细描述您期望的功能。 | Please describe in detail the features you expect. 4 | title: "\"\U0001F680 一些功能。。。 | [Feature]Some feature...\"" 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | #### 您使用的场景? | 1. Your usage scenarios? 13 | 14 | #### 您期望的结果是怎样的? | 2. What is your expected outcome? 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include $(TOPDIR)/rules.mk 2 | 3 | PKG_NAME:=luci-app-wechatpush 4 | PKG_VERSION:=3.6.9 5 | PKG_RELEASE:= 6 | 7 | PKG_MAINTAINER:=tty228 8 | PKG_CONFIG_DEPENDS:= \ 9 | CONFIG_PACKAGE_$(PKG_NAME)_Enable_Traffic_Monitoring \ 10 | CONFIG_PACKAGE_$(PKG_NAME)_Enable_Local_Disk_Information_Detection \ 11 | CONFIG_PACKAGE_$(PKG_NAME)_Enable_Host_Information_Detection 12 | 13 | LUCI_TITLE:=LuCI support for wechatpush 14 | LUCI_PKGARCH:=all 15 | LUCI_DEPENDS:=+iputils-arping +curl +jq +bash +luci-lua-runtime \ 16 | +PACKAGE_$(PKG_NAME)_Enable_Traffic_Monitoring:wrtbwmon \ 17 | +PACKAGE_$(PKG_NAME)_Enable_Local_Disk_Information_Detection:lsblk \ 18 | +PACKAGE_$(PKG_NAME)_Enable_Local_Disk_Information_Detection:smartmontools \ 19 | +PACKAGE_$(PKG_NAME)_Enable_Local_Disk_Information_Detection:smartmontools-drivedb \ 20 | +PACKAGE_$(PKG_NAME)_Enable_Host_Information_Detection:openssh-client \ 21 | +PACKAGE_$(PKG_NAME)_Enable_Host_Information_Detection:openssh-keygen 22 | 23 | define Package/$(PKG_NAME)/config 24 | config PACKAGE_$(PKG_NAME)_Enable_Traffic_Monitoring 25 | bool "Enable Traffic Monitoring" 26 | help 27 | The traffic statistics feature relies on the wrtbwmon package. This plugin may conflict with Routing/NAT, Flow Offloading, and proxy internet access plugins, potentially leading to an inability to retrieve traffic information. 28 | select PACKAGE_wrtbwmon 29 | depends on PACKAGE_$(PKG_NAME) 30 | default n 31 | config PACKAGE_$(PKG_NAME)_Local_Disk_Information_Detection 32 | bool "Local Disk Information Detection" 33 | help 34 | If the lsblk package is not installed, the total disk capacity information might be inconsistent with actual values. When smartctl is not installed, information about disk temperature, power-on time, health status, and more will be unavailable. If you are using a virtual machine or have not installed a physical disk, this feature is typically unnecessary. 35 | select PACKAGE_lsblk 36 | select PACKAGE_smartmontools 37 | select PACKAGE_smartmontools-drivedb 38 | depends on PACKAGE_$(PKG_NAME) 39 | default n 40 | config PACKAGE_$(PKG_NAME)_Host_Information_Detection 41 | bool "Host Information Detection" 42 | help 43 | When using a virtual machine and requiring information about the host machine's temperature and disk details, you need to install openssh-client and openssh-keygen for SSH connections. 44 | select PACKAGE_openssh-client 45 | select PACKAGE_openssh-keygen 46 | depends on PACKAGE_$(PKG_NAME) 47 | default n 48 | endef 49 | 50 | define Package/$(PKG_NAME)/conffiles 51 | /etc/config/wechatpush 52 | /usr/share/wechatpush/api/diy.json 53 | /usr/share/wechatpush/api/logo.jpg 54 | /usr/share/wechatpush/api/ipv4.list 55 | /usr/share/wechatpush/api/ipv6.list 56 | /usr/share/wechatpush/api/device_aliases.list 57 | endef 58 | 59 | include $(TOPDIR)/feeds/luci/luci.mk 60 | 61 | # call BuildPackage - OpenWrt buildroot signature 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 3 | [![Lastest Release](https://img.shields.io/github/release/tty228/luci-app-wechatpush.svg?style=flat)](https://github.com/tty228/luci-app-wechatpush/releases) 4 | [![GitHub All Releases](https://img.shields.io/github/downloads/tty228/luci-app-wechatpush/total)](https://github.com/tty228/luci-app-wechatpush/releases) 5 | 6 | [中文文档](README.md) | [English](README_en.md) 7 | 8 | 这是一款用于 OpenWRT 路由器上进行 微信、Telegram、邮件 通知的插件。 9 | 10 | 主要功能: 11 | - [x] 路由 IP、IPv6 变动推送 12 | - [x] 设备 上线、离线 推送 13 | - [x] 设备在线列表及流量使用情况 14 | - [x] CPU 负载、温度监视、PVE 宿主机温度监控 15 | - [x] 路由运行状态定时推送 16 | - [x] 路由 Web、SSH 登录提示,自动拉黑、端口敲门 17 | - [x] 无人值守任务 18 | 19 | 通知服务支持列表: 20 | | 推送应用 | 方式 | 接口说明 | 21 | | :-------- | :----- | :----- | 22 | | 微信 | Server酱 | https://sct.ftqq.com/ 23 | | 微信 | 推送加 | http://www.pushplus.plus/ 24 | | 微信 | WxPusher | https://wxpusher.zjiecode.com/docs 25 | | 企业微信 | 应用推送 | https://work.weixin.qq.com/api/doc/90000/90135/90248 26 | | Telegram | bot | https://t.me/BotFather 27 | | Mail | msmtp | https://marlam.de/msmtp/ 28 | 29 | 精力有限,如需要钉钉推送、飞书推送、Bark 推送等请尝试另一个分支 https://github.com/zzsj0928/luci-app-pushbot ,或使用自定义 API 设置 30 | 31 | v2.06.2 之后的版本不再支持 LuCI 18.06,如需编译,请使用 openwrt-18.06 分支,拉取源码时请使用 `git clone -b openwrt-18.06 https://github.com/tty228/luci-app-wechatpush.git` 命令 32 | 33 | ## 说明 34 | 35 | **关于安装:** 36 | 37 | 插件依赖 iputils-arping + curl + jq + bash,对于内存有限的路由器,请酌情安装,**在安装之前,请先运行 `opkg update` 命令,以便在安装过程中安装依赖。** 38 | 39 | 基于 X86 OpenWrt v23.05.0 制作,不同系统不同设备,可能会遇到各种问题,**如获取到错误的温度信息、页面显示错误、报错等,自行适配** 40 | 41 | **关于主机名:** 42 | 43 | 对于设备未宣告主机名、光猫拨号上网、OpenWrt 作为旁路网关等各类情况导致的获取主机名失败,可以通过以下方式设置主机名 44 | 45 | - 使用设备名备注 46 | - 在高级设置处配置从光猫、小米路由器、ROS 获取 47 | - 开启 MAC 设备数据库 48 | - 安装 samba*-server 或 samba*-client,使程序可以通过 NetBIOS 查询主机名 49 | 50 | 51 | **关于设备在线状态:** 52 | 53 | 默认使用 ping/arping 来主动探测设备在线状态,以对抗 Wi-Fi 休眠机制,主动探测较为耗时但可以获得较为精准的设备在线状态 54 | 55 | - 如遇设备休眠频繁,请在高级设置处自行调整超时设置 56 | - 如果不需要太过精准的设备在线信息,只需要其余功能,可以在高级设置中关闭主动探测 57 | 58 | **关于流量统计信息:** 59 | 60 | 流量统计功能依赖 wrtbwmon ,需自行选装或编译,**该插件与 Routing/NAT 、Flow Offloading 、代理上网等插件冲突,开启后将会无法获取流量,请自行选择** 61 | 62 | **关于硬盘信息:** 63 | 64 | 当 OpenWrt 系统或远程主机(PVE)未安装 lsblk 时,硬盘容量信息可能与实际不一致 65 | 66 | 当 OpenWrt 系统或远程主机(PVE)未安装 smartctl 时,硬盘温度、通电时间、健康度等信息不可用 67 | 68 | **关于 bug 提交:** 69 | 70 | 提交 bug 时请尽量带上以下信息 71 | 72 | - 设备信息及插件版本号 73 | - 执行 `/usr/share/wechatpush/wechatpush` 后的提示信息 74 | - 报错后的日志信息、`/tmp/wechatpush/` 目录下的文件信息 75 | - `bash -x /usr/share/wechatpush/wechatpush t1` 的详细运行信息 76 | 77 | 78 | ## 下载 79 | 80 | | 支持的 OpenWrt 版本 | 下载地址 | 81 | | :-------- | :----- | 82 | | openwrt-19.07.0 ... latest | [![Lastest Release](https://img.shields.io/github/release/tty228/luci-app-wechatpush.svg?style=flat)](https://github.com/tty228/luci-app-wechatpush/releases) 83 | | openwrt-18.06 | [![Release v2.06.2](https://img.shields.io/badge/release-v2.06.2-lightgrey.svg)](https://github.com/tty228/luci-app-wechatpush/releases/tag/v2.06.2) 84 | 85 | 86 | ## 捐赠 87 | 88 | 如果你觉得此项目对你有帮助,请捐助我们,使项目能持续发展和更加完善。 89 | 90 | ![image](https://github.com/tty228/Python-100-Days/blob/master/res/WX.jpg) 91 | -------------------------------------------------------------------------------- /README_en.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | [![Lastest Release](https://img.shields.io/github/release/tty228/luci-app-wechatpush.svg?style=flat)](https://github.com/tty228/luci-app-wechatpush/releases) 4 | [![GitHub All Releases](https://img.shields.io/github/downloads/tty228/luci-app-wechatpush/total)](https://github.com/tty228/luci-app-wechatpush/releases) 5 | 6 | [中文文档](README.md) | [English](README_en.md) 7 | 8 | **OpenWrt Notification Plugin – Send Alerts to WeChat or Telegram** 9 | 10 | This OpenWrt plugin delivers real-time router notifications to your mobile device via **WeChat** or **Telegram** or **Mail**. Monitor your network with alerts for: 11 | 12 | - [x] IP changes (IPv4/IPv6) 13 | - [x] Device connections (online/offline) 14 | - [x] Online client list & traffic usage 15 | - [x] CPU load & temperature (including virtualized hosts like PVE) 16 | - [x] Router status reports 17 | - [x] Security alerts (failed web/SSH logins with auto blacklist) 18 | - [x] Port knocking & automated tasks 19 | 20 | Supported services: 21 | | Push application | Method | description | 22 | | :-------- | :----- | :----- | 23 | | WeChat | Server Chan | https://sct.ftqq.com/ 24 | | WeChat | PushPlus | http://www.pushplus.plus/ 25 | | WeChat | WxPusher | https://wxpusher.zjiecode.com/docs 26 | | WeChat for Enterprise | Application Push | https://work.weixin.qq.com/api/doc/90000/90135/90248 27 | | Telegram | bot | https://t.me/BotFather 28 | | Mail | msmtp | https://marlam.de/msmtp/ 29 | 30 | Limited resources are available. If you need services such as DingTalk push, Feishu push, Bark push, etc., please try another branch at https://github.com/zzsj0928/luci-app-pushbot, or use **custom API settings**. 31 | 32 | ## Instructions 33 | 34 | **Regarding Installation:** 35 | 36 | The plugin requires dependencies on iputils-arping + curl + jq + bash. For routers with limited memory, please consider the installation carefully. **Before installing, please run the opkg update command to install dependencies during the installation process.** 37 | 38 | Developed based on X86 OpenWrt v23.05.0, different systems and devices may encounter various issues. **If you encounter errors in temperature information retrieval, display errors, or other issues, please adapt accordingly.** 39 | 40 | **Regarding Hostnames:** 41 | 42 | For devices that do not declare hostnames, devices connected via optical modem dial-up, OpenWrt used as a bypass gateway, and other scenarios where hostname retrieval fails, you can set the hostname using the following methods: 43 | 44 | - Use device name remarks. 45 | - Configure to obtain the hostname from the optical modem in advanced settings. 46 | - Enable MAC device database. 47 | - Install samba*-server or samba*-client to enable the program to query hostnames via NetBIOS. 48 | 49 | 50 | **Regarding Device Online Status:** 51 | 52 | By default, ping/arping is used to actively detect device online status to counter Wi-Fi sleep mechanism. Active detection takes more time but provides more accurate device online status. 53 | 54 | - If devices frequently go into sleep mode, please adjust the timeout settings in advanced settings. 55 | - If you don't require highly precise device online information and only need other features, you can disable active detection in advanced settings. 56 | 57 | 58 | **Regarding Traffic Statistics:** 59 | 60 | Traffic statistics functionality depends on `wrtbwmon`. Please install or compile it yourself. **Enabling this plugin will conflict with Routing/NAT, Flow Offloading, proxy internet access, and other plugins, resulting in the inability to obtain traffic statistics. Please choose accordingly.** 61 | 62 | **About Hard Drive Information:** 63 | 64 | When the OpenWrt system or remote host (PVE) does not have lsblk installed, the hard drive capacity information may be inconsistent with the actual capacity. 65 | 66 | When the OpenWrt system or remote host (PVE) does not have smartctl installed, information such as hard drive temperature, uptime, and health status will not be available. 67 | 68 | **Regarding Bug Submissions:** 69 | 70 | When submitting a bug, please provide the following information if possible: 71 | 72 | - Device information and plugin version number. 73 | - Prompt information after executing `/usr/share/wechatpush/wechatpush`. 74 | - Log information and file information in the `/tmp/wechatpush/` directory after encountering an error. 75 | - Detailed execution information of `bash -x /usr/share/wechatpush/wechatpush t1`. 76 | 77 | ## DownLoad 78 | 79 | | Supported OpenWrt Versions | Download Link | 80 | | :-------- | :----- | 81 | | openwrt-19.07.0 ... latest | [![Lastest Release](https://img.shields.io/github/release/tty228/luci-app-wechatpush.svg?style=flat)](https://github.com/tty228/luci-app-wechatpush/releases) 82 | | openwrt-18.06 | [![Release v2.06.2](https://img.shields.io/badge/release-v2.06.2-lightgrey.svg)](https://github.com/tty228/luci-app-wechatpush/releases/tag/v2.06.2) 83 | 84 | ## Donate 85 | 86 | If you feel that this project is helpful to you, please donate to us so that the project can continue to develop and be more perfect. 87 | 88 | ![image](https://github.com/tty228/Python-100-Days/blob/master/res/WX.jpg) 89 | 90 | -------------------------------------------------------------------------------- /htdocs/luci-static/resources/view/wechatpush/advanced.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 'require view'; 3 | 'require fs'; 4 | 'require ui'; 5 | 'require uci'; 6 | 'require rpc'; 7 | 'require form'; 8 | 'require poll'; 9 | 10 | return view.extend({ 11 | callHostHints: rpc.declare({ 12 | object: 'luci-rpc', 13 | method: 'getHostHints', 14 | expect: { '': {} } 15 | }), 16 | 17 | load: function () { 18 | return Promise.all([ 19 | this.callHostHints(), 20 | fs.read('/proc/net/arp') 21 | ]); 22 | }, 23 | 24 | parseArp: function (data) { 25 | var lines = data.split('\n'), 26 | hosts = []; 27 | 28 | for (var i = 1; i < lines.length; i++) { 29 | var columns = lines[i].replace(/ +/g, ' ').split(' '); 30 | 31 | if (columns.length >= 6) { 32 | hosts.push({ 33 | ip: columns[0], 34 | mac: columns[3] 35 | }); 36 | } 37 | } 38 | 39 | // Sort hosts array by IP address 40 | hosts.sort(function (a, b) { 41 | var ipA = a.ip.split('.').map(Number); 42 | var ipB = b.ip.split('.').map(Number); 43 | 44 | for (var i = 0; i < 4; i++) { 45 | if (ipA[i] !== ipB[i]) { 46 | return ipA[i] - ipB[i]; 47 | } 48 | } 49 | 50 | return 0; 51 | }); 52 | 53 | return hosts; 54 | }, 55 | 56 | formatHostIPMAC: function (host) { 57 | return host.ip + ' (' + host.mac + ')'; 58 | }, 59 | 60 | formatHostMACIP: function (host) { 61 | return host.mac + ' (' + host.ip + ')'; 62 | }, 63 | 64 | render: function (data) { 65 | var arpData = data[1], 66 | hosts = this.parseArp(arpData), 67 | m, s, o, 68 | programPath = '/usr/share/wechatpush/wechatpush'; 69 | 70 | m = new form.Map('wechatpush', _('')) 71 | m.description = _("If you are not familiar with the meanings of these options, please do not modify them.

") 72 | 73 | s = m.section(form.NamedSection, 'config', 'wechatpush', _('')); 74 | s.anonymous = true 75 | s.addremove = false 76 | 77 | o = s.option(form.Flag, "passive_mode", _("Disable active detection")) 78 | o.default = 0 79 | o.rmempty = true 80 | o.description = _("Disable active detection of client online status. Enabling this feature will no longer prompt device online/offline events.
Suitable for users who are not sensitive to online devices but need other features.") 81 | 82 | o = s.option(form.Value, "thread_num", _('Maximum concurrent processes')) 83 | o.placeholder = "3" 84 | o.datatype = "uinteger" 85 | o.rmempty = false; 86 | o.description = _("Do not change the setting value for low-performance devices, or reduce the parameters as appropriate.") 87 | 88 | o = s.option(form.ListValue, "defaultSortColumn", _("Client list sorting method")) 89 | o.default = "ip" 90 | o.value("ip", _("IP")) 91 | o.value("uptime", _("Online time")) 92 | o.description = _("This will change the sorting method for both the online device list page and the sorting order in the push content.") 93 | 94 | o = s.option(form.Value, "soc_code", _('Custom temperature reading command')) 95 | o.rmempty = true 96 | o.value("", _("Default")) 97 | o.value("pve", _("Proxmox Virtual Environment")) 98 | o.description = _("If you need to use special symbols such as quotes, $, !, etc. in custom commands, you need to escape them yourself.
You can use the command eval echo $(uci get wechatpush.wechatpush.soc_code) to view command output and error information.
The execution result should be a pure number (including decimals) for temperature comparison.
Here is an example that does not require escaping:
cat /sys/class/thermal/thermal_zone0/temp|sort -nr|head -n1|cut -c-2") 99 | 100 | o = s.option(form.Value, "server_host", _("Host machine address")) 101 | o.rmempty = true 102 | o.default = "10.0.0.2" 103 | o.depends('soc_code', 'pve'); 104 | 105 | o = s.option(form.Value, "server_port", _("Host machine SSH port")) 106 | o.rmempty = true 107 | o.default = "22" 108 | o.description = _('The default SSH port is 22. If you have a custom port, please fill in the custom SSH port.
Please make sure you have set up key-based login, otherwise it may cause script errors.
Install the sensors command on PVE by searching on the internet.
Example for key-based login (modify the address and port number accordingly):
opkg update # Update package list
opkg install openssh-client openssh-keygen # Install openssh client
echo -e \"\\n\" | ssh-keygen -t rsa # Generate key file (no passphrase)
pve_host=`uci get wechatpush.config.server_host` || pve_host=\"10.0.0.3\" # Read the PVE host address from the configuration file, If not saved, please fill in by yourself.
pve_port=`uci get wechatpush.config.server_port` || pve_host=\"22\" # Read the PVE host SSH port number from the configuration file, If not saved, please fill in by yourself.
ssh -o StrictHostKeyChecking=yes root@${pve_host} -p ${pve_port} \"tee -a ~/.ssh/OpenWrt_id_rsa.pub\" < ~/.ssh/id_rsa.pub # Transfer public key to PVE
ssh root@${pve_host} -p ${pve_port} \"cat ~/.ssh/OpenWrt_id_rsa.pub >> ~/.ssh/authorized_keys\" # Write public key to PVE
ssh -i /root/.ssh/id_rsa root@${pve_host} -p ${pve_port} sensors # To avoid script errors during the initial connection, please use a private key to connect to PVE and test the temperature command for its proper functioning.
For users who frequently flash firmware, please add /root/.ssh/ to the backup list to avoid duplicate operations.'); 109 | o.depends('soc_code', 'pve'); 110 | 111 | o = s.option(form.Button, '_soc', _('Test temperature command'), _('You may need to save the configuration before sending.')); 112 | o.inputstyle = 'action'; 113 | o.onclick = function () { 114 | var _this = this; 115 | return fs.exec(programPath, ['soc']).then(function (res) { 116 | if (!res.stdout) { 117 | throw new Error(_('Returned value is empty')); 118 | } 119 | _this.description = res.stdout.trim(); 120 | return _this.map.reset(); 121 | }).catch(function (err) { 122 | _this.description = _('Fetch failed:') + err.message; 123 | return _this.map.reset(); 124 | }); 125 | }; 126 | 127 | o = s.option(form.Value, 'up_timeout', _('Device online detection timeout (s)')); 128 | o.placeholder = "2" 129 | o.optional = false 130 | o.datatype = "uinteger" 131 | o.rmempty = false; 132 | o.depends('passive_mode', '0'); 133 | 134 | o = s.option(form.Value, "down_timeout", _('Device offline detection timeout (s)')) 135 | o.placeholder = "10" 136 | o.optional = false 137 | o.datatype = "uinteger" 138 | o.rmempty = false; 139 | o.depends('passive_mode', '0'); 140 | 141 | o = s.option(form.Value, "timeout_retry_count", _('Offline detection count')) 142 | o.placeholder = "2" 143 | o.optional = false 144 | o.datatype = "uinteger" 145 | o.rmempty = false; 146 | o.description = _("If the device has good signal strength and no Wi-Fi sleep issues, you can reduce the above values.
Due to the mysterious nature of Wi-Fi sleep during the night, if you encounter frequent disconnections, please adjust the parameters accordingly.
..╮(╯_╰)╭..") 147 | o.depends('passive_mode', '0'); 148 | 149 | o = s.option(form.Flag, "only_timeout_push", _("Offline timeout applies only to the devices that receive push notifications")) 150 | o.default = 0 151 | o.rmempty = true 152 | o.description = _("When this option is selected, the offline timeout and offline detection count apply only to the devices that require push notifications. Other devices will use default values, which can significantly reduce the time required for detection. However, it may result in inaccurate online time displayed in the online devices list. It is recommended to enable this option only when there are many devices and frequent offline occurrences are observed for specific devices of interest.") 153 | o.depends('passive_mode', '0'); 154 | 155 | o = s.option(form.DynamicList, 'always_check_ip_list', _('IP address to always scan')); 156 | o.datatype = 'ipaddr'; 157 | o.description = _('The IPs in the list are always subjected to online detection regardless of whether they exist in the ARP list, suitable for secondary routing scenarios.'); 158 | hosts.forEach(function (host) { 159 | o.value(host.ip, this.formatHostIPMAC(host)); 160 | }, this); 161 | o.depends('passive_mode', '0'); 162 | 163 | o = s.option(form.MultiValue, 'device_info_helper', _('Assist in obtaining device information')); 164 | o.value('gateway_info', _('Retrieve hostname list from modem')); 165 | o.value('miwifi_info', _('Get wireless band information and hostname from MiWiFi')); 166 | o.value('mikrotik_info', _('Retrieve hostname list from modem MikroTik Router')); 167 | o.value('openwrt_info', _('Get wireless band information and hostname from other OpenWrt')); 168 | o.value('scan_local_ip', _('Scan local IP')); 169 | o.modalonly = true; 170 | o.description = _('When OpenWrt is used as a bypass gateway and cannot obtain device hostnames or a complete list of local network devices.
the \"Retrieve hostname list from modem\" option has only been tested with HG5143F/HN8145V China Telecom gateways and may not be universally applicable.
The \"Scan local IP\" option may not retrieve hostnames, so please use device name annotations in conjunction with it.'); 171 | o.depends('passive_mode', '0'); 172 | 173 | o = s.option(form.Value, "gateway_host_url", _('Optical modem login URL')); 174 | o.rmempty = true; 175 | o.default = "http://192.168.1.1/cgi-bin/luci"; 176 | o.depends({ device_info_helper: "gateway_info", '!contains': true }); 177 | 178 | o = s.option(form.Value, "gateway_info_url", _('Device list JSON URL')); 179 | o.rmempty = true; 180 | o.default = "http://192.168.1.1/cgi-bin/luci/admin/allInfo"; 181 | o.description = _('Use F12 console to capture
ip, devName, model are mandatory fields. Example JSON file information:
{\"pc1\":{\"devName\":\"RouterOS\",\"model\":\"\",\"type\":\"pc\",\"ip\":\"192.168.1.7\"}}'); 182 | o.depends({ device_info_helper: "gateway_info", '!contains': true }); 183 | 184 | o = s.option(form.Value, "gateway_logout_url", _('Optical modem logout URL')) 185 | o.rmempty = true 186 | o.default = "http://192.168.1.1/cgi-bin/luci/admin/logout" 187 | o.description = _("Not a mandatory field, but it may affect other users logging into the web management page, e.g., HG5143F") 188 | o.depends({ device_info_helper: "gateway_info", '!contains': true }); 189 | 190 | o = s.option(form.Value, "gateway_username_id", _('Login page account input box ID')) 191 | o.rmempty = true 192 | o.default = "username" 193 | o.depends({ device_info_helper: "gateway_info", '!contains': true }); 194 | 195 | o = s.option(form.Value, "gateway_password_id", _('Login page password input box ID')) 196 | o.rmempty = true 197 | o.default = "psd" 198 | o.description = _("Right-click in the browser and select 'Inspect Element'") 199 | o.depends({ device_info_helper: "gateway_info", '!contains': true }); 200 | 201 | o = s.option(form.Value, "gateway_username", _('Optical modem login account')) 202 | o.rmempty = true 203 | o.default = "useradmin" 204 | o.depends({ device_info_helper: "gateway_info", '!contains': true }); 205 | 206 | o = s.option(form.Value, "gateway_password", _('Optical modem login password')) 207 | o.rmempty = true 208 | o.description = _("Use a regular account, no need for super password") 209 | o.depends({ device_info_helper: "gateway_info", '!contains': true }); 210 | 211 | o = s.option(form.Value, "miwifi_ip", _('MiWiFi IP Address')); 212 | o.rmempty = true; 213 | o.description = _("The main router address is all that is needed in the Mesh wireless network topology.") 214 | o.depends({ device_info_helper: "miwifi_info", '!contains': true }); 215 | 216 | o = s.option(form.Value, "miwifi_password", _('MiWiFi Login Password')) 217 | o.rmempty = true 218 | o.depends({ device_info_helper: "miwifi_info", '!contains': true }); 219 | 220 | o = s.option(form.Value, "mikrotik_ip", _('MikroTik Routers IP Address')); 221 | o.rmempty = true; 222 | o.description = _('echo -e "\\n" | ssh-keygen -t rsa -f /root/.ssh/id_rsa -N ""
scp /root/.ssh/id_rsa.pub your_username@mikrotik_ip:/id_rsa.pub
ssh your_username@mikrotik_ip
/user ssh-keys import public-key-file=id_rsa.pub user=your_username') 223 | o.depends({ device_info_helper: "mikrotik_info", '!contains': true }); 224 | 225 | o = s.option(form.Value, "mikrotik_username", _('MikroTik Router Account')) 226 | o.rmempty = true 227 | o.depends({ device_info_helper: "mikrotik_info", '!contains': true }); 228 | 229 | o = s.option(form.DynamicList, "op_host_ips", _('OpenWrt IP Address')); 230 | o.rmempty = true; 231 | o.description = _('echo -e "\\n" | ssh-keygen -t rsa -f /root/.ssh/id_rsa -N ""
ssh root@your_openwrt_ip "mkdir -p /root/.ssh && chmod 700 /root/.ssh && echo $(cat /root/.ssh/id_rsa.pub) >> /etc/dropbear/authorized_keys && chmod 600 /etc/dropbear/authorized_keys"') 232 | o.depends({ device_info_helper: "openwrt_info", '!contains': true }); 233 | 234 | o = s.option(form.Value, "scan_ip_range", _('IP range to be scanned')) 235 | o.rmempty = true 236 | o.placeholder = _('192.168.1.1-100'); 237 | o.depends({ device_info_helper: "scan_local_ip", '!contains': true }); 238 | 239 | o = s.option(form.Value, 'device_info_helper_sleeptime', _('Interval for capturing info')); 240 | o.rmempty = false; 241 | o.placeholder = '600'; 242 | o.datatype = 'and(uinteger,min(60))' 243 | o.description = _("Generally, frequent capturing is not necessary. Adjust it as needed.") 244 | o.depends({ device_info_helper: "gateway_info", '!contains': true }); 245 | o.depends({ device_info_helper: "miwifi_info", '!contains': true }); 246 | o.depends({ device_info_helper: "mikrotik_info", '!contains': true }); 247 | o.depends({ device_info_helper: "openwrt_info", '!contains': true }); 248 | o.depends({ device_info_helper: "scan_local_ip", '!contains': true }); 249 | 250 | o = s.option(form.Flag, "unattended_enable", _("Unattended tasks")) 251 | o.default = 0 252 | o.rmempty = true 253 | o.description = _("Please make sure the script can run properly, otherwise it may cause frequent restarts and other errors!") 254 | 255 | o = s.option(form.Flag, 'zerotier_helper', _('Restart zerotier after IP change')); 256 | o.description = _('An old issue with zerotier
Cannot reconnect after disconnection, emmm, I don\'t know if it has been fixed now.'); 257 | o.depends('unattended_enable', '1'); 258 | 259 | o = s.option(form.Flag, "unattended_only_on_disturb_time", _("Redial only during Do-Not-Disturb period")) 260 | o.default = 0 261 | o.rmempty = true 262 | o.description = _("Avoid redialing network during the day to prevent waiting for DDNS domain resolution. This feature does not affect disconnection detection.
Due to the issue of certain apps consuming excessive data at night, this feature may be unstable.") 263 | o.depends('unattended_enable', '1'); 264 | 265 | o = s.option(form.DynamicList, 'unattended_device_aliases', _('Followed device list')); 266 | o.datatype = 'macaddr'; 267 | o.description = _("Will only be executed when none of the devices in the list are online.
After an hour of Do-Not-Disturb period, if the devices in the focus list have low traffic (around 100kb/m) for five minutes, they will be considered offline.") 268 | o.depends('unattended_enable', '1'); 269 | 270 | hosts.forEach(function (host) { 271 | o.value(host.mac, this.formatHostMACIP(host)); 272 | }, this); 273 | 274 | o = s.option(form.ListValue, "network_disconnect_event", _("When the network is disconnected")) 275 | o.default = "" 276 | o.value("", _("No operation")) 277 | o.value("1", _("Restart the router")) 278 | o.value("2", _("Redialing network")) 279 | o.description = _("The restart operation will occur ten minutes after the network disconnection and will be attempted a maximum of two times. If the option to log in to the optical modem is available, this operation will attempt to restart the optical modem.
【!!This feature cannot guarantee compatibility!!】") 280 | o.depends('unattended_enable', '1'); 281 | 282 | o = s.option(form.ListValue, "unattended_autoreboot_mode", _("Scheduled reboot")) 283 | o.default = "" 284 | o.value("", _("No operation")) 285 | o.value("1", _("Restart the router")) 286 | o.value("2", _("Redialing network")) 287 | o.depends('unattended_enable', '1'); 288 | 289 | o = s.option(form.Value, "autoreboot_system_uptime", _("System uptime greater than")) 290 | o.rmempty = true 291 | o.default = "24" 292 | o.datatype = "uinteger" 293 | o.description = _("Unit: hours") 294 | o.depends('unattended_autoreboot_mode', '1'); 295 | 296 | o = s.option(form.Value, "autoreboot_network_uptime", _("Network uptime greater than")) 297 | o.rmempty = true 298 | o.default = "24" 299 | o.datatype = "uinteger" 300 | o.description = _("Unit: hours") 301 | o.depends('unattended_autoreboot_mode', '2'); 302 | 303 | return m.render(); 304 | } 305 | }); 306 | -------------------------------------------------------------------------------- /htdocs/luci-static/resources/view/wechatpush/client.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 'require view'; 3 | 'require fs'; 4 | 'require ui'; 5 | 'require poll'; 6 | 'require uci'; 7 | 8 | return view.extend({ 9 | load: function () { 10 | var self = this; 11 | // 清除 localStorage 中的排序设置 12 | localStorage.removeItem('sortColumn'); 13 | localStorage.removeItem('sortDirection'); 14 | uci.load('wechatpush'); 15 | return this.fetchAndRenderDevices().then(function () { 16 | self.setupAutoRefresh(); 17 | }); 18 | }, 19 | 20 | fetchAndRenderDevices: function () { 21 | var self = this; 22 | return this.fetchDevices().then(function (data) { 23 | var container = self.render(data); 24 | self.switchContent(container); 25 | }).catch(function (error) { 26 | console.error('Error fetching or rendering devices:', error); 27 | }); 28 | }, 29 | 30 | fetchDevices: function () { 31 | var devices_path = '/tmp/wechatpush/devices.json'; 32 | return fs.read(devices_path).then(function (content) { 33 | try { 34 | var data = JSON.parse(content); 35 | var wlanMap = {}; 36 | 37 | // 如果存在无线接口信息,解析为频段 38 | if (data.wlan && Array.isArray(data.wlan)) { 39 | data.wlan.forEach(function (wlan) { 40 | wlanMap[wlan.interface] = wlan.band; 41 | }); 42 | } 43 | 44 | // 解析设备的接口信息 45 | data.devices.forEach(function (device) { 46 | if (device.type) { 47 | device.interface = device.type; 48 | } else if (wlanMap[device.interface]) { 49 | device.interface = wlanMap[device.interface]; 50 | } else { 51 | device.interface = "LAN"; 52 | } 53 | }); 54 | return { devices: data.devices }; 55 | } catch (e) { 56 | console.error('Error parsing JSON:', e); 57 | return { devices: [] }; 58 | } 59 | }); 60 | }, 61 | 62 | render: function (data) { 63 | if (!data || !data.devices || !Array.isArray(data.devices)) { 64 | return document.createElement('div'); 65 | } 66 | var devices = data.devices.filter(device => device.status === 'online' || device.status === 'unknown'); 67 | var totalDevices = devices.length; 68 | var headers = [_('Hostname'), _('IPv4 address'), _('MAC address'), _('Interfaces'), _('Connection Point'), _('Online time'), _('Details')]; 69 | var columns = ['name', 'ip', 'mac', 'interface', 'parent', 'uptime', 'usage']; 70 | var visibleColumns = []; 71 | var hasData = false; 72 | 73 | // 获取配置中的默认排序列 74 | var defaultSortColumn = uci.get('wechatpush', 'config', 'defaultSortColumn') || 'ip'; 75 | var defaultSortDirection = (defaultSortColumn === 'uptime') ? 'desc' : 'asc'; 76 | 77 | // 获取存储的排序设置,如果没有则使用默认设置 78 | var storedSortColumn = localStorage.getItem('sortColumn'); 79 | var storedSortDirection = localStorage.getItem('sortDirection'); 80 | 81 | var currentSortColumn = storedSortColumn || defaultSortColumn; 82 | var currentSortDirection = storedSortDirection || defaultSortDirection; 83 | 84 | devices.sort(function (a, b) { 85 | return compareDevices(a, b, currentSortColumn, currentSortDirection); 86 | }); 87 | 88 | // 根据数据源决定可见列 89 | for (var i = 0; i < columns.length; i++) { 90 | var column = columns[i]; 91 | var hasColumnData = false; 92 | 93 | // 特殊处理 parent 列 94 | if (column === 'parent') { 95 | var hasNonLocalParent = false; 96 | for (var j = 0; j < devices.length; j++) { 97 | var parentValue = devices[j][column]; 98 | if (parentValue && parentValue !== "Local") { 99 | hasNonLocalParent = true; 100 | break; 101 | } 102 | } 103 | // 如果存在非 "Local" 的 parent 值,则显示该列 104 | if (hasNonLocalParent) { 105 | visibleColumns.push(i); 106 | } 107 | } else { 108 | // 其他列的正常逻辑 109 | for (var j = 0; j < devices.length; j++) { 110 | if (devices[j][column] !== undefined && devices[j][column] !== '') { 111 | hasColumnData = true; 112 | hasData = true; 113 | break; 114 | } 115 | } 116 | if (hasColumnData) { 117 | visibleColumns.push(i); 118 | } 119 | } 120 | } 121 | 122 | var style = ` 123 | /* 设备表格样式 */ 124 | .device-table { 125 | width: 80%; /* 表格宽度占满父容器 */ 126 | border-collapse: collapse; /* 合并边框 */ 127 | margin-top: 10px; /* 顶部外边距 */ 128 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* 阴影效果 */ 129 | border-radius: 8px; /* 圆角边框 */ 130 | overflow: hidden; /* 内容溢出隐藏 */ 131 | } 132 | 133 | .device-table th, 134 | .device-table td { 135 | padding: 10px; /* 单元格内边距 */ 136 | text-align: center; /* 文本居中 */ 137 | border: 1px solid #ddd; /* 边框样式 */ 138 | } 139 | 140 | .device-table th { 141 | background-color: rgba(0, 0, 0, 0.05); /* 表头背景色,透明 */ 142 | font-weight: bold; /* 粗体字体 */ 143 | cursor: pointer; /* 鼠标指针样式为指针 */ 144 | position: relative; /* 相对定位 */ 145 | } 146 | 147 | .device-table th.sortable::after { 148 | right: 10px; /* 右侧距离 */ 149 | top: 50%; /* 顶部偏移50% */ 150 | transform: translateY(-50%); /* 垂直居中 */ 151 | border-width: 5px 5px 0; /* 边框宽度 */ 152 | border-style: solid; /* 边框样式为实线 */ 153 | opacity: 0.6; /* 透明度 */ 154 | } 155 | 156 | .device-table th.asc::after { 157 | content: ''; 158 | position: absolute; 159 | right: 10px; 160 | top: 50%; 161 | transform: translateY(-50%); 162 | border-width: 6px; 163 | border-style: solid; 164 | border-color: #666 transparent transparent transparent; /* 向上箭头颜色 */ 165 | } 166 | 167 | .device-table th.desc::after { 168 | content: ''; 169 | position: absolute; 170 | right: 10px; 171 | top: 50%; 172 | transform: translateY(-50%); 173 | border-width: 6px; 174 | border-style: solid; 175 | border-color: transparent transparent #666 transparent; /* 向下箭头颜色 */ 176 | } 177 | 178 | .device-table tbody tr:nth-child(even) { 179 | background-color: rgba(0, 0, 0, 0.05); /* 偶数行背景色,透明 */ 180 | } 181 | 182 | .device-table td:first-child { 183 | text-align: left; /* 第一列文本左对齐 */ 184 | padding-left: 20px; /* 第一列左侧内边距 */ 185 | } 186 | 187 | .device-table td a { 188 | color: #007bff; /* 链接颜色 */ 189 | text-decoration: none; /* 去掉下划线 */ 190 | } 191 | 192 | .device-table td a:hover { 193 | text-decoration: underline; /* 鼠标悬停下划线 */ 194 | } 195 | 196 | .device-table .hide { 197 | display: none; /* 隐藏元素 */ 198 | } 199 | 200 | @media (max-width: 767px) { 201 | .device-table { 202 | width: 100%; /* 表格宽度占满父容器 */ 203 | overflow: hidden; /* 内容溢出隐藏 */ 204 | } 205 | .device-table th, 206 | .device-table td { 207 | padding: 3px; /* 单元格内边距 */ 208 | text-align: center; /* 文本居中 */ 209 | border: 0.35px solid #ddd; /* 边框样式 */ 210 | } 211 | .device-table td:first-child { 212 | max-width: 80px; 213 | } 214 | .device-table td:first-child { 215 | text-align: left; /* 第一列文本左对齐 */ 216 | padding-left: 2px; /* 第一列左侧内边距 */ 217 | overflow: hidden; /* 隐藏溢出内容 */ 218 | text-overflow: ellipsis; /* 显示省略号 */ 219 | } 220 | /* 隐藏特定列 */ 221 | .device-table th[data-column="parent"], 222 | .device-table td[data-column="parent"] { 223 | display: none; 224 | } 225 | /* 隐藏接口列的文本部分 */ 226 | .device-table td[data-column="interface"] span:not(.iface-icon) { 227 | display: none; 228 | } 229 | /* 调整图标样式 */ 230 | .device-table td[data-column="interface"] .iface-icon { 231 | margin-right: 0; /* 去掉图标右侧的间距 */ 232 | } 233 | } 234 | `; 235 | 236 | function createTable() { 237 | var table = document.createElement('table'); 238 | table.classList.add('device-table'); 239 | 240 | var thead = document.createElement('thead'); 241 | var tr = document.createElement('tr'); 242 | 243 | for (var i = 0; i < headers.length; i++) { 244 | var th = document.createElement('th'); 245 | th.textContent = headers[i]; 246 | 247 | if (visibleColumns.includes(i)) { 248 | th.classList.add('sortable'); 249 | th.dataset.column = columns[i]; 250 | if (columns[i] === currentSortColumn) { 251 | th.classList.add(currentSortDirection === 'asc' ? 'asc' : 'desc'); 252 | } 253 | } else { 254 | th.classList.add('hide'); 255 | } 256 | 257 | tr.appendChild(th); 258 | } 259 | 260 | thead.appendChild(tr); 261 | table.appendChild(thead); 262 | 263 | var tbody = document.createElement('tbody'); 264 | devices.forEach(function (device) { 265 | var row = document.createElement('tr'); 266 | for (var i = 0; i < columns.length; i++) { 267 | if (visibleColumns.includes(i)) { 268 | var cell = document.createElement('td'); 269 | cell.dataset.column = columns[i]; 270 | if (columns[i] === 'uptime') { 271 | cell.textContent = calculateUptime(device['uptime'], window.innerWidth <= 767); 272 | } else if (columns[i] === 'ip' && device['http_access']) { 273 | var link = document.createElement('a'); 274 | link.href = `${device['http_access']}://${device['ip']}`; 275 | link.textContent = device['ip']; 276 | link.target = '_blank'; 277 | cell.appendChild(link); 278 | } else if (columns[i] === 'interface') { 279 | var icon = document.createElement('span'); 280 | icon.classList.add('iface-icon'); 281 | if (device['interface'] === '2.4G') { 282 | icon.innerHTML = '📶'; 283 | } else if (device['interface'] === '5G') { 284 | icon.innerHTML = '🛜'; 285 | } else if (device['interface'] === 'WiFi') { 286 | icon.innerHTML = '🛜'; 287 | } 288 | 289 | var text = document.createElement('span'); 290 | text.textContent = device['interface']; 291 | 292 | cell.appendChild(icon); 293 | cell.appendChild(text); 294 | } else if (columns[i] === 'parent') { 295 | if (device['parent']) { 296 | var parentDevice = devices.find(d => { 297 | // 统一转换为大写比较 298 | var deviceMac = (d.mac || '').toUpperCase(); 299 | var parentMac = (device['parent'] || '').toUpperCase(); 300 | return deviceMac === parentMac || d.ip === device['parent']; 301 | }); 302 | if (parentDevice) { 303 | cell.textContent = parentDevice.name || parentDevice.ip; 304 | } else { 305 | cell.textContent = device['parent']; 306 | } 307 | } else { 308 | cell.textContent = ''; 309 | } 310 | } else { 311 | cell.textContent = device[columns[i]]; 312 | } 313 | row.appendChild(cell); 314 | } 315 | } 316 | tbody.appendChild(row); 317 | }); 318 | 319 | table.appendChild(tbody); 320 | 321 | return table; 322 | } 323 | 324 | function calculateUptime(uptime, simpleFormat = false) { 325 | var startTimeStamp = parseInt(uptime); 326 | var currentTimeStamp = Math.floor(Date.now() / 1000); 327 | var uptimeInSeconds = currentTimeStamp - startTimeStamp; 328 | 329 | var days = Math.floor(uptimeInSeconds / (3600 * 24)); 330 | var hours = Math.floor((uptimeInSeconds % (3600 * 24)) / 3600); 331 | var minutes = Math.floor((uptimeInSeconds % 3600) / 60); 332 | var seconds = uptimeInSeconds % 60; 333 | 334 | if (simpleFormat) { 335 | return days > 0 ? `${days}d ${hours}h` : 336 | hours > 0 ? `${hours}h ${minutes}m` : 337 | minutes > 0 ? `${minutes}m ${seconds}s` : 338 | `${seconds}s`; 339 | } else { 340 | if (days > 0) { 341 | return _('%dd %dh').replace(/%d/g, match => 342 | match === '%d' ? days : hours); 343 | } else if (hours > 0) { 344 | return _('%dh %dm').replace(/%d/g, match => 345 | match === '%d' ? hours : minutes); 346 | } else if (minutes > 0) { 347 | return _('%dm %ds').replace(/%d/g, match => 348 | match === '%d' ? minutes : seconds); 349 | } else { 350 | return _('%ds').replace('%d', seconds); 351 | } 352 | } 353 | } 354 | 355 | function compareDevices(a, b, column, direction) { 356 | var value1 = getValueForSorting(a, column); 357 | var value2 = getValueForSorting(b, column); 358 | 359 | // 处理 name/mac 列的 "unknown" 优先级 360 | if (column === 'name' || column === 'mac') { 361 | const isUnknown1 = (value1 === "unknown"); 362 | const isUnknown2 = (value2 === "unknown"); 363 | 364 | if (isUnknown1 !== isUnknown2) { 365 | return direction === 'asc' 366 | // 升序时 unknown 排最后(视为最大值),降序时排最前 367 | //? (isUnknown1 ? 1 : -1) 368 | //: (isUnknown1 ? -1 : 1); 369 | // 升序时 unknown 排最前(视为最小值) 370 | ? (isUnknown1 ? -1 : 1) 371 | : (isUnknown1 ? 1 : -1); 372 | } 373 | } 374 | 375 | // 处理 parent 列的优先级 376 | if (column === 'parent') { 377 | const aHasValue = a.parent ? 1 : 0; 378 | const bHasValue = b.parent ? 1 : 0; 379 | if (aHasValue !== bHasValue) { 380 | return direction === 'desc' 381 | ? (bHasValue - aHasValue) 382 | : (aHasValue - bHasValue); 383 | } 384 | value1 = a.parent || ''; 385 | value2 = b.parent || ''; 386 | } 387 | 388 | // 通用比较逻辑 389 | if (value1 < value2) { 390 | return direction === 'asc' ? -1 : 1; 391 | } else if (value1 > value2) { 392 | return direction === 'asc' ? 1 : -1; 393 | } 394 | return 0; 395 | } 396 | 397 | var interfaceDisplayMap = { 398 | '2.4G': '2.4G', 399 | '5G': '5G', 400 | 'WiFi': 'WiFi' 401 | }; 402 | 403 | // 排序 404 | function getValueForSorting(device, column) { 405 | if (column === 'uptime') { 406 | return parseInt(device['uptime']); 407 | } else if (column === 'ip') { 408 | return ipToNumber(device['ip']); 409 | } else if (column === 'interface') { 410 | return interfaceDisplayMap[device['interface']] || 'LAN'; 411 | } else if (column === 'parent') { 412 | // 使用 parent 列的实际显示值进行排序 413 | if (device['parent']) { 414 | var parentDevice = devices.find(d => { 415 | var deviceMac = (d.mac || '').toUpperCase(); 416 | var parentMac = (device['parent'] || '').toUpperCase(); 417 | return deviceMac === parentMac || d.ip === device['parent']; 418 | }); 419 | if (parentDevice) { 420 | return parentDevice.name || parentDevice.ip; 421 | } else { 422 | return device['parent']; 423 | } 424 | } else { 425 | return ''; 426 | } 427 | } 428 | return device[column]; 429 | } 430 | 431 | function ipToNumber(ipAddress) { 432 | var parts = ipAddress.split('.'); 433 | var number = 0; 434 | 435 | for (var i = 0; i < parts.length; i++) { 436 | number = number * 256 + parseInt(parts[i]); 437 | } 438 | 439 | return number; 440 | } 441 | 442 | var container = document.createElement('div'); 443 | refreshContainer(); 444 | 445 | container.addEventListener('click', function (event) { 446 | if (event.target.tagName === 'TH' && event.target.parentNode.rowIndex === 0) { 447 | var columnIndex = event.target.cellIndex; 448 | var column = columns[columnIndex]; 449 | var direction = 'asc'; 450 | 451 | // 使在线时间第一次点击方向为倒序 452 | if (column === 'uptime' || column === 'parent') { 453 | if (currentSortColumn !== column) { 454 | // 首次点击该列,默认方向为 desc 455 | direction = 'desc'; 456 | } else { 457 | // 切换方向 458 | direction = currentSortDirection === 'desc' ? 'asc' : 'desc'; 459 | } 460 | } else if (column === currentSortColumn) { 461 | direction = currentSortDirection === 'asc' ? 'desc' : 'asc'; 462 | } else { 463 | direction = 'asc'; 464 | } 465 | 466 | sortTable(column, direction); 467 | } 468 | }); 469 | 470 | function refreshContainer() { 471 | container.innerHTML = ''; 472 | container.appendChild(document.createElement('h2')).textContent = _('Currently %s devices online').replace('%s', totalDevices); 473 | container.appendChild(createTable()); 474 | container.appendChild(document.createElement('style')).textContent = style; 475 | } 476 | 477 | function sortTable(column, direction) { 478 | devices.sort(function (a, b) { 479 | return compareDevices(a, b, column, direction); 480 | }); 481 | 482 | currentSortColumn = column; 483 | currentSortDirection = direction; 484 | 485 | // 存储排序设置 486 | localStorage.setItem('sortColumn', currentSortColumn); 487 | localStorage.setItem('sortDirection', currentSortDirection); 488 | 489 | refreshContainer(); 490 | } 491 | 492 | return container; 493 | }, 494 | 495 | setupAutoRefresh: function () { 496 | var self = this; 497 | poll.add(L.bind(function () { 498 | self.fetchAndRenderDevices(); 499 | })); 500 | }, 501 | 502 | switchContent: function (newContent) { 503 | var existingContainer = document.querySelector('#view'); 504 | if (!existingContainer) { 505 | console.error('Table container not found.'); 506 | return; 507 | } 508 | existingContainer.innerHTML = ''; 509 | existingContainer.appendChild(newContent); 510 | }, 511 | 512 | handleSave: null, 513 | handleSaveApply: null, 514 | handleReset: null 515 | }); -------------------------------------------------------------------------------- /htdocs/luci-static/resources/view/wechatpush/config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 'require view'; 3 | 'require fs'; 4 | 'require ui'; 5 | 'require uci'; 6 | 'require rpc'; 7 | 'require form'; 8 | 9 | 'require poll'; 10 | 'require tools.widgets as widgets'; 11 | 'require tools.firewall as fwtool'; 12 | 13 | var callServiceList = rpc.declare({ 14 | object: 'service', 15 | method: 'list', 16 | params: ['name'], 17 | expect: { '': {} } 18 | }); 19 | 20 | function getServiceStatus() { 21 | return L.resolveDefault(callServiceList('wechatpush'), {}).then(function (res) { 22 | console.log(res); 23 | var isRunning = false; 24 | try { 25 | isRunning = res['wechatpush']['instances']['instance1']['running']; 26 | } catch (e) { } 27 | return isRunning; 28 | }); 29 | } 30 | 31 | function renderStatus(isRunning) { 32 | var spanTemp = '%s %s'; 33 | var renderHTML; 34 | if (isRunning) { 35 | renderHTML = String.format(spanTemp, 'green', _('wechatpush'), _('RUNNING')); 36 | } else { 37 | renderHTML = String.format(spanTemp, 'red', _('wechatpush'), _('NOT RUNNING')); 38 | } 39 | 40 | return renderHTML; 41 | } 42 | 43 | var cbiRichListValue = form.ListValue.extend({ 44 | renderWidget: function (section_id, option_index, cfgvalue) { 45 | var choices = this.transformChoices(); 46 | var widget = new ui.Dropdown((cfgvalue != null) ? cfgvalue : this.default, choices, { 47 | id: this.cbid(section_id), 48 | sort: this.keylist, 49 | optional: true, 50 | select_placeholder: this.select_placeholder || this.placeholder, 51 | custom_placeholder: this.custom_placeholder || this.placeholder, 52 | validate: L.bind(this.validate, this, section_id), 53 | disabled: (this.readonly != null) ? this.readonly : this.map.readonly 54 | }); 55 | 56 | return widget.render(); 57 | }, 58 | 59 | value: function (value, title, description) { 60 | if (description) { 61 | form.ListValue.prototype.value.call(this, value, E([], [ 62 | E('span', { 'class': 'hide-open' }, [title]), 63 | E('div', { 'class': 'hide-close', 'style': 'min-width:25vw' }, [ 64 | E('strong', [title]), 65 | E('br'), 66 | E('span', { 'style': 'white-space:normal' }, description) 67 | ]) 68 | ])); 69 | } 70 | else { 71 | form.ListValue.prototype.value.call(this, value, title); 72 | } 73 | } 74 | }); 75 | 76 | return view.extend({ 77 | callHostHints: rpc.declare({ 78 | object: 'luci-rpc', 79 | method: 'getHostHints', 80 | expect: { '': {} } 81 | }), 82 | 83 | load: function () { 84 | return Promise.all([ 85 | this.callHostHints() 86 | ]); 87 | }, 88 | 89 | render: function (data) { 90 | if (fwtool.checkLegacySNAT()) 91 | return fwtool.renderMigration(); 92 | else 93 | return this.renderForwards(data); 94 | }, 95 | 96 | renderForwards: function (data) { 97 | var hosts = data[0], 98 | m, s, o, 99 | programPath = '/usr/share/wechatpush/wechatpush'; 100 | 101 | m = new form.Map('wechatpush', _('WeChat push'), _('A tool that can push device messages from OpenWrt to a mobile phone via WeChat or Telegram.

If you encounter any issues while using it, please submit them here:') + '' + _('GitHub Project Address') + ''); 102 | 103 | s = m.section(form.TypedSection); 104 | s.anonymous = true; 105 | s.render = function () { 106 | var statusView = E('p', { id: 'service_status' }, _('Collecting data ...')); 107 | poll.add(function () { 108 | return L.resolveDefault(getServiceStatus()).then(function (res) { 109 | statusView.innerHTML = renderStatus(res); 110 | }); 111 | }); 112 | 113 | setTimeout(function () { 114 | poll.start(); 115 | }, 100); 116 | 117 | return E('div', { class: 'cbi-section', id: 'status_bar' }, [ 118 | statusView 119 | ]); 120 | } 121 | 122 | s = m.section(form.NamedSection, 'config', 'wechatpush', _('')); 123 | s.tab('basic', _('Basic Settings')); 124 | s.tab('content', _('Push Content')); 125 | s.tab('ipset', _('Auto Ban')); 126 | s.tab('crontab', _('Scheduled Push')); 127 | s.tab('disturb', _('Do Not Disturb')); 128 | s.addremove = false; 129 | s.anonymous = true; 130 | 131 | // 基本设置 132 | o = s.taboption('basic', form.Flag, 'enable', _('Enabled')); 133 | 134 | o = s.taboption('basic', cbiRichListValue, 'jsonpath', _('Push Mode')); 135 | o.value('', _('Close'), 136 | _('Do not use push notifications, only use other features.')); 137 | o.value('/usr/share/wechatpush/api/serverchan.json', _('WeChat serverchan'), 138 | _('Using serverchan API, simple configuration, supports multiple push methods')); 139 | o.value('/usr/share/wechatpush/api/serverchan3.json', _('Serverchan3 APP'), 140 | _('Using serverchan3 API, simple configuration, support push to ServerChan App')); 141 | o.value('/usr/share/wechatpush/api/qywx_mpnews.json', _('WeChat Work Image Message'), 142 | _('Using WeChat Work application message, more complex configuration, and starting from June 20, 2022, additional configuration for trusted IP is required. Trusted IP cannot be shared. This channel is no longer recommended.')); 143 | o.value('/usr/share/wechatpush/api/qywx_markdown.json', _('WeChat Work Markdown Version'), 144 | _('WeChat Work application message in plain text format, no need to click the title to view the content, same as above')); 145 | o.value('/usr/share/wechatpush/api/wxpusher.json', _('wxpusher'), 146 | _('Another channel for WeChat push, the configuration is relatively simple, and only supports official accounts')); 147 | o.value('/usr/share/wechatpush/api/pushplus.json', _('pushplus'), 148 | _('Another channel for WeChat push, the configuration is relatively simple, and it supports multiple push methods')); 149 | o.value('/usr/share/wechatpush/api/telegram.json', _('Telegram'), 150 | _('Telegram Bot Push')); 151 | o.value('/usr/share/wechatpush/api/msmtp.json', _('msmtp'), 152 | _('To send emails using msmtp, you must manually install msmtp and configure `/etc/msmtprc`.')); 153 | o.value('/usr/share/wechatpush/api/diy.json', _('Custom Push'), 154 | _('By modifying the JSON file, you can use a custom API')); 155 | 156 | o = s.taboption('basic', form.Value, 'sckey', _('「wechatpush」sendkey')); 157 | o.description = _('Get Instructions') + ' ' + _('Click here') + ''; 158 | o.rmempty = false; 159 | o.depends('jsonpath', '/usr/share/wechatpush/api/serverchan.json'); 160 | 161 | o = s.taboption('basic', form.Value, 'sc3key', _('「Serverchan3」sendkey')); 162 | o.description = _('Get Instructions') + ' ' + _('Click here') + ''; 163 | o.rmempty = false; 164 | o.depends('jsonpath', '/usr/share/wechatpush/api/serverchan3.json'); 165 | 166 | o = s.taboption('basic', form.Value, 'sc3uid', _('「Serverchan3」uid')); 167 | o.description = _('ServerChan3 uid'); 168 | o.rmempty = false; 169 | o.depends('jsonpath', '/usr/share/wechatpush/api/serverchan3.json'); 170 | 171 | o = s.taboption('basic', form.Value, 'sc3tags', _('「Serverchan3」tags')); 172 | o.description = _('ServerChan3 message tags, split with |'); 173 | o.depends('jsonpath', '/usr/share/wechatpush/api/serverchan3.json'); 174 | 175 | o = s.taboption('basic', form.Value, 'corpid', _('corpid')); 176 | o.description = _('Get Instructions') + ' ' + _('Click here') + ''; 177 | o.rmempty = false; 178 | o.depends('jsonpath', '/usr/share/wechatpush/api/qywx_mpnews.json'); 179 | o.depends('jsonpath', '/usr/share/wechatpush/api/qywx_markdown.json'); 180 | 181 | o = s.taboption('basic', form.Value, 'userid', _('userid')); 182 | o.rmempty = false; 183 | o.description = _('Send to All App Users, enter @all'); 184 | o.depends('jsonpath', '/usr/share/wechatpush/api/qywx_mpnews.json'); 185 | o.depends('jsonpath', '/usr/share/wechatpush/api/qywx_markdown.json'); 186 | 187 | o = s.taboption('basic', form.Value, 'agentid', _('agentid')); 188 | o.rmempty = false; 189 | o.depends('jsonpath', '/usr/share/wechatpush/api/qywx_mpnews.json'); 190 | o.depends('jsonpath', '/usr/share/wechatpush/api/qywx_markdown.json'); 191 | 192 | o = s.taboption('basic', form.Value, 'corpsecret', _('Secret')); 193 | o.rmempty = false; 194 | o.depends('jsonpath', '/usr/share/wechatpush/api/qywx_mpnews.json'); 195 | o.depends('jsonpath', '/usr/share/wechatpush/api/qywx_markdown.json'); 196 | 197 | o = s.taboption('basic', form.Value, 'mediapath', _('Thumbnail Image File Path')) 198 | o.rmempty = false; 199 | o.default = '/usr/share/wechatpush/api/logo.jpg'; 200 | o.depends('jsonpath', '/usr/share/wechatpush/api/qywx_mpnews.json'); 201 | o.description = _('Supports JPG and PNG formats within 2MB
Optimal size: 900383 or 2.35:1'); 202 | 203 | o = s.taboption('basic', form.Value, 'proxy_ip', _('Trusted IP address')); 204 | o.depends('jsonpath', '/usr/share/wechatpush/api/qywx_mpnews.json'); 205 | o.depends('jsonpath', '/usr/share/wechatpush/api/qywx_markdown.json'); 206 | o.description = _('If the application was created after June 20, 2022, you need to set the trusted IP. This option should be used in conjunction with a proxy server.'); 207 | 208 | o = s.taboption('basic', form.Value, 'wxpusher_apptoken', _('appToken')); 209 | o.description = _('Get Instructions') + ' ' + _('Click here') + ''; 210 | o.rmempty = false; 211 | o.depends('jsonpath', '/usr/share/wechatpush/api/wxpusher.json'); 212 | 213 | o = s.taboption('basic', form.Value, 'wxpusher_uids', _('uids')); 214 | o.depends('jsonpath', '/usr/share/wechatpush/api/wxpusher.json'); 215 | 216 | o = s.taboption('basic', form.Value, 'wxpusher_topicIds', _('topicIds(Mass sending)')); 217 | o.description = _('Get Instructions') + ' ' + _('Click here') + ''; 218 | o.depends('jsonpath', '/usr/share/wechatpush/api/wxpusher.json'); 219 | 220 | o = s.taboption('basic', form.Value, 'pushplus_token', _('pushplus_token')); 221 | o.description = _('Get Instructions') + ' ' + _('Click here') + ''; 222 | o.rmempty = false; 223 | o.depends('jsonpath', '/usr/share/wechatpush/api/pushplus.json'); 224 | 225 | o = s.taboption('basic', form.Value, 'tg_token', _('TG_token')); 226 | o.description = _('Get Bot') + ' ' + _('Click here') + '' + _('
Send a message to the created bot to initiate a conversation.'); 227 | o.rmempty = false; 228 | o.depends('jsonpath', '/usr/share/wechatpush/api/telegram.json'); 229 | 230 | o = s.taboption('basic', form.Value, 'chat_id', _('TG_chatid')); 231 | o.description = _('Get chat_id') + ' ' + _('Click here') + '' + _('
If you want to send to a group/channel, please create a non-Chinese group/channel (for easier chatid lookup, you can rename it later).
Add the bot to the group, send a message, and use https://api.telegram.org/bot token /getUpdates to obtain the chatid.'); 232 | o.rmempty = false; 233 | o.depends('jsonpath', '/usr/share/wechatpush/api/telegram.json'); 234 | 235 | o = s.taboption('basic', form.Value, 'recipient_email', _('Recipient Email Address')); 236 | o.depends('jsonpath', '/usr/share/wechatpush/api/msmtp.json'); 237 | o.description = _('opkg update
opkg install msmtp'); 238 | 239 | o = s.taboption('basic', form.TextValue, 'diy_json', _('Custom Push')); 240 | o.rows = 28; 241 | o.wrap = 'oft'; 242 | o.cfgvalue = function (section_id) { 243 | return fs.trimmed('/usr/share/wechatpush/api/diy.json'); 244 | }; 245 | o.write = function (section_id, formvalue) { 246 | return this.cfgvalue(section_id).then(function (value) { 247 | if (value == formvalue) { 248 | return 249 | } 250 | return fs.write('/usr/share/wechatpush/api/diy.json', formvalue.trim().replace(/\r\n/g, '\n') + '\n'); 251 | }); 252 | }; 253 | o.description = _('Please refer to the comments and other interface files for modifications. Limited resources, no longer supporting more interfaces, please debug on your own.
You can use a similar website to check the JSON file format: https://www.google.com/search?q=JSON+Parser+Online
Please use the 「Save」 button in the text box.'); 254 | o.depends('jsonpath', '/usr/share/wechatpush/api/diy.json'); 255 | 256 | o = s.taboption('basic', form.Value, 'proxy_address', _('Proxy Address')); 257 | o.description = _('When you want to use a proxy to push information, you can use this option.
This may be helpful for scenarios like trusted IPs for WeChat Work.Using special characters may cause sending failure.
Example:
http://username:password@127.0.0.1:1080
socks5://username:password@127.0.0.1:1080'); 258 | o.depends('jsonpath', '/usr/share/wechatpush/api/serverchan.json'); 259 | o.depends('jsonpath', '/usr/share/wechatpush/api/serverchan3.json'); 260 | o.depends('jsonpath', '/usr/share/wechatpush/api/qywx_mpnews.json'); 261 | o.depends('jsonpath', '/usr/share/wechatpush/api/wxpusher.json'); 262 | o.depends('jsonpath', '/usr/share/wechatpush/api/pushplus.json'); 263 | o.depends('jsonpath', '/usr/share/wechatpush/api/telegram.json'); 264 | o.depends('jsonpath', '/usr/share/wechatpush/api/diy.json'); 265 | 266 | o = s.taboption('basic', form.Button, '_test', _('Send Test'), _('You may need to save the configuration before sending.')); 267 | o.inputstyle = 'add'; 268 | o.onclick = function () { 269 | var _this = this; 270 | return fs.exec(programPath, ['test']).then(function (res) { 271 | if (res.code === 0) 272 | _this.description = _('Message sent successfully. If you don\'t receive the message, please check the logs for manual processing.'); 273 | else if (res.code === 1) 274 | _this.description = _('Sending failed'); 275 | 276 | return _this.map.reset(); 277 | }).catch(function (err) { 278 | ui.addNotification(null, E('p', [_('Unknown error: %s.').format(err)])); 279 | _this.description = _('Sending failed'); 280 | return _this.map.reset(); 281 | }); 282 | } 283 | o.depends('jsonpath', '/usr/share/wechatpush/api/serverchan.json'); 284 | o.depends('jsonpath', '/usr/share/wechatpush/api/serverchan3.json'); 285 | o.depends('jsonpath', '/usr/share/wechatpush/api/qywx_mpnews.json'); 286 | o.depends('jsonpath', '/usr/share/wechatpush/api/wxpusher.json'); 287 | o.depends('jsonpath', '/usr/share/wechatpush/api/pushplus.json'); 288 | o.depends('jsonpath', '/usr/share/wechatpush/api/telegram.json'); 289 | o.depends('jsonpath', '/usr/share/wechatpush/api/diy.json'); 290 | 291 | o = s.taboption('basic', form.Value, 'device_name', _('Device Name')); 292 | o.description = _('The device name will be displayed in the push message title to identify the source device of the message.'); 293 | 294 | o = s.taboption('basic', form.Value, 'sleeptime', _('Check Interval (s)')); 295 | o.rmempty = false; 296 | o.placeholder = '60'; 297 | o.datatype = 'and(uinteger,min(10))'; 298 | o.description = _('Shorter intervals provide quicker response but consume more system resources.'); 299 | 300 | o = s.taboption('basic', cbiRichListValue, 'oui_data', _('MAC Device Database')); 301 | o.value('', _('Close'), 302 | _('Do not use MAC device database')); 303 | o.value('1', _('Simplified Version'), 304 | _('Includes common device manufacturers, occupies approximately 200Kb of space')); 305 | o.value('2', _('Full Version'), 306 | _('Download the complete database, processed size is approximately 1.3Mb')); 307 | o.value('3', _('Network Query'), 308 | _('Enables network query, slower response. Only use if space is limited.')); 309 | 310 | o = s.taboption('basic', form.Button, '_update_oui', _('Update MAC Device Database')); 311 | o.inputstyle = 'add'; 312 | o.onclick = function () { 313 | var _this = this; 314 | return fs.exec('/usr/libexec/wechatpush-call', ['down_oui']).then(function (res) { 315 | if (res.code === 2) { 316 | _this.description = _('Database is up to date, skipping update'); 317 | } 318 | return _this.map.reset(); 319 | }).catch(function (err) { 320 | ui.addNotification(null, E('p', [_('Unknown error: %s.').format(err)])); 321 | _this.description = _('Browser timeout or unknown error. If the log shows that the update process has been established, please ignore this error: %s.'); 322 | return _this.map.reset(); 323 | }); 324 | }; 325 | o.depends('oui_data', '1'); 326 | o.depends('oui_data', '2'); 327 | 328 | o = s.taboption('basic', form.Flag, 'reset_regularly', _('Reset Traffic Data Every Day at Midnight')); 329 | 330 | o = s.taboption('basic', form.Flag, 'debuglevel', _('Enable Logging')); 331 | 332 | o = s.taboption('basic', form.TextValue, '_device_aliases', _('Device Alias')); 333 | o.rows = 20; 334 | o.wrap = 'oft'; 335 | o.cfgvalue = function (section_id) { 336 | return fs.trimmed('/usr/share/wechatpush/api/device_aliases.list'); 337 | }; 338 | o.write = function (section_id, formvalue) { 339 | return this.cfgvalue(section_id).then(function (value) { 340 | if (value == formvalue) { 341 | return 342 | } 343 | return fs.write('/usr/share/wechatpush/api/device_aliases.list', formvalue.trim().replace(/\r\n/g, '\n') + '\n'); 344 | }); 345 | }; 346 | o.description = _('Please enter the device MAC and device alias separated by a space, such as:
XX:XX:XX:XX:XX:XX My Phone
192.168.1.2 My PC
Please use the 「Save」 button in the text box.'); 347 | 348 | // 推送内容 349 | o = s.taboption('content', form.MultiValue, 'lite_enable', _('Simplified mode')); 350 | o.value('device', _('Simplify the current device list')); 351 | o.value('nowtime', _('Simplify the current time')); 352 | o.value('content', _('Push only the title')); 353 | 354 | o = s.taboption('content', form.Button, '_getip', _('Test IP acquisition command'), _('You may need to save the configuration before sending.')); 355 | o.inputstyle = 'action'; 356 | o.onclick = function () { 357 | var _this = this; 358 | return fs.exec(programPath, ['getip']).then(function (res) { 359 | if (!res.stdout) { 360 | throw new Error(_('Returned value is empty')); 361 | } 362 | _this.description = res.stdout.trim(); 363 | return _this.map.reset(); 364 | }).catch(function (err) { 365 | _this.description = _('Fetch failed:') + err.message; 366 | return _this.map.reset(); 367 | }); 368 | }; 369 | 370 | o = s.taboption('content', cbiRichListValue, 'get_ipv4_mode', _('IPv4 Dynamic Notification')); 371 | o.value('', _('Close'), 372 | _(' ')); 373 | o.value('1', _('Obtain through interface'), 374 | _(' ')); 375 | o.value('2', _('Obtain through URL'), 376 | _('May fail due to server stability and frequent connections.
If the interface can obtain the IP address properly, it is not recommended to use this method.')); 377 | 378 | o = s.taboption('content', widgets.DeviceSelect, 'ipv4_interface', _("Device")); 379 | o.description = _('Generally, it should be the pppoe-wan or WAN interface. For multi-dial environments, please select the appropriate interface yourself.'); 380 | o.modalonly = true; 381 | o.multiple = false; 382 | o.default = 'pppoe-wan'; 383 | o.depends('get_ipv4_mode', '1'); 384 | 385 | o = s.taboption('content', form.TextValue, 'ipv4_list', _('IPv4 API List')); 386 | o.depends('get_ipv4_mode', '2'); 387 | o.optional = false; 388 | o.rows = 8; 389 | o.wrap = 'oft'; 390 | o.cfgvalue = function (section_id) { 391 | return fs.trimmed('/usr/share/wechatpush/api/ipv4.list'); 392 | }; 393 | o.write = function (section_id, formvalue) { 394 | return this.cfgvalue(section_id).then(function (value) { 395 | if (value == formvalue) { 396 | return 397 | } 398 | return fs.write('/usr/share/wechatpush/api/ipv4.list', formvalue.trim().replace(/\r\n/g, '\n') + '\n'); 399 | }); 400 | }; 401 | o.description = _('Access a random address from the list above,URLs in the list are specific to Chinese websites. If you need to use this feature, please replace the URLs with the ones available to you.
Please use the 「Save」 button in the text box.'); 402 | 403 | o = s.taboption('content', cbiRichListValue, 'get_ipv6_mode', _('IPv6 Dynamic Notification')); 404 | o.value('', _('Close'), 405 | _(' ')); 406 | o.value('1', _('Obtain through interface'), 407 | _(' ')); 408 | o.value('2', _('Obtain through URL'), 409 | _('May fail due to server stability and frequent connections.
If the interface can obtain the IP address properly, it is not recommended to use this method.')); 410 | 411 | o = s.taboption('content', widgets.DeviceSelect, 'ipv6_interface', _("Device")); 412 | o.description = _('Generally, it should be the pppoe-wan or WAN interface. For multi-dial environments, please select the appropriate interface yourself.'); 413 | o.modalonly = true; 414 | o.multiple = false; 415 | o.default = 'WAN'; 416 | o.depends('get_ipv6_mode', '1'); 417 | 418 | o = s.taboption('content', form.TextValue, 'ipv6_list', _('IPv6 API List')); 419 | o.depends('get_ipv6_mode', '2') 420 | o.optional = false; 421 | o.rows = 8; 422 | o.wrap = 'oft'; 423 | o.cfgvalue = function (section_id) { 424 | return fs.trimmed('/usr/share/wechatpush/api/ipv6.list'); 425 | }; 426 | o.write = function (section_id, formvalue) { 427 | return this.cfgvalue(section_id).then(function (value) { 428 | if (value == formvalue) { 429 | return 430 | } 431 | return fs.write('/usr/share/wechatpush/api/ipv6.list', formvalue.trim().replace(/\r\n/g, '\n') + '\n'); 432 | }); 433 | }; 434 | o.description = _('Access a random address from the list above,URLs in the list are specific to Chinese websites. If you need to use this feature, please replace the URLs with the ones available to you.
Please use the 「Save」 button in the text box.'); 435 | 436 | o = s.taboption('content', form.MultiValue, 'device_notification', _('Device Online/Offline Notification')); 437 | o.value('online', _('Online Notification')); 438 | o.value('offline', _('Offline Notification')); 439 | o.modalonly = true; 440 | 441 | o = s.taboption('content', form.MultiValue, 'cpu_notification', _('CPU Alert')); 442 | o.value('load', _('Load Alert')); 443 | o.value('temp', _('Temperature Alert')); 444 | o.modalonly = true; 445 | o.description = _('Device alert will be triggered only if it exceeds the set value continuously for five minutes, and there won\'t be a second reminder within an hour.'); 446 | 447 | o = s.taboption('content', form.Value, 'cpu_load_threshold', _('Load alert threshold')); 448 | o.rmempty = false; 449 | o.placeholder = '2'; 450 | o.depends({ cpu_notification: "load", '!contains': true }); 451 | o.validate = function (section_id, value) { 452 | var floatValue = parseFloat(value); 453 | if (!isNaN(floatValue) && floatValue.toString() === value) { 454 | return true; 455 | } 456 | return _('Please enter a numeric value only'); 457 | }; 458 | o.description = _('In general, when the load value is lower than the number of logical cores, you typically don\'t need to pay much attention to it.'); 459 | 460 | o = s.taboption('content', form.Value, 'temperature_threshold', _('Temperature alert threshold')); 461 | o.rmempty = false; 462 | o.placeholder = '80'; 463 | o.datatype = 'and(uinteger,min(1))'; 464 | o.depends({ cpu_notification: "temp", '!contains': true }); 465 | o.description = _('Please confirm that the device can retrieve temperature. If you need to modify the command, please go to advanced settings.'); 466 | 467 | o = s.taboption('content', form.MultiValue, 'login_notification', _('Login Notification')); 468 | o.value('web_logged', _('Web Login')); 469 | o.value('ssh_logged', _('SSH Login')); 470 | o.value('web_login_failed', _('Frequent Web Login Errors')); 471 | o.value('ssh_login_failed', _('Frequent SSH Login Errors')); 472 | o.modalonly = true; 473 | 474 | o = s.taboption('content', form.Value, 'login_max_num', _('Login failure count')); 475 | o.default = '3'; 476 | o.rmempty = false; 477 | o.datatype = 'and(uinteger,min(1))'; 478 | o.depends({ login_notification: "web_login_failed", '!contains': true }); 479 | o.depends({ login_notification: "ssh_login_failed", '!contains': true }); 480 | o.description = _('Send notification after exceeding the count, and optionally auto-ban IP'); 481 | 482 | o = s.taboption('content', form.Flag, 'client_usage', _('Device abnormal traffic alert')); 483 | o.description = _('Please ensure that you can retrieve device traffic information correctly, otherwise this feature will not work properly'); 484 | o.default = '0'; 485 | 486 | o = s.taboption('content', form.Value, 'client_usage_max', _('Per-minute traffic limit')); 487 | o.placeholder = '10M'; 488 | o.rmempty = false; 489 | o.depends('client_usage', '1'); 490 | o.description = _('Abnormal traffic alert (byte), you can append K or M'); 491 | 492 | o = s.taboption('content', form.Flag, 'client_usage_disturb', _('Abnormal traffic do not disturb')); 493 | o.default = '0'; 494 | o.depends('client_usage', '1'); 495 | 496 | o = fwtool.addMACOption(s, 'content', 'client_usage_whitelist', _('Abnormal traffic monitoring list'), 497 | _('Please select device MAC'), hosts); 498 | o.rmempty = true; 499 | o.datatype = 'list(neg(macaddr))'; 500 | o.depends('client_usage_disturb', '1'); 501 | 502 | // 自动封禁 503 | o = s.taboption('ipset', form.Flag, 'login_web_black', _('Auto-ban unauthorized login devices')); 504 | o.default = '0'; 505 | o.depends({ login_notification: "web_login_failed", '!contains': true }); 506 | o.depends({ login_notification: "ssh_login_failed", '!contains': true }); 507 | 508 | o = s.taboption('ipset', form.Value, 'login_ip_black_timeout', _('Blacklisting time (s)')); 509 | o.default = '86400'; 510 | o.rmempty = false; 511 | o.datatype = 'and(uinteger,min(0))'; 512 | o.depends('login_web_black', '1'); 513 | o.description = _('\"0\" in ipset means permanent blacklist, use with caution. If misconfigured, change the device IP and clear rules in LUCI.
Note: The whitelist for bans is located under the \"Do Not Disturb\" tab.'); 514 | 515 | o = s.taboption('ipset', form.Flag, 'port_knocking_enable', _('Port knocking')); 516 | o.default = '0'; 517 | o.description = _('If you have disabled LAN port inbound and forwarding in Firewall - Zone Settings, it won\'t work.'); 518 | o.depends({ login_notification: "web_login_failed", '!contains': true }); 519 | o.depends({ login_notification: "ssh_login_failed", '!contains': true }); 520 | 521 | o = s.taboption('ipset', form.Value, 'login_port_white', _('Port')); 522 | o.default = ''; 523 | o.description = _('Open port after successful login
example:\"22\"、\"21:25\"、\"21:25,135:139\"'); 524 | o.depends('port_knocking_enable', '1'); 525 | 526 | o = s.taboption('ipset', form.DynamicList, 'login_port_forward_list', _('Port Forwards')); 527 | o.default = ''; 528 | o.description = _('Example: Forward port 13389 of this device (IPv4:10.0.0.1 / IPv6:fe80::10:0:0:2) to port 3389 of (IPv4:10.0.0.2 / IPv6:fe80::10:0:0:8)
\"10.0.0.1,13389,10.0.0.2,3389\"
\"fe80::10:0:0:1,13389,fe80::10:0:0:2,3389\"'); 529 | o.depends('port_knocking_enable', '1'); 530 | 531 | o = s.taboption('ipset', form.Value, 'login_ip_white_timeout', _('Release time (s)')); 532 | o.default = '86400'; 533 | o.datatype = 'and(uinteger,min(0))'; 534 | o.description = _('\"0\" in ipset means permanent release, use with caution'); 535 | o.depends('port_knocking_enable', '1'); 536 | 537 | o = s.taboption('ipset', form.TextValue, 'ip_black_list', _('IP blacklist')); 538 | o.rows = 8; 539 | o.wrap = 'soft'; 540 | o.cfgvalue = function (section_id) { 541 | return fs.trimmed('/usr/share/wechatpush/api/ip_blacklist'); 542 | }; 543 | o.write = function (section_id, formvalue) { 544 | return this.cfgvalue(section_id).then(function (value) { 545 | if (value == formvalue) { 546 | return 547 | } 548 | return fs.write('/usr/share/wechatpush/api/ip_blacklist', formvalue.trim().replace(/\r\n/g, '\n') + '\n'); 549 | }); 550 | }; 551 | o.depends('login_web_black', '1'); 552 | o.description = _('You can add or delete here, the numbers after represent the remaining time. When adding, only the IP needs to be entered.
Due to limitations on the web interface, please keep one empty line if you need to clear the content; otherwise, it will not be possible to submit. ╮(╯_╰)╭
Please use the 「Save」 button in the text box.'); 553 | 554 | // 定时推送 555 | o = s.taboption('crontab', cbiRichListValue, 'crontab_mode', _('Scheduled Tasks')); 556 | o.value('', _('Close'), 557 | _(' ')); 558 | o.value('1', _('Scheduled sending'), 559 | _('Send at the same time every day')); 560 | o.value('2', _('Interval sending'), 561 | _('Starting from 00:00, send every * hours')); 562 | 563 | o = s.taboption('crontab', form.MultiValue, 'crontab_regular_time', _('Sending time')); 564 | for (var t = 0; t <= 23; t++) { 565 | o.value(t, _('Every day') + t + _('clock')); 566 | } 567 | o.modalonly = true; 568 | o.depends("crontab_mode", "1"); 569 | 570 | o = s.taboption('crontab', form.ListValue, 'crontab_interval_time', _('Interval sending')); 571 | o.default = "6" 572 | for (var t = 0; t <= 12; t++) { 573 | o.value(t, _("") + t + _("Hour")); 574 | } 575 | o.default = ''; 576 | o.datatype = "uinteger"; 577 | o.depends('crontab_mode', '2'); 578 | o.description = _('Starting from 00:00, send every * hours'); 579 | 580 | o = s.taboption('crontab', form.Value, 'send_title', _('Push title')); 581 | o.depends('crontab_mode', '1'); 582 | o.depends('crontab_mode', '2'); 583 | o.placeholder = _('OpenWrt Router Status:'); 584 | o.description = _('Using special characters may cause sending failure'); 585 | 586 | o = s.taboption('crontab', form.MultiValue, 'send_notification', _('Push content')); 587 | o.value('router_status', _('System running status')); 588 | o.value('router_temp', _('Device temperature')); 589 | o.value('wan_info', _('WAN info')); 590 | o.value('client_list', _('Client list')); 591 | o.modalonly = true; 592 | o.depends('crontab_mode', '1'); 593 | o.depends('crontab_mode', '2'); 594 | 595 | o = s.taboption('crontab', form.Button, '_send', _('Manual sending'), _('You may need to save the configuration before sending.
Due to browser timeout limitations, if the program is not running, it may exit due to timeout during device list initialization')); 596 | o.inputstyle = 'add'; 597 | o.onclick = function () { 598 | var _this = this; 599 | return fs.exec(programPath, ['send']).then(function (res) { 600 | if (res.code === 0) 601 | _this.description = _('Message sent successfully. If you don\'t receive the message, please check the logs for manual processing.'); 602 | else if (res.code === 1) 603 | _this.description = _('Sending failed'); 604 | 605 | return _this.map.reset(); 606 | }).catch(function (err) { 607 | ui.addNotification(null, E('p', [_('Unknown error: %s.').format(err)])); 608 | _this.description = _('Sending failed'); 609 | return _this.map.reset(); 610 | }); 611 | } 612 | 613 | // 免打扰 614 | o = s.taboption('disturb', cbiRichListValue, 'do_not_disturb_mode', _('Do Not Disturb time setting')); 615 | o.value('', _('Close'), 616 | _(' ')); 617 | o.value('1', _('Mode 1: Script Suspension'), 618 | _('Suspend all script actions, including unattended tasks, until the end of the time period')); 619 | o.value('2', _('Mode 2: Silent Mode'), 620 | _('Stop sending notifications, but log normally')); 621 | 622 | o = s.taboption('disturb', form.ListValue, 'do_not_disturb_starttime', _('Do Not Disturb start time')); 623 | for (var t = 0; t <= 23; t++) { 624 | o.value(t, _('Every day') + t + _('clock')); 625 | } 626 | o.default = '0'; 627 | o.datatype = "uinteger" 628 | o.depends('do_not_disturb_mode', '1'); 629 | o.depends('do_not_disturb_mode', '2'); 630 | 631 | o = s.taboption('disturb', form.ListValue, 'do_not_disturb_endtime', _('Do Not Disturb end time')); 632 | for (var t = 0; t <= 23; t++) { 633 | o.value(t, _('Every day') + t + _('clock')); 634 | } 635 | o.default = 8 636 | o.datatype = "uinteger" 637 | o.depends('do_not_disturb_mode', '1'); 638 | o.depends('do_not_disturb_mode', '2'); 639 | 640 | o = s.taboption('disturb', cbiRichListValue, 'mac_filtering_mode_1', _('MAC Filtering Mode 1')); 641 | o.value('', _('Close'), 642 | _(' ')); 643 | o.value('allow', _('Ignore devices in the list'), 644 | _('Ignored devices will not receive notifications or be logged')); 645 | o.value('block', _('Notify only devices in the list'), 646 | _('Ignored devices will not receive notifications or be logged')); 647 | o.value('interface', _('Notify only devices using this interface'), 648 | _('Multiple selections are not supported at the moment')); 649 | 650 | o = fwtool.addMACOption(s, 'disturb', 'up_down_push_whitelist', _('Ignored device list'), 651 | _('Please select device MAC'), hosts); 652 | o.datatype = 'list(neg(macaddr))'; 653 | o.depends('mac_filtering_mode_1', 'allow'); 654 | 655 | o = fwtool.addMACOption(s, 'disturb', 'up_down_push_blacklist', _('Followed device list'), 656 | _('Please select device MAC'), hosts); 657 | o.datatype = 'list(neg(macaddr))'; 658 | o.depends('mac_filtering_mode_1', 'block'); 659 | o.description = _('AA:AA:AA:AA:AA:AA\\|BB:BB:BB:BB:BB:BB Multiple MAC addresses can be treated as the same user.
Notifications will not be sent once any device is online, and notifications will only be sent when all devices are offline to avoid frequent notifications in dual Wi-Fi scenarios.'); // 有点问题,待修复 660 | 661 | o = s.taboption('disturb', widgets.DeviceSelect, 'up_down_push_interface', _("Device")); 662 | o.description = _('Notify only devices using this interface'); 663 | o.modalonly = true; 664 | o.multiple = false; 665 | o.depends('mac_filtering_mode_1', 'interface'); 666 | 667 | o = s.taboption('disturb', cbiRichListValue, 'mac_filtering_mode_2', _('MAC Filtering Mode 2')); 668 | o.value('', _('Close'), 669 | _(' ')); 670 | o.value('mac_online', _('Do Not Disturb when devices are online'), 671 | _('No notifications will be sent when any device in the list is online')); 672 | o.value('mac_offline', _('Do Not Disturb when devices are offline'), 673 | _('No notifications will be sent when any device in the list is offline')); 674 | 675 | o = fwtool.addMACOption(s, 'disturb', 'mac_online_list', _('Do Not Disturb device online list'), 676 | _('Please select device MAC'), hosts); 677 | o.datatype = 'list(neg(macaddr))'; 678 | o.depends('mac_filtering_mode_2', 'mac_online'); 679 | 680 | o = fwtool.addMACOption(s, 'disturb', 'mac_offline_list', _('Do Not Disturb device offline list'), 681 | _('Please select device MAC'), hosts); 682 | o.datatype = 'list(neg(macaddr))'; 683 | o.depends('mac_filtering_mode_2', 'mac_offline'); 684 | 685 | o = s.taboption('disturb', form.Value, 'cpu_threshold_duration', _('When CPU temperature or load exceeds the threshold continuously for (s) seconds.')); 686 | o.rmempty = false; 687 | o.default = '300'; 688 | o.datatype = 'and(uinteger)'; 689 | o.description = _('If set to 0, it\'s a single check without considering duration.'); 690 | o.depends({ cpu_notification: "temp", '!contains': true }); 691 | o.depends({ cpu_notification: "load", '!contains': true }); 692 | 693 | o = s.taboption('disturb', form.Value, 'cpu_notification_delay', _('CPU alarm quiet time (seconds)')); 694 | o.rmempty = false; 695 | o.default = '3600'; 696 | o.datatype = 'and(uinteger)'; 697 | o.description = _('No repeat notifications within the set time after the initial push notification.'); 698 | o.depends({ cpu_notification: "temp", '!contains': true }); 699 | o.depends({ cpu_notification: "load", '!contains': true }); 700 | 701 | o = s.taboption('disturb', cbiRichListValue, 'login_disturb', _('Do Not Disturb for Login Reminders')); 702 | o.value('', _('Close'), 703 | _(' ')); 704 | o.value('1', _('Only record in the log'), 705 | _('Ignore all login notifications (including failed logins), and only record them in the log.')); 706 | o.value('2', _('Send notification only on the first login'), 707 | _('Send notification only once within the specified time interval.')); 708 | 709 | o = fwtool.addIPOption(s, 'disturb', 'login_ip_white_list', _('Login Alert (Auto-Ban) Whitelist'), null, 'ipv4', hosts, true); 710 | o.datatype = 'ipaddr'; 711 | o.depends({ login_notification: "web_logged", '!contains': true }); 712 | o.depends({ login_notification: "ssh_logged", '!contains': true }); 713 | o.depends({ login_notification: "web_login_failed", '!contains': true }); 714 | o.depends({ login_notification: "ssh_login_failed", '!contains': true }); 715 | o.description = _('Add the IP addresses in the list to the whitelist for the blocking function (if available), and ignore automatic blocking and login event notifications. Only record in the log. Mask notation is currently not supported.'); 716 | 717 | o = s.taboption('disturb', form.Flag, 'login_log_enable', _('Login reminder log anti-flooding')); 718 | o.description = _('Users in the whitelist or during the undisturbed time period after their first login IP will be exempt from log recording, preventing log flooding.'); 719 | o.depends('login_disturb', '1'); 720 | o.depends('login_disturb', '2'); 721 | 722 | o = s.taboption('disturb', form.Value, 'login_notification_delay', _('Login reminder do not disturb time (s)')); 723 | o.rmempty = false; 724 | o.placeholder = '3600'; 725 | o.datatype = 'and(uinteger,min(10))'; 726 | o.description = _('Send notification after the first login and do not repeat within the specified time
Take a shortcut and read the login time from the log'); 727 | o.depends('login_disturb', '2'); 728 | 729 | return m.render(); 730 | } 731 | }); 732 | -------------------------------------------------------------------------------- /htdocs/luci-static/resources/view/wechatpush/log.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 'require dom'; 3 | 'require fs'; 4 | 'require poll'; 5 | 'require uci'; 6 | 'require view'; 7 | 'require form'; 8 | 9 | return view.extend({ 10 | render: function () { 11 | var css = ` 12 | /* 日志框文本区域 */ 13 | #log_textarea { 14 | margin-top: 10px; 15 | } 16 | #log_textarea pre { 17 | padding: 10px; /* 内边距 */ 18 | border: 1px solid #ddd; /* 边框颜色 */ 19 | border-radius: 6px; /* 边框圆角 */ 20 | font-family: Consolas, Menlo, Monaco, monospace; 21 | font-size: 14px; 22 | line-height: 1.6; /* 行高 */ 23 | white-space: pre-wrap; 24 | word-wrap: break-word; 25 | overflow-y: auto; 26 | max-height: 600px; 27 | } 28 | /* 5s 自动刷新文字 */ 29 | .cbi-section small { 30 | margin-left: 5px; 31 | font-size: 12px; 32 | color: #666; /* 深灰色文字 */ 33 | } 34 | `; 35 | 36 | var log_textarea = E('div', { 'id': 'log_textarea' }, 37 | E('img', { 38 | 'src': L.resource(['icons/loading.gif']), 39 | 'alt': _('Loading...'), 40 | 'style': 'vertical-align:middle' 41 | }, _('Collecting data ...')) 42 | ); 43 | 44 | var log_path = '/tmp/wechatpush/wechatpush.log'; 45 | var lastLogContent = ''; 46 | 47 | var clear_log_button = E('div', {}, [ 48 | E('button', { 49 | 'class': 'cbi-button cbi-button-remove', 50 | 'click': function (ev) { 51 | ev.preventDefault(); 52 | var button = ev.target; 53 | button.disabled = true; 54 | button.textContent = _('Clear Logs...'); 55 | fs.exec_direct('/usr/libexec/wechatpush-call', ['clear_log']) 56 | .then(function () { 57 | button.textContent = _('Logs cleared successfully!'); 58 | button.disabled = false; 59 | button.textContent = _('Clear Logs'); 60 | // 立即刷新日志显示框 61 | var log = E('pre', { 'wrap': 'pre' }, [_('Log is clean.')]); 62 | dom.content(log_textarea, log); 63 | lastLogContent = ''; 64 | }) 65 | .catch(function () { 66 | button.textContent = _('Failed to clear log.'); 67 | button.disabled = false; 68 | button.textContent = _('Clear Logs'); 69 | }); 70 | } 71 | }, _('Clear Logs')) 72 | ]); 73 | 74 | poll.add(L.bind(function () { 75 | return fs.read_direct(log_path, 'text') 76 | .then(function (res) { 77 | var newContent = res.trim() || _('Log is clean.'); 78 | 79 | if (newContent !== lastLogContent) { 80 | var log = E('pre', { 'wrap': 'pre' }, [newContent]); 81 | dom.content(log_textarea, log); 82 | log.scrollTop = log.scrollHeight; 83 | lastLogContent = newContent; 84 | } 85 | }).catch(function (err) { 86 | var log; 87 | if (err.toString().includes('NotFoundError')) { 88 | log = E('pre', { 'wrap': 'pre' }, [_('Log file does not exist.')]); 89 | } else { 90 | log = E('pre', { 'wrap': 'pre' }, [_('Unknown error: %s').format(err)]); 91 | } 92 | dom.content(log_textarea, log); 93 | }); 94 | })); 95 | 96 | return E('div', { 'class': 'cbi-map' }, [ 97 | E('style', [css]), 98 | E('div', { 'class': 'cbi-section' }, [ 99 | clear_log_button, 100 | log_textarea, 101 | E('small', {}, _('Refresh every 5 seconds.').format(L.env.pollinterval)), 102 | E('div', { 'class': 'cbi-section-actions cbi-section-actions-right' }) 103 | ]) 104 | ]); 105 | }, 106 | 107 | handleSaveApply: null, 108 | handleSave: null, 109 | handleReset: null 110 | }); 111 | -------------------------------------------------------------------------------- /htdocs/luci-static/resources/view/wechatpush/status.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 'require view'; 3 | 'require rpc'; 4 | 5 | var callServiceList = rpc.declare({ 6 | object: 'service', 7 | method: 'list', 8 | params: ['name'], 9 | expect: { '': {} } 10 | }); 11 | 12 | function getServiceStatus() { 13 | return L.resolveDefault(callServiceList('wechatpush'), {}).then(function (res) { 14 | console.log(res); 15 | var isRunning = false; 16 | try { 17 | isRunning = res['wechatpush']['instances']['instance1']['running']; 18 | } catch (e) { } 19 | return isRunning; 20 | }); 21 | } 22 | 23 | return view.extend({ 24 | load: function () { 25 | return getServiceStatus(); 26 | }, 27 | 28 | render: function (status) { 29 | // 如果服务正在运行,跳转到 client 页面 30 | if (status) { 31 | window.location.pathname = '/cgi-bin/luci/admin/services/wechatpush/client'; 32 | } else { 33 | window.location.pathname = '/cgi-bin/luci/admin/services/wechatpush/config'; 34 | } 35 | }, 36 | 37 | handleSave: null, 38 | handleSaveApply: null, 39 | handleReset: null 40 | }); 41 | -------------------------------------------------------------------------------- /po/zh_Hans/wechatpush.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "PO-Revision-Date: 2023-06-01 20:00+0000\n" 4 | "Last-Translator: https://github.com/tty228/luci-app-wechatpush \n" 5 | "Language-Team: \n" 6 | "Language: zh_Hans\n" 7 | "Content-Type: text/plain; charset=UTF-8\n" 8 | "Content-Transfer-Encoding: 8bit\n" 9 | "X-Generator: Weblate 4.18-dev\n" 10 | 11 | #: applications/luci-app-wechatpush/root/usr/share/luci/menu.d/luci-app-wechatpush.json:3 12 | msgid "WeChat push" 13 | msgstr "微信推送" 14 | 15 | #: applications/luci-app-wechatpush/root/usr/share/luci/menu.d/luci-app-wechatpush.json:15 16 | msgid "Basic Settings" 17 | msgstr "基本设置" 18 | 19 | #: applications/luci-app-wechatpush/root/usr/share/luci/menu.d/luci-app-wechatpush.json:24 20 | msgid "Advance Setting" 21 | msgstr "高级设置" 22 | 23 | #: applications/luci-app-wechatpush/root/usr/share/luci/menu.d/luci-app-wechatpush.json:33 24 | msgid "Online Devices" 25 | msgstr "在线设备" 26 | 27 | #: applications/luci-app-wechatpush/root/usr/share/luci/menu.d/luci-app-wechatpush.json:33 28 | msgid "Log" 29 | msgstr "日志" 30 | 31 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:101 32 | msgid "A tool that can push device messages from OpenWrt to a mobile phone via WeChat or Telegram.

If you encounter any issues while using it, please submit them here:" 33 | msgstr "一个通过微信或 Telegram,从 OpenWrt 上推送设备消息到手机的工具

如果你在使用中遇到问题,请到这里提交:" 34 | 35 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:101 36 | msgid "GitHub Project Address" 37 | msgstr "GitHub 项目地址" 38 | 39 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:124 40 | msgid "Push Content" 41 | msgstr "推送内容" 42 | 43 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:125 44 | msgid "Auto Ban" 45 | msgstr "自动封禁" 46 | 47 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:126 48 | msgid "Scheduled Push" 49 | msgstr "定时推送" 50 | 51 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:127 52 | msgid "Do Not Disturb" 53 | msgstr "免打扰" 54 | 55 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:134 56 | msgid "Push Mode" 57 | msgstr "推送模式" 58 | 59 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:134 60 | msgid "Do not use push notifications, only use other features." 61 | msgstr "不使用推送通知,仅使用其他功能" 62 | 63 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:135 64 | msgid "WeChat serverchan" 65 | msgstr "微信 Server 酱" 66 | 67 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:136 68 | msgid "Using serverchan API, simple configuration, supports multiple push methods" 69 | msgstr "使用 Server酱 接口,配置较简单,支持多项推送方式" 70 | 71 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js 72 | msgid "Serverchan3 APP" 73 | msgstr "Server 酱 APP" 74 | 75 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js 76 | msgid "Using serverchan3 API, simple configuration, support push to ServerChan App" 77 | msgstr "使用 ServerChan3 接口,配置较简单,支持推送到Server酱 APP" 78 | 79 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:137 80 | msgid "WeChat Work Image Message" 81 | msgstr "企业微信 图文消息" 82 | 83 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:138 84 | msgid "Using WeChat Work application message, more complex configuration, and starting from June 20, 2022, additional configuration for trusted IP is required. Trusted IP cannot be shared. This channel is no longer recommended." 85 | msgstr "使用 企业微信应用消息,配置较为麻烦,且 2022 年 6 月 20 日之后新创建的应用,需要额外配置可信 IP,可信 IP 不可公用,不再推荐此通道" 86 | 87 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:139 88 | msgid "WeChat Work Markdown Version" 89 | msgstr "企业微信 markdown 版" 90 | 91 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:140 92 | msgid "WeChat Work application message in plain text format, no need to click the title to view the content, same as above" 93 | msgstr "企业微信应用消息 纯文字版,无需点击标题查看内容,其他同上" 94 | 95 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:142 96 | msgid "Another channel for WeChat push, the configuration is relatively simple, and only supports official accounts" 97 | msgstr "微信推送的另一个通道,配置较简单,只支持公众号" 98 | 99 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:144 100 | msgid "Another channel for WeChat push, the configuration is relatively simple, and it supports multiple push methods" 101 | msgstr "微信推送的另一个通道,配置较简单,支持多项推送方式" 102 | 103 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:146 104 | msgid "Telegram Bot Push" 105 | msgstr "Telegram bot 推送,若无梯子,请勿使用" 106 | 107 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:147 108 | msgid "Custom Push" 109 | msgstr "自定义推送" 110 | 111 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:152 112 | msgid "To send emails using msmtp, you must manually install msmtp and configure `/etc/msmtprc`." 113 | msgstr "使用 msmtp 发送邮件,你必须自行安装 msmtp 和配置 `/etc/msmtprc`" 114 | 115 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:148 116 | msgid "By modifying the JSON file, you can use a custom API" 117 | msgstr "通过修改 JSON 文件,使用自定义接口" 118 | 119 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:150 120 | msgid "「wechatpush」sendkey" 121 | msgstr "「Server酱」sendkey" 122 | 123 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js 124 | msgid "「Serverchan3」sendkey" 125 | msgstr "「Server酱3」sendkey" 126 | 127 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js 128 | msgid "「Serverchan3」uid" 129 | msgstr "「Server酱3」uid" 130 | 131 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js 132 | msgid "ServerChan3 uid" 133 | msgstr "Server酱3 用户独立uid" 134 | 135 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js 136 | msgid "「Serverchan3」tags" 137 | msgstr "「Server酱3」消息标签" 138 | 139 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js 140 | msgid "ServerChan3 message tags, split with |" 141 | msgstr "Server酱3 使用标签来标记消息类型,支持多个使用|分隔" 142 | 143 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:151 144 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:156 145 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:184 146 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:193 147 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:198 148 | msgid "Get Instructions" 149 | msgstr "获取说明" 150 | 151 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:151 152 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:156 153 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:184 154 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:193 155 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:198 156 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:203 157 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:208 158 | msgid "Click here" 159 | msgstr "点击这里" 160 | 161 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:155 162 | msgid "corpid" 163 | msgstr "企业ID(corpid)" 164 | 165 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:161 166 | msgid "userid" 167 | msgstr "帐号(userid)" 168 | 169 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:163 170 | msgid "Send to All App Users, enter @all" 171 | msgstr "群发到应用请填入 @all" 172 | 173 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:167 174 | msgid "agentid" 175 | msgstr "应用id(agentid)" 176 | 177 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:172 178 | msgid "Secret" 179 | msgstr "应用密钥(Secret)" 180 | 181 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:177 182 | msgid "Thumbnail Image File Path" 183 | msgstr "图片缩略图文件路径" 184 | 185 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:181 186 | msgid "Supports JPG and PNG formats within 2MB
Optimal size: 900383 or 2.35:1" 187 | msgstr "只支持 2MB 以内 JPG、PNG 格式
最佳尺寸:900383 或 2.35:1" 188 | 189 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:183 190 | msgid "Trusted IP address" 191 | msgstr "可信 IP 地址" 192 | 193 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:187 194 | msgid "If the application was created after June 20, 2022, you need to set the trusted IP. This option should be used in conjunction with a proxy server." 195 | msgstr "如果是 2022 年 6 月 20 日之后新创建的应用,需设置可信 IP,该选项需配合代理服务器使用" 196 | 197 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:192 198 | msgid "topicIds(Mass sending)" 199 | msgstr "topicIds(群发)" 200 | 201 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:203 202 | msgid "Get Bot" 203 | msgstr "获取机器人" 204 | 205 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:203 206 | msgid "
Send a message to the created bot to initiate a conversation." 207 | msgstr "
与创建的机器人发一条消息,开启对话" 208 | 209 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:208 210 | msgid "Get chat_id" 211 | msgstr "获取 chat_id" 212 | 213 | msgid "Recipient Email Address" 214 | msgstr "收件邮箱地址" 215 | 216 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:208 217 | msgid "
If you want to send to a group/channel, please create a non-Chinese group/channel (for easier chatid lookup, you can rename it later).
Add the bot to the group, send a message, and use https://api.telegram.org/bot token /getUpdates to obtain the chatid." 218 | msgstr "
如需通过群组/频道推送,请创建一个非中文的群组或频道(便于查找 chatid,后续再更名)
将机器人添加至群组,发送信息后通过 https://api.telegram.org/bot token /getUpdates 获取 chatid" 219 | 220 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:226 221 | msgid "Please refer to the comments and other interface files for modifications. Limited resources, no longer supporting more interfaces, please debug on your own.
You can use a similar website to check the JSON file format: https://www.google.com/search?q=JSON+Parser+Online
Please use the 「Save」 button in the text box." 222 | msgstr "请参照注释和其他接口文件修改,精力有限,不再支持更多接口,自行调试
请参考类似网站检查 JSON 文件格式:https://www.baidu.com/s?wd=json在线解析
文本框请使用「保存」按钮" 223 | 224 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:229 225 | msgid "Proxy Address" 226 | msgstr "代理地址" 227 | 228 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:230 229 | msgid "When you want to use a proxy to push information, you can use this option.
This may be helpful for scenarios like trusted IPs for WeChat Work.Using special characters may cause sending failure.
Example:
http://username:password@127.0.0.1:1080
socks5://username:password@127.0.0.1:1080" 230 | msgstr "当你想要使用代理推送信息时,可以使用这个选项
可能有助于企业微信可信 IP 等情况,默认为空,使用特殊符号可能会造成发送失败
例子:
http://username:password@127.0.0.1:1080
socks5://username:password@127.0.0.1:1080" 231 | 232 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:230 233 | msgid "Send Test" 234 | msgstr "发送测试" 235 | 236 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:230 237 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:67 238 | msgid "You may need to save the configuration before sending." 239 | msgstr "你可能需要先保存配置再进行发送" 240 | 241 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:236 242 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:578 243 | msgid "Message sent successfully. If you don't receive the message, please check the logs for manual processing." 244 | msgstr "发送成功,如果收不到信息,请查看日志手动处理" 245 | 246 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:238 247 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:243 248 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:579 249 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:584 250 | msgid "Sending failed" 251 | msgstr "发送失败" 252 | 253 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:242 254 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:277 255 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:350 256 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:401 257 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:583 258 | msgid "Unknown error: %s." 259 | msgstr "未知错误:%s" 260 | 261 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:248 262 | msgid "Device Name" 263 | msgstr "设备名称" 264 | 265 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:249 266 | msgid "The device name will be displayed in the push message title to identify the source device of the message." 267 | msgstr "在推送信息标题中会标识本设备名称,用于区分推送信息的来源设备" 268 | 269 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:251 270 | msgid "Check Interval (s)" 271 | msgstr "检测时间间隔(秒)" 272 | 273 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:255 274 | msgid "Shorter intervals provide quicker response but consume more system resources." 275 | msgstr "越短的时间间隔响应越及时,但会占用更多的系统资源" 276 | 277 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:257 278 | msgid "MAC Device Database" 279 | msgstr "MAC 设备数据库" 280 | 281 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:259 282 | msgid "Do not use MAC device database" 283 | msgstr "不使用 MAC 设备数据库" 284 | 285 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:260 286 | msgid "Simplified Version" 287 | msgstr "简化版" 288 | 289 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:261 290 | msgid "Includes common device manufacturers, occupies approximately 200Kb of space" 291 | msgstr "仅包含常见设备厂商,约占用 200Kb 空间" 292 | 293 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:262 294 | msgid "Full Version" 295 | msgstr "完整版" 296 | 297 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:263 298 | msgid "Download the complete database, processed size is approximately 1.3Mb" 299 | msgstr "下载完整数据,处理后约占用 1.3Mb 空间" 300 | 301 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:264 302 | msgid "Network Query" 303 | msgstr "网络查询" 304 | 305 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:265 306 | msgid "Enables network query, slower response. Only use if space is limited." 307 | msgstr "网络查询,查询速度较慢且需要梯子,除非空间紧缺,否则请勿使用" 308 | 309 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:267 310 | msgid "Update MAC Device Database" 311 | msgstr "更新 MAC 设备数据库" 312 | 313 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:273 314 | msgid "Database is up to date, skipping update" 315 | msgstr "已是最新,跳过更新" 316 | 317 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:278 318 | msgid "Browser timeout or unknown error. If the log shows that the update process has been established, please ignore this error: %s." 319 | msgstr "浏览器超时强制退出或未知错误,若日志显示已建立更新进程,请忽略此错误:%s" 320 | 321 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:285 322 | msgid "Reset Traffic Data Every Day at Midnight" 323 | msgstr "每天零点重置流量数据" 324 | 325 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:287 326 | msgid "Enable Logging" 327 | msgstr "开启日志" 328 | 329 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:289 330 | msgid "Device Alias" 331 | msgstr "设备别名" 332 | 333 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:303 334 | msgid "Please enter the device MAC and device alias separated by a space, such as:
XX:XX:XX:XX:XX:XX My Phone
192.168.1.2 My PC
Please use the 「Save」 button in the text box." 335 | msgstr "请输入设备 MAC 和设备别名,用空格隔开,例如:
XX:XX:XX:XX:XX:XX 我的手机
192.168.1.2 我的电脑
文本框请使用「保存」按钮" 336 | 337 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:306 338 | msgid "Test IP acquisition command" 339 | msgstr "测试 IP 获取命令" 340 | 341 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:306 342 | msgid "IPv4 Dynamic Notification" 343 | msgstr "IPv4 变动通知" 344 | 345 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:309 346 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:360 347 | msgid "Obtain through interface" 348 | msgstr "通过网络接口获取" 349 | 350 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:311 351 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:362 352 | msgid "Obtain through URL" 353 | msgstr "通过 URL 获取" 354 | 355 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:312 356 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:363 357 | msgid "May fail due to server stability and frequent connections.
If the interface can obtain the IP address properly, it is not recommended to use this method." 358 | msgstr "会因服务器稳定性、连接频繁等原因导致获取失败。
如接口可以正常获取 IP,不推荐使用此方法。" 359 | 360 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:337 361 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:388 362 | msgid "Access a random address from the list above,URLs in the list are specific to Chinese websites. If you need to use this feature, please replace the URLs with the ones available to you.
Please use the 「Save」 button in the text box." 363 | msgstr "从以上列表中随机访问地址
文本框请使用「保存」按钮" 364 | 365 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:315 366 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:366 367 | msgid "Generally, it should be the pppoe-wan or WAN interface. For multi-dial environments, please select the appropriate interface yourself." 368 | msgstr "一般应为 pppoe-wan 或 WAN 接口。多拨环境请自行选择。" 369 | 370 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:321 371 | msgid "IPv4 API List" 372 | msgstr "IPv4 API 列表" 373 | 374 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:339 375 | msgid "Update IPv4 list" 376 | msgstr "更新 IPv4 list" 377 | 378 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:345 379 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:396 380 | msgid "Update successful" 381 | msgstr "更新成功" 382 | 383 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:347 384 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:351 385 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:398 386 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:402 387 | msgid "Update failed" 388 | msgstr "更新失败" 389 | 390 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:357 391 | msgid "IPv6 Dynamic Notification" 392 | msgstr "IPv6 变动通知" 393 | 394 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:372 395 | msgid "IPv6 API List" 396 | msgstr "IPv6 API 列表" 397 | 398 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:390 399 | msgid "Update IPv6 list" 400 | msgstr "更新 IPv6 list" 401 | 402 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:408 403 | msgid "Automatically update API list" 404 | msgstr "API 列表自动更新" 405 | 406 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:409 407 | msgid "When multiple IP retrieval attempts fail, try to automatically update the list file from GitHub" 408 | msgstr "当多次获取 IP 失败时,尝试自动从 GitHub 上更新列表文件
因为懒得做外链,所以请确保你可以链接 raw.githubusercontent.com" 409 | 410 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:413 411 | msgid "Device Online/Offline Notification" 412 | msgstr "设备上下线通知" 413 | 414 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:414 415 | msgid "Online Notification" 416 | msgstr "上线通知" 417 | 418 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:415 419 | msgid "Offline Notification" 420 | msgstr "下线通知" 421 | 422 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:418 423 | msgid "CPU Alert" 424 | msgstr "CPU 报警" 425 | 426 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:419 427 | msgid "Load Alert" 428 | msgstr "负载报警" 429 | 430 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:420 431 | msgid "Temperature Alert" 432 | msgstr "温度报警" 433 | 434 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:422 435 | msgid "Device alert will be triggered only if it exceeds the set value continuously for five minutes, and there won't be a second reminder within an hour." 436 | msgstr "设备报警只会在连续五分钟超过设定值时才会推送,一个小时内不会再提醒第二次。" 437 | 438 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:424 439 | msgid "Load alert threshold" 440 | msgstr "负载报警阈值" 441 | 442 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:451 443 | msgid "In general, when the load value is lower than the number of logical cores, you typically don't need to pay much attention to it." 444 | msgstr "通常情况下,负载值低于逻辑核心数量时,你不需要关注它" 445 | 446 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:433 447 | msgid "Please enter a numeric value only" 448 | msgstr "请输入纯数字" 449 | 450 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:436 451 | msgid "Temperature alert threshold" 452 | msgstr "温度报警阈值" 453 | 454 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:441 455 | msgid "Please confirm that the device can retrieve temperature. If you need to modify the command, please go to advanced settings." 456 | msgstr "请确认设备可以获取温度。如果需修改命令,请移步高级设置。" 457 | 458 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:443 459 | msgid "Login Notification" 460 | msgstr "登录提醒" 461 | 462 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:444 463 | msgid "Web Login" 464 | msgstr "Web 登录" 465 | 466 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:445 467 | msgid "SSH Login" 468 | msgstr "SSH 登录" 469 | 470 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:446 471 | msgid "Frequent Web Login Errors" 472 | msgstr "Web 频繁错误登录" 473 | 474 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:447 475 | msgid "Frequent SSH Login Errors" 476 | msgstr "SSH 频繁错误登录" 477 | 478 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:450 479 | msgid "Login failure count" 480 | msgstr "登录失败次数" 481 | 482 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:456 483 | msgid "Send notification after exceeding the count, and optionally auto-ban IP" 484 | msgstr "超过次数后推送提醒,并可选自动封禁 IP" 485 | 486 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:458 487 | msgid "Device abnormal traffic alert" 488 | msgstr "设备异常流量警报" 489 | 490 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:459 491 | msgid "Please ensure that you can retrieve device traffic information correctly, otherwise this feature will not work properly" 492 | msgstr "请确保可以正确获取设备流量情况,否则此功能无法正常工作" 493 | 494 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:462 495 | msgid "Per-minute traffic limit" 496 | msgstr "每分钟流量限制" 497 | 498 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:466 499 | msgid "Abnormal traffic alert (byte), you can append K or M" 500 | msgstr "设备异常流量警报(byte),你可以追加 K 或者 M" 501 | 502 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:468 503 | msgid "Abnormal traffic do not disturb" 504 | msgstr "异常流量免打扰" 505 | 506 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:472 507 | msgid "Abnormal traffic monitoring list" 508 | msgstr "异常流量关注列表" 509 | 510 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:473 511 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:633 512 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:639 513 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:659 514 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:664 515 | msgid "Please select device MAC" 516 | msgstr "请选择设备 MAC" 517 | 518 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:479 519 | msgid "Auto-ban unauthorized login devices" 520 | msgstr "自动封禁非法登录设备" 521 | 522 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:484 523 | msgid "Blacklisting time (s)" 524 | msgstr "拉黑时间(秒)" 525 | 526 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:489 527 | msgid "\"0\" in ipset means permanent blacklist, use with caution. If misconfigured, change the device IP and clear rules in LUCI.
Note: The whitelist for bans is located under the \"Do Not Disturb\" tab." 528 | msgstr "ipset 中, \"0\" 为永久拉黑,慎用。如不幸误操作,请更改设备 IP 进入 LUCI 界面清空规则。
注:封禁白名单位于 “免打扰” 选项卡。" 529 | 530 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:491 531 | msgid "Port knocking" 532 | msgstr "端口敲门" 533 | 534 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:497 535 | msgid "Port" 536 | msgstr "端口" 537 | 538 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:499 539 | msgid "Open port after successful login
example:\"22\"、\"21:25\"、\"21:25,135:139\"" 540 | msgstr "登录成功后开放端口
例:\"22\"、\"21:25\"、\"21:25,135:139\"" 541 | 542 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:494 543 | msgid "If you have disabled LAN port inbound and forwarding in Firewall - Zone Settings, it won't work." 544 | msgstr "如在 防火墙 - 区域设置 中禁用了 LAN 口入站和转发,该功能将不起作用" 545 | 546 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:505 547 | msgid "Example: Forward port 13389 of this device (IPv4:10.0.0.1 / IPv6:fe80::10:0:0:2) to port 3389 of (IPv4:10.0.0.2 / IPv6:fe80::10:0:0:8)
\"10.0.0.1,13389,10.0.0.2,3389\"
\"fe80::10:0:0:1,13389,fe80::10:0:0:2,3389\"" 548 | msgstr "例:将本机 (IPv4:10.0.0.1 / IPv6:fe80::10:0:0:2) 的 13389 端口转发到 (IPv4:10.0.0.2 / IPv6:fe80::10:0:0:8) 的 3389 端口:
\"10.0.0.1,13389,10.0.0.2,3389\"
\"fe80::10:0:0:2,13389,fe80::10:0:0:8,3389\"" 549 | 550 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:508 551 | msgid "Release time (s)" 552 | msgstr "放行时间(秒)" 553 | 554 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:494 555 | msgid "\"0\" in ipset means permanent release, use with caution" 556 | msgstr "ipset 中, \"0\" 为永久放行,慎用" 557 | 558 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:514 559 | msgid "IP blacklist" 560 | msgstr "IP 黑名单列表" 561 | 562 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:529 563 | msgid "You can add or delete here, the numbers after represent the remaining time. When adding, only the IP needs to be entered.
Due to limitations on the web interface, please keep one empty line if you need to clear the content; otherwise, it will not be possible to submit. ╮(╯_╰)╭
Please use the 「Save」 button in the text box." 564 | msgstr "可在此处添加或删除,后面的数字为剩余时间,添加时只需要输入 IP
由于网页端的限制,如需清空内容,请保留一处空白的换行,否则内容为空会导致无法提交 ╮(╯_╰)╭
文本框请使用「保存」按钮" 565 | 566 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:535 567 | msgid "Scheduled sending" 568 | msgstr "定时发送" 569 | 570 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:536 571 | msgid "Send at the same time every day" 572 | msgstr "每天固定时间发送" 573 | 574 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:537 575 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:547 576 | msgid "Interval sending" 577 | msgstr "间隔发送" 578 | 579 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:538 580 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:555 581 | msgid "Starting from 00:00, send every * hours" 582 | msgstr "从 00:00 开始,每 * 小时发送一次" 583 | 584 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:540 585 | msgid "Sending time" 586 | msgstr "发送时间" 587 | 588 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:542 589 | msgid "Every day" 590 | msgstr "每天" 591 | 592 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:542 593 | msgid "clock" 594 | msgstr "点" 595 | 596 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:557 597 | msgid "Push title" 598 | msgstr "推送标题" 599 | 600 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:560 601 | msgid "OpenWrt Router Status:" 602 | msgstr "OpenWrt 路由状态:" 603 | 604 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:561 605 | msgid "Using special characters may cause sending failure" 606 | msgstr "使用特殊符号可能会造成发送失败" 607 | 608 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:563 609 | msgid "Push content" 610 | msgstr "推送内容" 611 | 612 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:564 613 | msgid "System running status" 614 | msgstr "系统运行情况" 615 | 616 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:565 617 | msgid "Device temperature" 618 | msgstr "设备温度" 619 | 620 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:566 621 | msgid "WAN info" 622 | msgstr "WAN 信息" 623 | 624 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:567 625 | msgid "Client list" 626 | msgstr "客户端列表" 627 | 628 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:572 629 | msgid "Manual sending" 630 | msgstr "手动发送" 631 | 632 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:572 633 | msgid "You may need to save the configuration before sending.
Due to browser timeout limitations, if the program is not running, it may exit due to timeout during device list initialization" 634 | msgstr "你可能需要先保存配置再进行发送
由于浏览器超时限制,若程序未在运行,可能会因初始化设备列表超时退出" 635 | 636 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:591 637 | msgid "Simplified mode" 638 | msgstr "精简模式" 639 | 640 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:592 641 | msgid "Simplify the current device list" 642 | msgstr "精简当前设备列表" 643 | 644 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:593 645 | msgid "Simplify the current time" 646 | msgstr "精简当前时间" 647 | 648 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:594 649 | msgid "Push only the title" 650 | msgstr "只推送标题" 651 | 652 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:596 653 | msgid "Do Not Disturb time setting" 654 | msgstr "免打扰时段设置" 655 | 656 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:599 657 | msgid "Mode 1: Script Suspension" 658 | msgstr "模式一:脚本挂起" 659 | 660 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:600 661 | msgid "Suspend all script actions, including unattended tasks, until the end of the time period" 662 | msgstr "暂停脚本任何动作,包括无人值守任务,直到时段结束" 663 | 664 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:601 665 | msgid "Mode 2: Silent Mode" 666 | msgstr "模式二:静默模式" 667 | 668 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:602 669 | msgid "Stop sending notifications, but log normally" 670 | msgstr "停止信息推送,但正常记录日志" 671 | 672 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:604 673 | msgid "Do Not Disturb start time" 674 | msgstr "免打扰开始时间" 675 | 676 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:613 677 | msgid "Do Not Disturb end time" 678 | msgstr "免打扰结束时间" 679 | 680 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:622 681 | msgid "MAC Filtering Mode 1" 682 | msgstr "MAC 过滤模式一" 683 | 684 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:625 685 | msgid "Ignore devices in the list" 686 | msgstr "忽略列表内设备" 687 | 688 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:626 689 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:628 690 | msgid "Ignored devices will not receive notifications or be logged" 691 | msgstr "被忽略设备不做推送和日志记录" 692 | 693 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:627 694 | msgid "Notify only devices in the list" 695 | msgstr "仅通知列表内设备" 696 | 697 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:629 698 | msgid "Notify only devices using this interface" 699 | msgstr "仅通知此接口设备" 700 | 701 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:630 702 | msgid "Multiple selections are not supported at the moment" 703 | msgstr "暂不支持多选" 704 | 705 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:632 706 | msgid "Ignored device list" 707 | msgstr "忽略设备列表" 708 | 709 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:637 710 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:148 711 | msgid "Followed device list" 712 | msgstr "关注设备列表" 713 | 714 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:641 715 | msgid "AA:AA:AA:AA:AA:AA\\|BB:BB:BB:BB:BB:BB Multiple MAC addresses can be treated as the same user.
Notifications will not be sent once any device is online, and notifications will only be sent when all devices are offline to avoid frequent notifications in dual Wi-Fi scenarios." 716 | msgstr "AA:AA:AA:AA:AA:AA\\|BB:BB:BB:BB:BB:BB 可以将多个 MAC 视为同一用户
任一设备在线后不再推送,设备全部离线时才会推送,避免双 wifi 频繁推送" 717 | 718 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:644 719 | msgid "Notify only devices using this interface" 720 | msgstr "仅通知此接口设备" 721 | 722 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:649 723 | msgid "MAC Filtering Mode 2" 724 | msgstr "MAC 过滤模式二" 725 | 726 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:652 727 | msgid "Do Not Disturb when devices are online" 728 | msgstr "设备在线时免打扰" 729 | 730 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:653 731 | msgid "No notifications will be sent when any device in the list is online" 732 | msgstr "当列表内任意设备在线时,不推送信息" 733 | 734 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:654 735 | msgid "Do Not Disturb when devices are offline" 736 | msgstr "设备离线后免打扰" 737 | 738 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:655 739 | msgid "No notifications will be sent when any device in the list is offline" 740 | msgstr "当列表内任意设备离线后,不推送信息" 741 | 742 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:657 743 | msgid "Do Not Disturb device online list" 744 | msgstr "设备在线免打扰列表" 745 | 746 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:662 747 | msgid "Do Not Disturb device offline list" 748 | msgstr "设备离线免打扰列表" 749 | 750 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:682 751 | msgid "When CPU temperature or load exceeds the threshold continuously for (s) seconds." 752 | msgstr "当 CPU 温度或负载超过阈值持续超过(秒)" 753 | 754 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:686 755 | msgid "If set to 0, it's a single check without considering duration." 756 | msgstr "如果设置为 0,则为单次检测,不考虑持续时间" 757 | 758 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:688 759 | msgid "CPU alarm quiet time (seconds)" 760 | msgstr "CPU 报警免打扰时间(秒)" 761 | 762 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:692 763 | msgid "No repeat notifications within the set time after the initial push notification." 764 | msgstr "首次推送通知后,在设定时间内不再重复提醒" 765 | 766 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:700 767 | msgid "Do Not Disturb for Login Reminders" 768 | msgstr "登录提醒免打扰" 769 | 770 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:703 771 | msgid "Only record in the log" 772 | msgstr "仅记录到日志" 773 | 774 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:704 775 | msgid "Ignore all login notifications (including failed logins), and only record them in the log." 776 | msgstr "忽略所有登录提醒(包括失败的登录),仅记录到日志" 777 | 778 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:706 779 | msgid "Send notification only on the first login" 780 | msgstr "仅在首次登录时推送通知" 781 | 782 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:673 783 | msgid "Send notification only once within the specified time interval." 784 | msgstr "在设定时间间隔内,仅首次发送推送通知" 785 | 786 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:675 787 | msgid "Login reminder do not disturb time (s)" 788 | msgstr "登录提醒免打扰时间(秒)" 789 | 790 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:679 791 | msgid "Send notification after the first login and do not repeat within the specified time
Take a shortcut and read the login time from the log" 792 | msgstr "首次登录后推送通知,在设定时间内不再重复提醒
偷懒一下,登录时间从日志中读取,请确保开启日志功能" 793 | 794 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:682 795 | msgid "Login Alert (Auto-Ban) Whitelist" 796 | msgstr "登录提醒(自动封禁)白名单" 797 | 798 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:689 799 | msgid "Login reminder log anti-flooding" 800 | msgstr "登录提醒日志免刷屏" 801 | 802 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:690 803 | msgid "Users in the whitelist or during the undisturbed time period after their first login IP will be exempt from log recording, preventing log flooding." 804 | msgstr "白名单列表内的用户,或者登录 IP 处于首次登录后的免打扰时段,不做日志记录,避免日志刷屏" 805 | 806 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:688 807 | msgid "Add the IP addresses in the list to the whitelist for the blocking function (if available), and ignore automatic blocking and login event notifications. Only record in the log. Mask notation is currently not supported." 808 | msgstr "列表内 IP 加入封禁功能白名单(如果可用),并忽略自动封禁和登录事件推送,仅在日志中记录,暂不支持掩码位表示" 809 | 810 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:17 811 | msgid "If you are not familiar with the meanings of these options, please do not modify them.

" 812 | msgstr "如果你不了解这些选项的含义,请不要修改这些选项

" 813 | 814 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:19 815 | msgid "Advanced Settings" 816 | msgstr "高级设置" 817 | 818 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:23 819 | msgid "Device online detection timeout (s)" 820 | msgstr "设备上线检测超时(秒)" 821 | 822 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:28 823 | msgid "Device offline detection timeout (s)" 824 | msgstr "设备离线检测超时(秒)" 825 | 826 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:33 827 | msgid "Offline detection count" 828 | msgstr "离线检测次数" 829 | 830 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:37 831 | msgid "If the device has good signal strength and no Wi-Fi sleep issues, you can reduce the above values.
Due to the mysterious nature of Wi-Fi sleep during the night, if you encounter frequent disconnections, please adjust the parameters accordingly.
..╮(╯_╰)╭.." 832 | msgstr "若设备信号强度良好,无息屏 WiFi 休眠问题,可以减少以上数值
因夜间 WiFi 息屏休眠较为玄学,遇到设备频繁推送断开,烦请自行调整参数
..╮(╯_╰)╭.." 833 | 834 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:42 835 | msgid "Offline timeout applies only to the devices that receive push notifications" 836 | msgstr "离线超时只针对推送设备" 837 | 838 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:95 839 | msgid "IP address to always scan" 840 | msgstr "始终扫描的 IP" 841 | 842 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:95 843 | msgid "The IPs in the list are always subjected to online detection regardless of whether they exist in the ARP list, suitable for secondary routing scenarios." 844 | msgstr "列表中的 IP 始终进行在线检测,无论它是否存在于 ARP 列表,适用于二级路由等情况" 845 | 846 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:45 847 | msgid "When this option is selected, the offline timeout and offline detection count apply only to the devices that require push notifications. Other devices will use default values, which can significantly reduce the time required for detection. However, it may result in inaccurate online time displayed in the online devices list. It is recommended to enable this option only when there are many devices and frequent offline occurrences are observed for specific devices of interest." 848 | msgstr "选中此项后,离线超时时间和离线检测次数只针对需要推送的设备,其余设备使用默认值,可有效减少检测所需的时间,但会造成在线设备列表中的在线时间不准确,仅建议设备较多且关注的设备离线频繁时使用" 849 | 850 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:47 851 | msgid "Disable active detection" 852 | msgstr "关闭主动探测" 853 | 854 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:50 855 | msgid "Disable active detection of client online status. Enabling this feature will no longer prompt device online/offline events.
Suitable for users who are not sensitive to online devices but need other features." 856 | msgstr "关闭客户端在线状态的主动探测,因误报较为严重,启用此功能后设备上下线将不再提示
适用于对在线设备不敏感,但需要其他功能的用户" 857 | 858 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:52 859 | msgid "Maximum concurrent processes" 860 | msgstr "最大并发进程数" 861 | 862 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:56 863 | msgid "Do not change the setting value for low-performance devices, or reduce the parameters as appropriate." 864 | msgstr "低性能设备请勿更改设置值,或酌情减少参数" 865 | 866 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:120 867 | msgid "Client list sorting method" 868 | msgstr "客户端列表排序方式" 869 | 870 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:52 871 | msgid "This will change the sorting method for both the online device list page and the sorting order in the push content." 872 | msgstr "这将会同时改变在线设备列表页面和推送内容中的排序方式" 873 | 874 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:58 875 | msgid "Custom temperature reading command" 876 | msgstr "自定义温度读取命令" 877 | 878 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:60 879 | msgid "Default" 880 | msgstr "默认" 881 | 882 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:61 883 | msgid "Proxmox Virtual Environment" 884 | msgstr "PVE 虚拟机" 885 | 886 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:62 887 | msgid "If you need to use special symbols such as quotes, $, !, etc. in custom commands, you need to escape them yourself.
You can use the command eval echo $(uci get wechatpush.wechatpush.soc_code) to view command output and error information.
The execution result should be a pure number (including decimals) for temperature comparison.
Here is an example that does not require escaping:
cat /sys/class/thermal/thermal_zone0/temp|sort -nr|head -n1|cut -c-2" 888 | msgstr "自定义命令如需使用特殊符号,如引号、$、!等,则需要自行转义
可以使用 eval echo $(uci get wechatpush.wechatpush.soc_code) 命令查看命令输出及错误信息
执行结果需为纯数字(可带小数),用于温度对比
一个无需转义的例子:
cat /sys/class/thermal/thermal_zone0/temp|sort -nr|head -n1|cut -c-2" 889 | 890 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:64 891 | msgid "Host machine address" 892 | msgstr "宿主机地址" 893 | 894 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:70 895 | msgid "Host machine SSH port" 896 | msgstr "宿主机 SSH 端口" 897 | 898 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:73 899 | msgid "The default SSH port is 22. If you have a custom port, please fill in the custom SSH port.
Please make sure you have set up key-based login, otherwise it may cause script errors.
Install the sensors command on PVE by searching on the internet.
Example for key-based login (modify the address and port number accordingly):
opkg update # Update package list
opkg install openssh-client openssh-keygen # Install openssh client
echo -e \"\\n\" | ssh-keygen -t rsa # Generate key file (no passphrase)
pve_host=`uci get wechatpush.config.server_host` || pve_host=\"10.0.0.3\" # Read the PVE host address from the configuration file, If not saved, please fill in by yourself.
pve_port=`uci get wechatpush.config.server_port` || pve_host=\"22\" # Read the PVE host SSH port number from the configuration file, If not saved, please fill in by yourself.
ssh -o StrictHostKeyChecking=yes root@${pve_host} -p ${pve_port} \"tee -a ~/.ssh/OpenWrt_id_rsa.pub\" < ~/.ssh/id_rsa.pub # Transfer public key to PVE
ssh root@${pve_host} -p ${pve_port} \"cat ~/.ssh/OpenWrt_id_rsa.pub >> ~/.ssh/authorized_keys\" # Write public key to PVE
ssh -i /root/.ssh/id_rsa root@${pve_host} -p ${pve_port} sensors # To avoid script errors during the initial connection, please use a private key to connect to PVE and test the temperature command for its proper functioning.
For users who frequently flash firmware, please add /root/.ssh/ to the backup list to avoid duplicate operations." 900 | msgstr "SSH 端口默认为 22,如有自定义,请填写自定义 SSH 端口
请确认已经设置好密钥登陆,否则会引起脚本无法运行等错误!
PVE 安装 sensors 命令自行百度
密钥登陆例(自行修改地址与端口号):
opkg update #更新列表
opkg install openssh-client openssh-keygen #安装openssh客户端
echo -e \"\\n\" | ssh-keygen -t rsa # 生成密钥文件(空密码)
pve_host=`uci get wechatpush.config.server_host` || pve_host=\"10.0.0.3\" # 读取配置文件中的 pve 主机地址,如果未保存设置,请自行填写
pve_port=`uci get wechatpush.config.server_port` || pve_port=\"22\" # 读取配置文件中的 pve 主机 ssh 端口号,如果未保存设置,请自行填写
ssh -o StrictHostKeyChecking=yes root@${pve_host} -p ${pve_port} \"tee -a ~/.ssh/OpenWrt_id_rsa.pub\" < ~/.ssh/id_rsa.pub # 传送公钥到 PVE
ssh root@${pve_host} -p ${pve_port} \"cat ~/.ssh/OpenWrt_id_rsa.pub >> ~/.ssh/authorized_keys\" # 写入公钥到 PVE
ssh -i /root/.ssh/id_rsa root@${pve_host} -p ${pve_port} sensors # 因首次连接时需要确认,为避免脚本错误,请使用私钥连接 PVE 并测试温度命令是否正常运行。
刷机党自行将 /root/.ssh/ 加入备份列表,避免重复操作" 901 | 902 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:76 903 | msgid "Test temperature command" 904 | msgstr "测试温度命令" 905 | 906 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:82 907 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/config.js:312 908 | msgid "Returned value is empty" 909 | msgstr "返回值为空" 910 | 911 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:87 912 | msgid "Fetch failed:" 913 | msgstr "获取失败:" 914 | 915 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:91 916 | msgid "Assist in obtaining device information" 917 | msgstr "辅助获取设备列表" 918 | 919 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:164 920 | msgid "Retrieve hostname list from modem" 921 | msgstr "从光猫获取主机名等信息" 922 | 923 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:165 924 | msgid "Retrieve hostname list from modem MikroTik Router" 925 | msgstr "从 ROS 路由器中获取主机名等信息" 926 | 927 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:165 928 | msgid "Get wireless band information and hostname from MiWiFi" 929 | msgstr "从小米路由器中获取无线频段信息和主机名" 930 | 931 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:166 932 | msgid "Get wireless band information and hostname from other OpenWrt" 933 | msgstr "从其他 OpenWrt 中获取无线频段信息和主机名" 934 | 935 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:167 936 | msgid "Scan local IP" 937 | msgstr "扫描局域网 IP" 938 | 939 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:95 940 | msgid "When OpenWrt is used as a bypass gateway and cannot obtain device hostnames or a complete list of local network devices.
the \"Retrieve hostname list from modem\" option has only been tested with HG5143F/HN8145V China Telecom gateways and may not be universally applicable.
The \"Scan local IP\" option may not retrieve hostnames, so please use device name annotations in conjunction with it." 941 | msgstr "适用于 OpenWrt 作为旁路网关,无法获取设备主机名及完整的局域网设备列表时
\"从光猫获取主机名列表\"选项仅测试通过 HG5143F/HN8145V 天翼网关,不保证通用性
\"定期扫描局域网 IP\"选项可能无法获取主机名,请配合设备名备注使用" 942 | 943 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:97 944 | msgid "Optical modem login URL" 945 | msgstr "光猫登录地址 URL" 946 | 947 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:102 948 | msgid "Device list JSON URL" 949 | msgstr "设备列表 JSON URL" 950 | 951 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:105 952 | msgid "Use F12 console to capture
ip, devName, model are mandatory fields. Example JSON file information:
{\"pc1\":{\"devName\":\"RouterOS\",\"model\":\"\",\"type\":\"pc\",\"ip\":\"192.168.1.7\"}}" 953 | msgstr "使用 F12 控制台自行抓取
ip、devName、model 为必须项,JSON 文件信息范例:
{\"pc1\":{\"devName\":\"RouterOS\",\"model\":\"\",\"type\":\"pc\",\"ip\":\"192.168.1.7\"}}" 954 | 955 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:108 956 | msgid "Optical modem logout URL" 957 | msgstr "光猫注销登录 URL" 958 | 959 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:111 960 | msgid "Not a mandatory field, but it may affect other users logging into the web management page, e.g., HG5143F" 961 | msgstr "非必须项,但可能会影响其他用户登录 Web 管理页面,如 HG5143F" 962 | 963 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:114 964 | msgid "Login page account input box ID" 965 | msgstr "登录页面帐号输入框 ID" 966 | 967 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:119 968 | msgid "Login page password input box ID" 969 | msgstr "登录页面密码输入框 ID" 970 | 971 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:122 972 | msgid "Right-click in the browser and select 'Inspect Element'" 973 | msgstr "浏览器右键-检查元素" 974 | 975 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:125 976 | msgid "Optical modem login account" 977 | msgstr "光猫登录帐号" 978 | 979 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:130 980 | msgid "Optical modem login password" 981 | msgstr "光猫登录密码" 982 | 983 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:132 984 | msgid "Use a regular account, no need for super password" 985 | msgstr "使用普通账号即可,不需要超密" 986 | 987 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:209 988 | msgid "MiWiFi IP Address" 989 | msgstr "小米路由器 IP 地址" 990 | 991 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:213 992 | msgid "The main router address is all that is needed in the Mesh wireless network topology." 993 | msgstr "在 Mesh 无线网络拓扑中,只需要填写主路由器地址。" 994 | 995 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:216 996 | msgid "MiWiFi Login Password" 997 | msgstr "小米路由器登录密码" 998 | 999 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:213 1000 | msgid "MikroTik Routers IP Address" 1001 | msgstr "ROS 路由器 IP 地址" 1002 | 1003 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:213 1004 | msgid "MikroTik Router Account" 1005 | msgstr "ROS 路由器用户名" 1006 | 1007 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:216 1008 | msgid "The main router address is all that is needed in the Mesh wireless network topology." 1009 | msgstr "Mesh 无线网络拓扑中,只需要填写主路由地址" 1010 | 1011 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:135 1012 | msgid "IP range to be scanned" 1013 | msgstr "需要扫描的 IP 段" 1014 | 1015 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:140 1016 | msgid "Interval for capturing info" 1017 | msgstr "抓取信息时间间隔" 1018 | 1019 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:144 1020 | msgid "Generally, frequent capturing is not necessary. Adjust it as needed." 1021 | msgstr "一般不需要频繁抓取,酌情设置" 1022 | 1023 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:148 1024 | msgid "Unattended tasks" 1025 | msgstr "无人值守任务" 1026 | 1027 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:151 1028 | msgid "Please make sure the script can run properly, otherwise it may cause frequent restarts and other errors!" 1029 | msgstr "请确认脚本可以正常运行,否则可能造成频繁重启等错误!" 1030 | 1031 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:153 1032 | msgid "Restart zerotier after IP change" 1033 | msgstr "IP 变化后重启 zerotier" 1034 | 1035 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:154 1036 | msgid "An old issue with zerotier
Cannot reconnect after disconnection, emmm, I don't know if it has been fixed now." 1037 | msgstr "zerotier 的陈年老问题
断网后不能重新打洞,emmm,我也不知道修了没有" 1038 | 1039 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:157 1040 | msgid "Redial only during Do-Not-Disturb period" 1041 | msgstr "仅在免打扰时段重拨" 1042 | 1043 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:160 1044 | msgid "Avoid redialing network during the day to prevent waiting for DDNS domain resolution. This feature does not affect disconnection detection.
Due to the issue of certain apps consuming excessive data at night, this feature may be unstable." 1045 | msgstr "避免在白天重拨网络造成 DDNS 域名等待解析,此功能不影响断网检测
因夜间某些 APP 偷跑流量问题,该功能可能不稳定" 1046 | 1047 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:165 1048 | msgid "Will only be executed when none of the devices in the list are online.
After an hour of Do-Not-Disturb period, if the devices in the focus list have low traffic (around 100kb/m) for five minutes, they will be considered offline." 1049 | msgstr "只会在列表中设备都不在线时才会执行
免打扰时段一小时后,关注设备五分钟低流量(约100kb/m)将视为离线" 1050 | 1051 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:169 1052 | msgid "When the network is disconnected" 1053 | msgstr "网络断开时" 1054 | 1055 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:171 1056 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:179 1057 | msgid "No operation" 1058 | msgstr "无操作" 1059 | 1060 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:172 1061 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:180 1062 | msgid "Restart the router" 1063 | msgstr "重启路由器" 1064 | 1065 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:173 1066 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:181 1067 | msgid "Redialing network" 1068 | msgstr "重新拨号" 1069 | 1070 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:174 1071 | msgid "The restart operation will occur ten minutes after the network disconnection and will be attempted a maximum of two times. If the option to log in to the optical modem is available, this operation will attempt to restart the optical modem.
【!!This feature cannot guarantee compatibility!!】" 1072 | msgstr "重启操作将在网络断开十分钟后进行,且最多尝试两次。如果光猫登录选项可用,此操作将会尝试重启光猫。
【!!此功能无法保证兼容性!!】" 1073 | 1074 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:177 1075 | msgid "Scheduled reboot" 1076 | msgstr "定时重启" 1077 | 1078 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:184 1079 | msgid "System uptime greater than" 1080 | msgstr "系统运行时间大于" 1081 | 1082 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:188 1083 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:195 1084 | msgid "Unit: hours" 1085 | msgstr "单位为小时" 1086 | 1087 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/advanced.js:191 1088 | msgid "Network uptime greater than" 1089 | msgstr "网络在线时间大于" 1090 | 1091 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/client.js:70 1092 | msgid "Connection Point" 1093 | msgstr "连接点" 1094 | 1095 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/client.js:70 1096 | msgid "Online time" 1097 | msgstr "在线时间" 1098 | 1099 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/log.js:75 1100 | msgid "Clear Logs..." 1101 | msgstr "清除日志..." 1102 | 1103 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/log.js:75 1104 | msgid "Logs cleared successfully!" 1105 | msgstr "日志清除成功!" 1106 | 1107 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/log.js:81 1108 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/log.js:91 1109 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/log.js:95 1110 | msgid "Clear Logs" 1111 | msgstr "清除日志" 1112 | 1113 | #: applications/luci-app-wechatpush/htdocs/luci-static/resources/view/wechatpush/log.js:124 1114 | msgid "Refresh every 5 seconds." 1115 | msgstr "每 5 秒刷新" 1116 | 1117 | msgid "Create scheduled task" 1118 | msgstr "创建定时任务" 1119 | 1120 | msgid "Router status:" 1121 | msgstr "路由状态:" 1122 | 1123 | msgid "Send test:" 1124 | msgstr "发送测试:" 1125 | 1126 | msgid "Content 1" 1127 | msgstr "内容1" 1128 | 1129 | msgid "Content 2" 1130 | msgstr "内容2" 1131 | 1132 | msgid "Device 1" 1133 | msgstr "设备1" 1134 | 1135 | msgid "Device 2" 1136 | msgstr "设备2" 1137 | 1138 | msgid "Device 3" 1139 | msgstr "设备3" 1140 | 1141 | msgid "Device 4" 1142 | msgstr "设备4" 1143 | 1144 | msgid "Do not disturb time, exit scheduled push" 1145 | msgstr "免打扰时间,退出定时推送" 1146 | 1147 | msgid "Connected!" 1148 | msgstr "已连通!" 1149 | 1150 | msgid "Disconnected!" 1151 | msgstr "已断开!" 1152 | 1153 | msgid "System running status" 1154 | msgstr "系统运行状态" 1155 | 1156 | msgid "Average load:" 1157 | msgstr "平均负载:" 1158 | 1159 | msgid "CPU usage:" 1160 | msgstr "CPU占用:" 1161 | 1162 | msgid "Memory usage:" 1163 | msgstr "内存占用:" 1164 | 1165 | msgid "Global connection:" 1166 | msgstr "全球互联:" 1167 | 1168 | msgid "Device temperature" 1169 | msgstr "设备温度" 1170 | 1171 | msgid "CPU:" 1172 | msgstr "CPU:" 1173 | 1174 | msgid "Unable to get device temperature" 1175 | msgstr "无法获取设备温度" 1176 | 1177 | msgid "WAN Port Information" 1178 | msgstr "WAN 口信息" 1179 | 1180 | msgid "Interface IPv4:" 1181 | msgstr "接口 IPv4:" 1182 | 1183 | msgid "Outbound IPv4:" 1184 | msgstr "出口 IPv4:" 1185 | 1186 | msgid "Interface IPv6:" 1187 | msgstr "接口 IPv6:" 1188 | 1189 | msgid "Outbound IPv6:" 1190 | msgstr "出口 IPv6:" 1191 | 1192 | msgid "I encountered a problem" 1193 | msgstr "我遇到了一个难题" 1194 | 1195 | msgid "Scheduled send option error, you didn't select any items to send, what should I do?" 1196 | msgstr "定时发送选项错误,你没有选择需要发送的项目,该怎么办呢" 1197 | 1198 | msgid "Scheduled push failed, please check network or settings" 1199 | msgstr "定时推送失败,请检查网络或设置信息" 1200 | 1201 | msgid "Scheduled push task completed" 1202 | msgstr "定时推送任务完成" 1203 | 1204 | msgid "Device %s logged into router via %s" 1205 | msgstr "设备 %s 通过 %s 登录了路由器" 1206 | 1207 | msgid "/ (Homepage login)" 1208 | msgstr "/ (首页登录)" 1209 | 1210 | msgid "%s frequent %s login attempts" 1211 | msgstr "%s 频繁尝试 %s 登录" 1212 | 1213 | msgid "Block Information" 1214 | msgstr "封禁信息" 1215 | 1216 | msgid "Device %s (%s) frequently attempted %s %s login" 1217 | msgstr "设备 %s (%s) 频繁尝试 %s %s 登录" 1218 | 1219 | msgid "%s logged into router via %s" 1220 | msgstr "%s 通过 %s 登录了路由器" 1221 | 1222 | msgid "Login Information" 1223 | msgstr "登录信息" 1224 | 1225 | msgid "Device %s (%s) logged into router via %s %s" 1226 | msgstr "设备 %s (%s) 通过 %s %s 登录了路由器" 1227 | 1228 | msgid "Time:" 1229 | msgstr "时间:" 1230 | 1231 | msgid "Device IP:" 1232 | msgstr "设备 IP:" 1233 | 1234 | msgid "Login Method:" 1235 | msgstr "登录方式:" 1236 | 1237 | msgid "Total Traffic:" 1238 | msgstr "总计流量:" 1239 | 1240 | msgid "%s disconnected" 1241 | msgstr "%s 断开连接" 1242 | 1243 | msgid "Device Disconnected" 1244 | msgstr "设备断开连接" 1245 | 1246 | msgid "Device Status Changed" 1247 | msgstr "设备状态变化" 1248 | 1249 | msgid "Client Name:" 1250 | msgstr "客户端名:" 1251 | 1252 | msgid "Client IP:" 1253 | msgstr "客户端IP:" 1254 | 1255 | msgid "Client MAC:" 1256 | msgstr "客户端MAC:" 1257 | 1258 | msgid "Uptime:" 1259 | msgstr "在线时间:" 1260 | 1261 | msgid "Device %s %s disconnected" 1262 | msgstr "设备 %s %s 断开连接" 1263 | 1264 | msgid "JSON format error, not a standard JSON file, please check %s for unescaped special characters or syntax errors" 1265 | msgstr "JSON 文件格式错误,这不是一个标准的 JSON 文件,请检查 %s 文件是否有特殊符号未转义或语法错误" 1266 | 1267 | msgid "type:{ } field format error after variable substitution, please check for unescaped special characters or syntax errors in type:{ } field" 1268 | msgstr "type:{ } 字段转义变量后格式错误,请检查 type:{ } 字段内是否有特殊符号未转义或语法错误" 1269 | 1270 | msgid "Network or URL error, push failed, curl returned %s, please check the following debug information" 1271 | msgstr "网络错误或 URL 错误,推送失败,curl 返回值为 %s,请参考如下调试信息进行排查" 1272 | 1273 | msgid "Push test enabled, current curl return value is %s" 1274 | msgstr "推送测试已开启,当前 curl 返回值为 %s" 1275 | 1276 | msgid "Format error after variable substitution, please check %s for unescaped special characters or syntax errors" 1277 | msgstr "转义变量后格式错误,请检查 %s 字段内是否有特殊符号未转义或语法错误" 1278 | 1279 | msgid "JSON file saved to: %s" 1280 | msgstr "JSON 文件已保存至:%s" 1281 | 1282 | msgid "Push content preview saved to: %s" 1283 | msgstr "推送内容预览文件保存至:%s" 1284 | 1285 | msgid "If no message received, please check %s or use the following command to test manually" 1286 | msgstr "如果收不到信息,请检查 %s 文件,或使用下列命令手动测试返回值" 1287 | 1288 | msgid "Total Traffic:" 1289 | msgstr "总计流量:" 1290 | 1291 | msgid "%s abnormal traffic" 1292 | msgstr "%s 流量异常" 1293 | 1294 | msgid "Device abnormal traffic" 1295 | msgstr "设备流量异常" 1296 | 1297 | msgid "Device status changed" 1298 | msgstr "设备状态变化" 1299 | 1300 | msgid "Traffic in 1 minute:" 1301 | msgstr "一分钟内流量:" 1302 | 1303 | msgid "Whitelist add failed, IP format error" 1304 | msgstr "白名单添加失败,IP 格式错误" 1305 | 1306 | msgid "Currently no online devices" 1307 | msgstr "当前无在线设备" 1308 | 1309 | msgid "Currently %d online devices, details below" 1310 | msgstr "当前有 %d 台在线设备,具体如下" 1311 | 1312 | msgid "IP Address" 1313 | msgstr "IP 地址" 1314 | 1315 | msgid "Uptime" 1316 | msgstr "在线时间" 1317 | 1318 | msgid "Client Name" 1319 | msgstr "客户端名" 1320 | 1321 | msgid "%s connected to your router" 1322 | msgstr "%s 连接了你的路由器" 1323 | 1324 | msgid "New device connected" 1325 | msgstr "新设备连接" 1326 | 1327 | msgid "Device status changed" 1328 | msgstr "设备状态变化" 1329 | 1330 | msgid "Network Interface:" 1331 | msgstr "网络接口:" 1332 | 1333 | msgid "New device %s %s connected" 1334 | msgstr "新设备 %s %s 连接了" 1335 | 1336 | msgid "Login to MIWiFi failed, unable to get stok" 1337 | msgstr "登录 MIWiFi 失败,无法获取 stok" 1338 | 1339 | msgid "Failed to get modem information, maybe current user not logged out or wrong settings" 1340 | msgstr "获取光猫信息失败,可能当前用户未注销或设置错误" 1341 | 1342 | msgid "Disk Name:" 1343 | msgstr "硬盘名称:" 1344 | 1345 | msgid "Disk in standby" 1346 | msgstr "硬盘休眠中" 1347 | 1348 | msgid "Disk Temp:" 1349 | msgstr "硬盘温度:" 1350 | 1351 | msgid "Power On:" 1352 | msgstr "通电时间:" 1353 | 1354 | msgid "Disk Usage:" 1355 | msgstr "空间使用:" 1356 | 1357 | msgid "Health Used:" 1358 | msgstr "寿命使用:" 1359 | 1360 | msgid "Error Logs:" 1361 | msgstr "错误日志:" 1362 | 1363 | msgid "Self-Test Errors:" 1364 | msgstr "自检错误:" 1365 | 1366 | msgid "0E Errors:" 1367 | msgstr "0E 错误:" 1368 | 1369 | msgid "Disk health assessment FAILED!!!" 1370 | msgstr "硬盘整体健康评估不通过!!!" 1371 | 1372 | msgid "Disk has errors, please backup data immediately!!!" 1373 | msgstr "硬盘存在错误,请及时备份数据!!!" 1374 | 1375 | msgid "CPU temperature too high: %s" 1376 | msgstr "CPU 温度过高: %s" 1377 | 1378 | msgid "Device Alert!" 1379 | msgstr "设备报警!" 1380 | 1381 | msgid "CPU Temperature Too High!" 1382 | msgstr "CPU 温度过高!" 1383 | 1384 | msgid "CPU Temperature Alert" 1385 | msgstr "CPU 温度过高" 1386 | 1387 | msgid "CPU temperature has exceeded threshold for %s" 1388 | msgstr "CPU 温度已连续 %s 超过预设" 1389 | 1390 | msgid "No further alerts for %s" 1391 | msgstr "接下来 %s 不再提示" 1392 | 1393 | msgid "Current temperature: %s℃" 1394 | msgstr "当前温度:%s℃" 1395 | 1396 | msgid "CPU load too high: %s" 1397 | msgstr "CPU 负载过高: %s" 1398 | 1399 | msgid "CPU Load Too High!" 1400 | msgstr "CPU 负载过高!" 1401 | 1402 | msgid "CPU Load Alert" 1403 | msgstr "CPU 负载过高" 1404 | 1405 | msgid "CPU load has exceeded threshold for %s" 1406 | msgstr "CPU 负载已连续 %s 超过预设" 1407 | 1408 | msgid "Current load: %s" 1409 | msgstr "当前负载:%s" 1410 | 1411 | msgid "Top 3 CPU Processes" 1412 | msgstr "当前 CPU 占用前三的进程" 1413 | 1414 | msgid "Top 3 CPU processes: %s" 1415 | msgstr "CPU 占用前三: %s" 1416 | 1417 | msgid "Network connection restored" 1418 | msgstr "网络恢复正常" 1419 | 1420 | msgid "Network connection failed! Stopping detection!" 1421 | msgstr "当前网络不通!停止检测!" 1422 | 1423 | msgid "Attempting router reboot (attempt %s/3)" 1424 | msgstr "正在尝试重启路由,当前第 %s 次" 1425 | 1426 | msgid "Attempting network restart (attempt %s/3)" 1427 | msgstr "正在尝试重启网络,当前第 %s 次" 1428 | 1429 | msgid "Failed after 2 router reboots, please fix manually" 1430 | msgstr "已经重启路由2次,修复失败,请主人自行修复哦" 1431 | 1432 | msgid "Failed after 2 network restarts, please fix manually" 1433 | msgstr "已经重启网络2次,修复失败,请主人自行修复哦" 1434 | 1435 | msgid "Network Interface" 1436 | msgstr "网络接口" 1437 | 1438 | msgid "Location:" 1439 | msgstr "地址:" 1440 | 1441 | msgid "Interface:" 1442 | msgstr "接口:" 1443 | 1444 | msgid "Router has rebooted!" 1445 | msgstr "路由器已经重启!" 1446 | 1447 | msgid "Router Rebooted" 1448 | msgstr "路由器重新启动" 1449 | 1450 | msgid "Current IP: %s from: %s" 1451 | msgstr "当前 IP:%s 来自:%s" 1452 | 1453 | msgid "IP Address Changed" 1454 | msgstr "IP地址变化" 1455 | 1456 | msgid "Current IP:" 1457 | msgstr "当前 IP:" 1458 | 1459 | msgid "Current IPv6: %s from: %s" 1460 | msgstr "当前 IPv6:%s 来自:%s" 1461 | 1462 | msgid "IPv6 Address Changed" 1463 | msgstr "IPv6地址变化" 1464 | 1465 | msgid "Current IPv6:" 1466 | msgstr "当前 IPv6:" 1467 | 1468 | msgid "It's late at night, time to rest" 1469 | msgstr "夜深了,该休息了" 1470 | 1471 | msgid "Failed to get IP, current API: %s & %s" 1472 | msgstr "IP 获取失败,当前使用的 API 为 %s & %s" 1473 | 1474 | msgid "Failed to get IPv6, current API: %s & %s" 1475 | msgstr "IPv6 获取失败,当前使用的 API 为 %s & %s" 1476 | 1477 | msgid "Log exceeded limit, keeping last 300 entries" 1478 | msgstr "日志超出上限,保留最后 300 条" 1479 | 1480 | msgid "%ds" 1481 | msgstr "%d秒" 1482 | 1483 | msgid "%dm %ds" 1484 | msgstr "%d分%d秒" 1485 | 1486 | msgid "%dh %dm" 1487 | msgstr "%d小时%d分" 1488 | 1489 | msgid "%dd %dh" 1490 | msgstr "%d天%d小时" 1491 | 1492 | msgid "Uptime: %dd %dh %dm %ds" 1493 | msgstr "运行时间: %d天%d时%d分%d秒" 1494 | 1495 | msgid "Failed to retrieve remote host temperature. To prevent SSH connection timeout from affecting program functionality, the temperature retrieval feature has been disabled. Please verify your configuration and restart the script, or manually delete /tmp/wechatpush/temp_err to retry." 1496 | msgstr "远程主机温度获取失败,为避免 SSH 连接超时影响程序功能,已禁用温度获取功能,请确认配置正确后重启脚本或手动删除 `/tmp/wechatpush/temp_err` 重试" 1497 | 1498 | msgid "Failed to read settings, please check configuration." 1499 | msgstr "读取设置出错,请检查设置项" 1500 | 1501 | msgid "Loading online devices..." 1502 | msgstr "载入在线设备..." 1503 | 1504 | msgid "Initialization completed" 1505 | msgstr "初始化完成" 1506 | 1507 | msgid "Start running..." 1508 | msgstr "开始运行..." 1509 | 1510 | msgid "Loaded logs from previous restart" 1511 | msgstr "载入上次重启前日志" 1512 | 1513 | msgid "wrtbwmon not installed, traffic statistics unavailable" 1514 | msgstr "未安装 wrtbwmon,流量统计不可用" 1515 | 1516 | msgid "Cannot get iputils-arping version, please confirm if plugin is running properly" 1517 | msgstr "无法获取依赖项 iputils-arping 版本号,请确认插件是否正常运行" 1518 | 1519 | msgid "Cannot get curl version, please confirm if plugin is running properly" 1520 | msgstr "无法获取依赖项 curl 版本号,请确认插件是否正常运行" 1521 | 1522 | msgid "Please fill in the correct API key" 1523 | msgstr "请填写正确的 key" 1524 | 1525 | msgid "Multiple interfaces detected or configuration error, may not get interface uptime information, please confirm if plugin is running properly" 1526 | msgstr "存在多个接口或配置错误,可能无法获取接口在线时间等信息,请确认插件是否正常运行" 1527 | 1528 | msgid "Cannot read device temperature, please check command" 1529 | msgstr "无法读取设备温度,请检查命令" 1530 | 1531 | msgid "Cannot read device load, please check command" 1532 | msgstr "无法读取设备负载,请检查命令" 1533 | 1534 | msgid "Device list file format error, needs reinitialization. Original file saved to %s.err" 1535 | msgstr "设备列表文件格式错误,需重新初始化,原文件已保存至 %s.err" 1536 | 1537 | msgid "Starting background update of MAC information file" 1538 | msgstr "开始后台更新 MAC 信息文件" 1539 | 1540 | msgid "Failed to download MAC information file, return code: %s" 1541 | msgstr "设备 MAC 信息文件下载失败,返回码为 %s" 1542 | 1543 | msgid "MAC information file downloaded successfully, processing..." 1544 | msgstr "设备 MAC 信息文件下载成功,处理中" 1545 | 1546 | msgid "MAC information file processing completed" 1547 | msgstr "设备 MAC 信息文件处理完成" 1548 | 1549 | msgid "MAC information file does not need updating" 1550 | msgstr "MAC 信息文件无需更新" 1551 | 1552 | msgid "Location query timeout, current API: %s" 1553 | msgstr "归属地获取超时,当前使用的 API 为 %s" 1554 | 1555 | msgid "Currently %d online devices, details below" 1556 | msgstr "现有在线设备 %d 台,具体如下" 1557 | 1558 | msgid "Rebooting router..." 1559 | msgstr "重启路由器咯" 1560 | 1561 | msgid "Re-establishing PPPoE connection..." 1562 | msgstr "重新拨号咯" 1563 | 1564 | msgid "Failed to add to blacklist, invalid IP format: %s (removed from list)" 1565 | msgstr "黑名单添加失败,IP %s 格式错误,已从列表中移除" 1566 | 1567 | msgid "Currently %s devices online" 1568 | msgstr "当前共 %s 台设备在线" -------------------------------------------------------------------------------- /root/etc/config/wechatpush: -------------------------------------------------------------------------------- 1 | 2 | config wechatpush "config" 3 | option enable '0' 4 | option sleeptime '60' 5 | option debuglevel '1' 6 | option up_timeout '2' 7 | option down_timeout '10' 8 | option timeout_retry_count '2' 9 | option thread_num '3' 10 | -------------------------------------------------------------------------------- /root/etc/init.d/wechatpush: -------------------------------------------------------------------------------- 1 | #!/bin/sh /etc/rc.common 2 | 3 | START=99 4 | STOP=90 5 | USE_PROCD=1 6 | 7 | dir="/tmp/wechatpush/" 8 | 9 | start_service() { 10 | procd_open_instance 11 | enable_value=$(uci get wechatpush.config.enable 2>/dev/null || echo "0") 12 | [ "$enable_value" -ne "0" ] && procd_set_param command /usr/share/wechatpush/wechatpush && echo "wechatpush is starting now ..." 13 | procd_close_instance 14 | } 15 | 16 | reload_service() { 17 | stop 18 | sleep 1 19 | start 20 | } 21 | 22 | stop_service() { 23 | [ -f ${dir}child_pid ] && parent_pid=$(cat ${dir}child_pid) 24 | [ -n "$parent_pid" ] && { 25 | child_pids=$(pgrep -P $parent_pid) 26 | echo "Terminating child processes of wechatpush..." 27 | for child_pid in $child_pids; do 28 | kill $child_pid 29 | done 30 | } 31 | local pids=$(ps | grep "wechatpush" | grep -v grep | grep -v $$ | awk '{print $1}') 32 | [ -n "$pids" ] && echo "$pids" | xargs kill 2>/dev/null 33 | echo "Terminating wechatpush process..." 34 | } 35 | 36 | service_triggers() { 37 | procd_add_reload_trigger wechatpush 38 | } 39 | -------------------------------------------------------------------------------- /root/etc/uci-defaults/luci-wechatpush: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -rf /tmp/luci-* >/dev/null 2>&1 4 | -------------------------------------------------------------------------------- /root/usr/libexec/wechatpush-call: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | logfile="/tmp/wechatpush/wechatpush.log" 4 | dir="/tmp/wechatpush" && mkdir -p "${dir}" 5 | oui_base="${dir}/oui_base.txt" 6 | oui_data=$(uci get wechatpush.config.oui_data 2>/dev/null) 7 | oui_url="https://standards-oui.ieee.org/oui/oui.txt" 8 | lang=$(uci get luci.main.lang 2>/dev/null) 9 | if [ -z "$lang" ] || [[ "$lang" == "auto" ]]; then 10 | lang=$(echo "${LANG:-${LANGUAGE:-${LC_ALL:-${LC_MESSAGES:-zh_cn}}}}" | awk -F'[ .@]' '{print tolower($1)}' | sed 's/-/_/' 2>/dev/null) 11 | fi 12 | 13 | translate() { 14 | # 处理特殊字符 15 | local lua_script=$(cat </dev/null || echo "0") 28 | local datetime=$(date -r "${file_dir}" +%s 2>/dev/null || echo "0") 29 | expr $(date +%s) - ${datetime} 30 | } 31 | 32 | # 下载 33 | download_file() { 34 | url=$1 35 | output_file=$2 36 | retries=2 37 | retval=1 38 | 39 | # 尝试使用 curl 下载 40 | i=0 41 | while [ $i -lt $retries ]; do 42 | curl -fsSL --connect-timeout 15 --max-time 30 -o "${output_file}" "${url}" >/dev/null 2>&1 43 | retval=$? 44 | if [ $retval -eq 0 ]; then 45 | return 0 46 | fi 47 | i=$((i + 1)) 48 | sleep 1 # 等待1秒后重试 49 | done 50 | 51 | # 如果 curl 失败,尝试使用 wget 下载 52 | i=0 53 | while [ $i -lt $retries ]; do 54 | wget --no-check-certificate -T 15 -O "${output_file}" "${url}" >/dev/null 2>&1 55 | retval=$? 56 | if [ $retval -eq 0 ]; then 57 | return 0 58 | fi 59 | i=$((i + 1)) 60 | sleep 1 # 等待1秒后重试 61 | done 62 | 63 | return $retval 64 | } 65 | 66 | # 更新 MAC 信息文件 67 | down_oui() { 68 | if [ -n "${oui_data}" ] && [ "${oui_data}" -ne "3" ]; then 69 | echo "$(date "+%Y-%m-%d %H:%M:%S") [INFO] $(translate "Starting background update of MAC information file")" >>"${logfile}" 70 | download_file "${oui_url}" "${dir}/oui.txt" 71 | local RETVAL=$? 72 | [ ${RETVAL} -ne 0 ] && echo "$(date "+%Y-%m-%d %H:%M:%S") [ERROR] $(translate "Failed to download MAC information file, return code: ${RETVAL}")" >>"${logfile}" && return 1 73 | echo "$(date "+%Y-%m-%d %H:%M:%S") [INFO] $(translate "MAC information file downloaded successfully, processing...")" >>"${logfile}" 74 | if [ "${oui_data}" -eq "1" ]; then 75 | grep -i -E ".*(base 16).*(apple|aruba|asus|autelan|belkin|bhu|buffalo|cctf|cisco|comba|datang|dell|dlink|dowell|ericsson|fast|feixun|fiberhome|fujitsu|grentech|h3c|hisense|hiwifi|honghai|honghao|hp|htc|huawei|intel|jinli|jse|lenovo|lg|liteon|malata|meizu|mercury|meru|moto|netcore|netgear|nokia|omron|oneplus|oppo|philips|router_unkown|samsung|shanzhai|sony|start_net|sunyuanda|tcl|tenda|texas|tianyu|tp-link|ubq|undefine|VMware|utstarcom|volans|xerox|xiaomi|zdc|zhongxing|smartisan).*" "${dir}/oui.txt" | sed -E 's/( Electronic| Technology| Intelligence| TECHNOLOGIES| Device| Systems| TELECOMMUNICATIONS| Instruments| Electronics| Corporation| Telecommunication| Communications| Electrical| Technology| Corporate| Intelligent| Interactive| MOBILE| Solutions| Mobility| Meraki| ELECTRO| VISUAL| Limited| International| Information| LLC|Co$|Co\.|Ltd\.$|Inc\.|B\.V\.$|AB$|,).*$/ /I; s/[[:space:]]*$//; s/ +$//' >"${oui_base}" 76 | elif [ "${oui_data}" -eq "2" ]; then 77 | grep -i "(base 16)" "${dir}/oui.txt" | sed -E 's/( Electronic| Technology| Intelligence| TECHNOLOGIES| Device| Systems| TELECOMMUNICATIONS| Instruments| Electronics| Corporation| Telecommunication| Communications| Electrical| Technology| Corporate| Intelligent| Interactive| MOBILE| Solutions| Mobility| Meraki| ELECTRO| VISUAL| Limited| International| Information| LLC|Co$|Co\.|Ltd\.$|Inc\.|B\.V\.$|AB$|,).*$/ /I; s/[[:space:]]*$//; s/ +$//' >"${oui_base}" 78 | fi 79 | rm -f "${dir}/oui.txt" >/dev/null 2>&1 80 | echo "$(date "+%Y-%m-%d %H:%M:%S") [INFO] $(translate "MAC information file processing completed")" >>"${logfile}" 81 | fi 82 | } 83 | 84 | if [ "$1" == "clear_log" ]; then 85 | # 清空日志 86 | >"${logfile}" 87 | elif [ "$1" == "down_oui" ]; then 88 | # 更新 MAC 信息列表 89 | [ $(file_date "$oui_base") -lt 604800 ] && echo "$(date "+%Y-%m-%d %H:%M:%S") [INFO] $(translate "MAC information file does not need updating")" >>"${logfile}" && exit 2 90 | down_oui >/dev/null 2>&1 & 91 | elif [ "$1" == "child" ]; then 92 | shift 93 | command_name=$1 94 | shift 95 | "$command_name" "$@" 96 | fi 97 | -------------------------------------------------------------------------------- /root/usr/share/luci/menu.d/luci-app-wechatpush.json: -------------------------------------------------------------------------------- 1 | { 2 | "admin/services/wechatpush": { 3 | "title": "WeChat push", 4 | "order": 30, 5 | "action": { 6 | "type": "view", 7 | "path": "wechatpush/status" 8 | }, 9 | "depends": { 10 | "acl": [ "luci-app-wechatpush" ], 11 | "uci": { "wechatpush": true } 12 | } 13 | }, 14 | 15 | "admin/services/wechatpush/config": { 16 | "title": "Basic Settings", 17 | "order": 10, 18 | "action": { 19 | "type": "view", 20 | "path": "wechatpush/config" 21 | } 22 | }, 23 | 24 | "admin/services/wechatpush/advanced": { 25 | "title": "Advance Setting", 26 | "order": 20, 27 | "action": { 28 | "type": "view", 29 | "path": "wechatpush/advanced" 30 | } 31 | }, 32 | 33 | "admin/services/wechatpush/client": { 34 | "title": "Online Devices", 35 | "order": 30, 36 | "action": { 37 | "type": "view", 38 | "path": "wechatpush/client" 39 | } 40 | }, 41 | "admin/services/wechatpush/log": { 42 | "title": "Log", 43 | "order": 40, 44 | "action": { 45 | "type": "view", 46 | "path": "wechatpush/log" 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /root/usr/share/rpcd/acl.d/luci-app-wechatpush.json: -------------------------------------------------------------------------------- 1 | { 2 | "luci-app-wechatpush": { 3 | "description": "Grant UCI access for luci-app-wechatpush", 4 | "read": { 5 | "file": { 6 | "/etc/init.d/wechatpush": [ "exec" ], 7 | "/proc/net/arp": [ "read" ], 8 | "/usr/share/wechatpush/wechatpush": [ "exec" ], 9 | "/tmp/wechatpush/*": [ "read" ], 10 | "/usr/share/wechatpush/api/*": [ "read" ], 11 | "/usr/libexec/wechatpush-call": [ "exec" ] 12 | }, 13 | "ubus": { 14 | "service": [ "list" ] 15 | }, 16 | "uci": [ "wechatpush" ] 17 | }, 18 | "write": { 19 | "file": { 20 | "/usr/share/wechatpush/api/*": [ "write" ], 21 | "/tmp/wechatpush/*": [ "write" ] 22 | }, 23 | "uci": [ "wechatpush" ] 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /root/usr/share/wechatpush/api/device_aliases.list: -------------------------------------------------------------------------------- 1 | # Examples : 2 | #XX:XX:XX:XX:XX:XX My Phone 3 | #192.168.1.2 My PC 4 | -------------------------------------------------------------------------------- /root/usr/share/wechatpush/api/diy.json: -------------------------------------------------------------------------------- 1 | { 2 | "_//": "-------------------------------------------------------------------------------", 3 | "_readme": "这是 自定义 api 文件,这里以 telegram 为例", 4 | "_readme": "特殊符号请使用斜杠转义,变量使用 ${var} 表示", 5 | "_//": "-------------------------------------------------------------------------------", 6 | "_api": "【DIY 推送】", 7 | "_url": "api 地址", 8 | "_data": "生成的 json 文件路径,一般不需要改,如 api 不支持 json,请参考 serverchan 推送接口", 9 | "_content_type": "post 内容类型,这里为 json", 10 | "_//": "-------------------------------------------------------------------------------", 11 | "_str_title_start": "标题粗体字开始符号", 12 | "_str_title_end": "标题粗体字结束符号", 13 | "_str_linefeed": "换行符号", 14 | "_str_splitline": "换行+分隔符", 15 | "_str_space": "空格", 16 | "_str_tab": "TAB(用在行首,生成文字区块)", 17 | "_//": "-------------------------------------------------------------------------------", 18 | "_type": 19 | { 20 | "_readme": "下文中,text 为 telegram 推送需要的键值名称,参见 telegram 官方文档,后面的内容为生成标题所需要的字符串和变量,${1} 为标题内容变量,${nowtime} 为推送时间,${2} 为推送内容变量", 21 | "_readme": "下文中,chat_id 为 telegram 推送需要的键值名称,参见 telegram 官方文档,${chat_id} 为从脚本配置中读取名为 chat_id 的变量,其实就是你填写的机器人的 chat_id ", 22 | "_readme": "type 对象因为需要转义变量,前后必须使用 斜杠+双引号 转义", 23 | "_readme": "参照上文说明,填写下文相关参数" 24 | }, 25 | "_//": "-------------------------------------------------------------------------------", 26 | 27 | "url": "https://api.telegram.org/bot${tg_token}/sendMessage", 28 | "data": "@${tempjsonpath}", 29 | "content_type": "Content-Type: application/json", 30 | "str_title_start": "", 31 | "str_title_end": "", 32 | "str_linefeed": "\\n", 33 | "str_splitline": "\\n----\\n", 34 | "str_space": " ", 35 | "str_tab": " ", 36 | "type": 37 | { 38 | "text":"\"${str_title_start}${1}${str_title_end}${str_splitline}${nowtime}${2}\"", 39 | "chat_id":"\"${chat_id}\"", 40 | "parse_mode":"\"HTML\"" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /root/usr/share/wechatpush/api/ip_attribution.list: -------------------------------------------------------------------------------- 1 | https://ip.rss.ink/v1/qqwry?ip=${ip} | jq -r '.data.area' 2 | ip.plus/${ip} | sed -n 's/.*来自: //p' 3 | http://ip-api.com/json/${ip}?lang=zh-CN | jq -r '"\(.country) \(.regionName) \(.city)"' -------------------------------------------------------------------------------- /root/usr/share/wechatpush/api/ip_blacklist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tty228/luci-app-wechatpush/aeb2759192cce103cff30227d478b1728d2f6dc9/root/usr/share/wechatpush/api/ip_blacklist -------------------------------------------------------------------------------- /root/usr/share/wechatpush/api/ipv4.list: -------------------------------------------------------------------------------- 1 | ddns.oray.com/checkip 2 | www.net.cn/static/customercare/yourip.asp 3 | ip.3322.net 4 | ip.threep.top 5 | ip.atomo.cn 6 | ip.ddnspod.com 7 | 4.ipw.cn 8 | ipv4.ip.mir6.com -------------------------------------------------------------------------------- /root/usr/share/wechatpush/api/ipv6.list: -------------------------------------------------------------------------------- 1 | speed.neu6.edu.cn/getIP.php 2 | 6.ipw.cn 3 | ip.atomo.cn 4 | ip.ddnspod.com 5 | v6.ip.zxinc.org/getip 6 | ipv6.ip.mir6.com -------------------------------------------------------------------------------- /root/usr/share/wechatpush/api/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tty228/luci-app-wechatpush/aeb2759192cce103cff30227d478b1728d2f6dc9/root/usr/share/wechatpush/api/logo.jpg -------------------------------------------------------------------------------- /root/usr/share/wechatpush/api/msmtp.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "msmtp ${recipient_email}", 3 | "data": "${tempjsonpath}", 4 | "content_type": "", 5 | "command": "'\"To: \\(.to)\\nSubject: \\(.subject)\\nContent-Type: text/html\\n\\n\\(.body)\"'", 6 | "str_title_start": "

", 7 | "str_title_end": "

", 8 | "str_linefeed": "
", 9 | "str_splitline": "
----
", 10 | "str_space": " ", 11 | "str_tab": " ", 12 | "type": 13 | { 14 | "to":"\"${recipient_email}\"", 15 | "subject":"\"${1}\"", 16 | "body":"\"${nowtime}${2}\"" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /root/usr/share/wechatpush/api/pushplus.json: -------------------------------------------------------------------------------- 1 | { 2 | "_api": "这是 pushplus api 文件", 3 | "_api": "【pushplus】", 4 | 5 | "url": "http://www.pushplus.plus/send", 6 | "data": "@${tempjsonpath}", 7 | "content_type": "Content-Type: application/json", 8 | "str_title_start": "##### ", 9 | "str_title_end": "", 10 | "str_linefeed": "\\n", 11 | "str_splitline": "\\n----\\n", 12 | "str_space": " ", 13 | "str_tab": " ", 14 | "type": 15 | { 16 | "title": "\"${1}\"", 17 | "content": "\"${2}\"", 18 | "token": "\"${pushplus_token}\"", 19 | "template":"\"markdown\"" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /root/usr/share/wechatpush/api/qywx_markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "_api": "这是企业微信 markdown 模板信息 api 文件", 3 | "_api": "【企业微信】", 4 | 5 | "url": "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=$(curl -s \"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${corpid}&corpsecret=${corpsecret}\"|jq '.access_token' | sed 's/\"//g')", 6 | "data": "@${tempjsonpath}", 7 | "content_type": "Content-Type: application/json", 8 | "str_title_start": "#### ", 9 | "str_title_end": "", 10 | "str_linefeed": "\\n", 11 | "str_splitline": "\\n\\n", 12 | "str_space": " ", 13 | "str_tab": "> ", 14 | "type": 15 | { 16 | "touser": "\"${userid}\"", 17 | "msgtype": "\"markdown\"", 18 | "agentid": "\"${agentid}\"", 19 | "markdown": { 20 | "content": "\"${1}${str_linefeed}${nowtime}${2}\"" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /root/usr/share/wechatpush/api/qywx_mpnews.json: -------------------------------------------------------------------------------- 1 | { 2 | "_api": "这是企业微信图文信息 api 文件", 3 | "_api": "【企业微信】", 4 | 5 | "url": "\"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=$(curl -s \"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${corpid}&corpsecret=${corpsecret}\"|jq '.access_token'|sed 's/\"//g')\"", 6 | "data": "@${tempjsonpath}", 7 | "content_type": "Content-Type: application/json", 8 | "str_title_start": "", 9 | "str_title_end": "", 10 | "str_linefeed": "
", 11 | "str_splitline": "
", 12 | "str_space": " ", 13 | "str_tab": "", 14 | "type": 15 | { 16 | "touser": "\"${userid}\"", 17 | "msgtype": "\"mpnews\"", 18 | "agentid": "\"${agentid}\"", 19 | "mpnews":{ 20 | "articles":[ 21 | { 22 | "title": "\"${1} ${nowtime}\"", 23 | "thumb_media_id": "\"`curl \"https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token=$(curl -s \"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${corpid}&corpsecret=${corpsecret}\"|jq '.access_token'|sed 's/\"//g')&type=image\" -F \"file=@${mediapath}\"|jq '.media_id'|sed 's/\"//g'`\"", 24 | "author": "\"\"", 25 | "content_source_url": "\"\"", 26 | "content": "\"${2}\"", 27 | "digest": "\"\"" 28 | } 29 | ] 30 | }, 31 | "safe":0 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /root/usr/share/wechatpush/api/serverchan.json: -------------------------------------------------------------------------------- 1 | { 2 | "_api": "这是 serverchan api 文件", 3 | "_api": "【serverchan】", 4 | 5 | "url": "\"https://sctapi.ftqq.com/${sckey}.send\"", 6 | "data": "\"text=${1}&desp=${nowtime}${str_linefeed}${2}\"", 7 | "content_type": "Content-Type:application/x-www-form-urlencoded", 8 | "str_title_start": "#### ", 9 | "str_title_end": "", 10 | "str_linefeed": "%0D%0A%0D%0A", 11 | "str_splitline": "%0D%0A%0D%0A----%0D%0A%0D%0A", 12 | "str_space": " ", 13 | "str_tab": " ", 14 | "type": 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /root/usr/share/wechatpush/api/serverchan3.json: -------------------------------------------------------------------------------- 1 | { 2 | "_api": "这是 serverchan3 api 文件", 3 | "_api": "【serverchan3】", 4 | 5 | "url": "\"https://${sc3uid}.push.ft07.com/send/${sc3key}.send\"", 6 | "data": "@${tempjsonpath}", 7 | "content_type": "Content-Type: application/json", 8 | "str_title_start": "##### ", 9 | "str_title_end": "", 10 | "str_linefeed": " \\n", 11 | "str_splitline": "\\n----\\n", 12 | "str_space": " ", 13 | "str_tab": " ", 14 | "type": 15 | { 16 | "title": "\"${1}\"", 17 | "desp": "\"${nowtime}${str_linefeed}${2}\"", 18 | "tags": "\"${sc3tags}\"" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /root/usr/share/wechatpush/api/telegram.json: -------------------------------------------------------------------------------- 1 | { 2 | "_api": "这是 telegram api 文件", 3 | "_api": "【telegram】", 4 | 5 | "url": "https://api.telegram.org/bot${tg_token}/sendMessage", 6 | "data": "@${tempjsonpath}", 7 | "content_type": "Content-Type: application/json", 8 | "str_title_start": "", 9 | "str_title_end": "", 10 | "str_linefeed": "\\n", 11 | "str_splitline": "\\n----\\n", 12 | "str_space": " ", 13 | "str_tab": "\\t", 14 | "type": 15 | { 16 | "text":"\"${str_title_start}${1}${str_title_end}${str_splitline}${nowtime}${2}\"", 17 | "chat_id":"\"${chat_id}\"", 18 | "parse_mode":"\"HTML\"" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /root/usr/share/wechatpush/api/wxpusher.json: -------------------------------------------------------------------------------- 1 | { 2 | "_api": "这是 wxpusher api 文件", 3 | "_api": "【wxpusher】", 4 | 5 | "url": "http://wxpusher.zjiecode.com/api/send/message", 6 | "data": "@${tempjsonpath}", 7 | "content_type": "Content-Type: application/json", 8 | "str_title_start": "#### ", 9 | "str_title_end": "", 10 | "str_linefeed": "\\n", 11 | "str_splitline": "\\n----\\n", 12 | "str_space": " ", 13 | "str_tab": " ", 14 | "type": 15 | { 16 | "summary":"\"${1}\"", 17 | "content":"\"${2}\"", 18 | "appToken":"\"${wxpusher_apptoken}\"", 19 | "topicIds":"[\"${wxpusher_topicIds}\"]", 20 | "uids":"[\"${wxpusher_uids}\"]", 21 | "contentType":3 22 | } 23 | } 24 | --------------------------------------------------------------------------------