├── .github └── workflows │ └── sync.yml ├── CloudflareSpeedTest.csv ├── LICENSE ├── README-FA.md ├── README.md ├── _worker.js ├── addressesapi.txt ├── addressescsv.csv ├── addressesipv6api.txt ├── socks5Data └── sub.png /.github/workflows/sync.yml: -------------------------------------------------------------------------------- 1 | name: Upstream Sync 2 | 3 | permissions: 4 | contents: write 5 | 6 | on: 7 | schedule: 8 | - cron: "0 0 * * *" # every day 9 | workflow_dispatch: 10 | 11 | jobs: 12 | sync_latest_from_upstream: 13 | name: Sync latest commits from upstream repo 14 | runs-on: ubuntu-latest 15 | if: ${{ github.event.repository.fork }} 16 | 17 | steps: 18 | # Step 1: run a standard checkout action 19 | - name: Checkout target repo 20 | uses: actions/checkout@v3 21 | 22 | # Step 2: run the sync action 23 | - name: Sync upstream changes 24 | id: sync 25 | uses: aormsby/Fork-Sync-With-Upstream-action@v3.4 26 | with: 27 | upstream_sync_repo: cmliu/WorkerVless2sub 28 | upstream_sync_branch: main 29 | target_sync_branch: main 30 | target_repo_token: ${{ secrets.GITHUB_TOKEN }} # automatically generated, no need to set 31 | 32 | # Set test_mode true to run tests instead of the true action!! 33 | test_mode: false 34 | 35 | - name: Sync check 36 | if: failure() 37 | run: | 38 | echo "[Error] 由于上游仓库的 workflow 文件变更,导致 GitHub 自动暂停了本次自动更新,你需要手动 Sync Fork 一次,详细教程请查看项目README.md " 39 | echo "[Error] Due to a change in the workflow file of the upstream repository, GitHub has automatically suspended the scheduled automatic update. You need to manually sync your fork. Please refer to the project README.md for instructions. " 40 | exit 1 41 | -------------------------------------------------------------------------------- /CloudflareSpeedTest.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmliu/WorkerVless2sub/ba08748d123d89d1ac8866d5f3c5008fad24da66/CloudflareSpeedTest.csv -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README-FA.md: -------------------------------------------------------------------------------- 1 | # تولید کننده اشتراک Cloudflare Workers همراه با VLESS و دامنه اختصاصی 2 | 3 | سلام بچه‌ها! خوبین؟ امیدوارم حالتون خوب باشه. می‌خوام یه چیز باحال بهتون معرفی کنم. یه ابزار خفن ساختم که با Cloudflare Workers کار می‌کنه و خودش اشتراک‌های VLESS و Trojan رو با بهترین خط‌ها درست می‌کنه. اگه می‌خواین بدونین چطوری کار می‌کنه، یه ویدیو گذاشتم، می‌تونین [اینجا](https://www.youtube.com/watch?v=p-KhFJAC4WQ&t=70s) ببینینش. 4 | 5 | راستی، اگه دوست دارین با بقیه در موردش حرف بزنین، بیاین تو گروه تلگراممون: [@CMLiussss](https://t.me/CMLiussss). یه تشکر ویژه هم از [Alice Networks](https://alice.ws/aff.php?aff=15) دارم که سرور ابری رو برای [سرویس تبدیل اشتراک CM](https://sub.fxxk.dedyn.io/) فراهم کرده. دمشون گرم! 6 | 7 | # چجوری روی Pages راه‌اندازیش کنیم؟ 8 | 9 | خب، اول یه [آموزش ویدیویی](https://www.youtube.com/watch?v=p-KhFJAC4WQ&t=509s) براتون گذاشتم. ولی اگه حوصله ویدیو دیدن ندارین، اینجا قدم به قدم براتون توضیح می‌دم: 10 | 11 | ### 1. نصبش کنیم روی Cloudflare Pages: 12 | - اول برین تو گیت‌هاب و این پروژه رو فورک کنین. یادتون نره بهش یه ستاره هم بدین، خوشحالم می‌کنین! 13 | - بعدش برین تو داشبورد Cloudflare Pages و روی "اتصال به Git" کلیک کنین. پروژه `WorkerVless2sub` رو پیدا کنین و "شروع تنظیمات" رو بزنین. 14 | 15 | ### 2. یه دامنه اختصاصی بهش بدیم: 16 | - تو همون داشبورد Pages، برین سراغ "دامنه‌های سفارشی" و "تنظیم دامنه سفارشی" رو بزنین. 17 | - یه ساب‌دامین بهش بدین. مثلاً اگه دامینتون `fuck.cloudns.biz` هست، بنویسین `sub.fuck.cloudns.biz`. 18 | - حالا برین تو تنظیمات DNS دامینتون و یه رکورد CNAME برای ساب‌دامین `sub` به `WorkerVless2sub.pages.dev` اضافه کنین. بعدش برگردین و "فعال‌سازی دامنه" رو بزنین. 19 | 20 | ### 3. حالا وقتشه تنظیمات اصلی رو انجام بدیم: 21 | 22 | فرض کنیم آدرس پروژه Pages شما `sub.fuck.cloudns.biz` شده: 23 | - یه متغیر `TOKEN` اضافه کنین. مقدار پیش‌فرضش `auto` هست. این میشه آدرس سریع اشتراکتون، مثلاً `https://sub.fuck.cloudns.biz/auto` 24 | - یه متغیر `HOST` اضافه کنین، مثلاً `edgetunnel-2z2.pages.dev` 25 | - یه متغیر `UUID` هم اضافه کنین، مثلاً `30e9c5c8-ed28-4cd9-b008-dc67277f8b02` 26 | - و در آخر، یه متغیر `PATH` اضافه کنین، مثلاً `/?ed=2048` 27 | 28 | ### 4. خط‌های بهینه شخصی خودتون رو اضافه کنین: 29 | 30 | - متغیرهای `ADD` و `ADDNOTLS` رو برای خط‌های بهینه ثابت اضافه کنین. اگه پورت نذارین، واسه TLS از 443 و واسه noTLS از 80 استفاده می‌کنه. بعد از # هم می‌تونین یه توضیح کوچیک بذارین. مثلاً: 31 | ``` 32 | icook.tw:2053#دامنه خفن 33 | cloudflare.cfgo.cc#خط رسمی توپ 34 | ``` 35 | 36 | - متغیرهای `ADDAPI` و `ADDNOTLSAPI` رو هم برای URL فایل‌های txt که آدرس‌های IP بهینه توشونه اضافه کنین. مثلاً: 37 | ```url 38 | https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/addressesapi.txt 39 | https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/addressesipv6api.txt 40 | ``` 41 | 42 |
43 | «من حرفه‌ای‌ام! پایگاه IP دارم! IPtest رو می‌شناسم! فایل csv تست سرعت هم دارم!» 44 | 45 | اوکی داداش، پس بذار اینا رو هم بهت بگم: 46 | 47 | - یه متغیر `ADDCSV` اضافه کن واسه URL فایل csv که نتایج تست سرعت iptest توشه. مثلاً: 48 | ```js 49 | https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/addressescsv.csv 50 | ``` 51 | - یه متغیر `DLS` هم بذار که مشخص کنه حداقل سرعت قابل قبول واسه `ADDCSV` چقدره. IP‌هایی که از این کندترن به لیست اشتراک بهینه اضافه نمیشن. فقط عدد بنویس، واحد مهم نیست. مثلاً: 52 | ```js 53 | 8 54 | ``` 55 | 56 |
57 | 58 | # چجوری روی Workers راه‌اندازیش کنیم؟ 59 | 60 | یه [آموزش ویدیویی](https://youtu.be/AtCF7eq0hcE) هم واسه این گذاشتم. ولی اگه ترجیح میدی بخونی، اینم توضیحاتش: 61 | 62 | ### 1. بذاریمش رو Cloudflare Worker: 63 | 64 | - برو تو داشبورد Cloudflare Worker و یه Worker جدید بساز. 65 | - محتوای [worker.js](https://github.com/cmliu/WorkerVless2sub/blob/main/_worker.js) رو کپی کن و تو ویرایشگر Worker بچسبون. 66 | 67 | ### 2. تنظیمات اصلی رو انجام بدیم: 68 | 69 | فرض کنیم دامنه پروژه Workers شما `sub.cmliussss.workers.dev` شده: 70 | - یه متغیر `TOKEN` بساز. مقدار پیش‌فرضش `auto` هست. این میشه آدرس سریع اشتراکت، مثلاً `https://sub.cmliussss.workers.dev/auto` 71 | - یه متغیر `HOST` بساز، مثلاً `edgetunnel-2z2.pages.dev` 72 | - یه متغیر `UUID` هم بساز، مثلاً `30e9c5c8-ed28-4cd9-b008-dc67277f8b02` 73 | - و یه متغیر `PATH` بساز، مثلاً `/?ed=2048` 74 | 75 | ### 3. خط‌های بهینه شخصی خودت رو اضافه کن: 76 | 77 | **3.1 تغییر پارامتر addresses** 78 | 79 | - پارامتر `addresses` رو واسه اضافه کردن خط‌های بهینه ثابت تغییر بده. اگه پورت ننویسی، از 443 استفاده می‌کنه. فعلاً نمی‌تونی اشتراک غیر TLS بسازی. بعد از # هم می‌تونی توضیح بذاری. مثلاً: 80 | ```js 81 | let addresses = [ 82 | 'icook.tw:2053#دامنه خفن', 83 | 'cloudflare.cfgo.cc#خط رسمی توپ', 84 | '185.221.160.203:443#IP بهینه تلکام', 85 | ]; 86 | ``` 87 | این روش بیشتر واسه دامنه‌های بهینه خوبه. واسه بهینه‌هایی که زیاد عوض میشن، بهتره از `addressesapi` استفاده کنی. 88 | 89 | **3.2 تغییر پارامتر addressesapi** 90 | 91 | - پارامتر `addressesapi` رو تغییر بده و URL فایل txt که آدرس‌های IP بهینه توشه رو بهش بده. مثلاً: 92 | ```js 93 | let addressesapi = [ 94 | 'https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/addressesapi.txt', 95 | 'https://addressesapi.090227.xyz/CloudFlareYes', 96 | ]; 97 | ``` 98 | می‌تونی از [addressesapi.txt](https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/addressesapi.txt) الگو بگیری و یکی واسه خودت بسازی. 99 | 100 |
101 | «من حرفه‌ای‌ام! پایگاه IP دارم! IPtest رو می‌شناسم! فایل csv تست سرعت هم دارم!» 102 | 103 | 104 | **3.3 تغییر پارامتر addressescsv** 105 | 106 | - پارامتر `addressescsv` رو تغییر بده و URL فایل csv که نتایج تست سرعت iptest توشه رو بهش بده. مثلاً: 107 | ```js 108 | let DLS = 4;//حداقل سرعت 109 | let addressescsv = [ 110 | 'https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/addressescsv.csv', 111 | 'https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/addressescsv.csv', 112 | ]; 113 | ``` 114 | `DLS` حداقل سرعت قابل قبول رو مشخص می‌کنه. IP‌هایی که از این کندترن به لیست اشتراک بهینه اضافه نمیشن. فقط عدد بنویس، واحد مهم نیست. خودت با توجه به نتایج تست سرعتت تنظیمش کن. 115 | 116 |
117 | # چجوری از این ابزار استفاده کنیم؟ 118 | 119 | یه [آموزش ویدیویی](https://youtu.be/OjqCKeEY7DQ) هم واسه این گذاشتم. ولی اگه ترجیح میدی بخونی، بفرما: 120 | 121 | فرض کنیم دامنه پروژه Workers شما `sub.cmliussss.workers.dev` شده: 122 | 123 | ## 1. اشتراک سریع 124 | 125 | - یه متغیر `TOKEN` بساز. مقدار پیش‌فرضش `auto` هست. این میشه آدرس سریع اشتراکت `/auto`. مثلاً: 126 | ```url 127 | https://sub.cmliussss.workers.dev/auto 128 | ``` 129 | 130 | ## 2. اشتراک سفارشی 131 | ### اشتراک VLESS 132 | - **فرمت اشتراک سفارشی** اینجوریه: `https://[دامنه Workers شما]/sub?host=[دامنه Vless شما]&uuid=[UUID شما]&path=[مسیر ws شما]` 133 | - **host**: دامنه مخفی VLESS شما، مثلاً `edgetunnel-2z2.pages.dev` 134 | - **uuid**: UUID کلاینت VLESS شما، مثلاً `30e9c5c8-ed28-4cd9-b008-dc67277f8b02` 135 | - **path** (اختیاری): مسیر VLESS شما (اگه نداری خالی بذار)، مثلاً `/?ed=2560` 136 | - **sni** (اختیاری): SNI VLESS شما (اگه خالی باشه از همون `host` استفاده میکنه)، مثلاً `www.10068.cn` 137 | - **type** (اختیاری): پروتکل انتقال VLESS شما (اگه خالی باشه از `ws` استفاده میکنه)، مثلاً `splithttp` 138 | - آدرس اشتراک سفارشیت اینجوری میشه: 139 | ```url 140 | https://sub.cmliussss.workers.dev/sub?host=edgetunnel-2z2.pages.dev&uuid=30e9c5c8-ed28-4cd9-b008-dc67277f8b02&path=/?ed=2560&sni=www.10068.cn&type=splithttp 141 | ``` 142 | - یادت باشه که مسیر حتماً باید "/sub" داشته باشه. 143 | 144 | ### اشتراک Trojan 145 | - **فرمت اشتراک سفارشی** اینجوریه: `https://[دامنه Workers شما]/sub?host=[دامنه Trojan شما]&pw=[رمز عبور شما]&path=[مسیر ws شما]` 146 | - **host**: دامنه مخفی Trojan شما، مثلاً `hbpb.us.kg` 147 | - **pw**: رمز عبور کلاینت Trojan شما، مثلاً `bpb-trojan` 148 | - **path** (اختیاری): مسیر Trojan شما (اگه نداری خالی بذار)، مثلاً `/tr?ed=2560` 149 | - **sni** (اختیاری): SNI Trojan شما (اگه خالی باشه از همون `host` استفاده میکنه)، مثلاً `www.10068.cn` 150 | - **type** (اختیاری): پروتکل انتقال Trojan شما (اگه خالی باشه از `ws` استفاده میکنه)، مثلاً `splithttp` 151 | - آدرس اشتراک سفارشیت اینجوری میشه: 152 | ```url 153 | https://sub.cmliussss.workers.dev/sub?host=hbpb.us.kg&pw=bpb-trojan&path=/tr?ed=2560 154 | ``` 155 | - یادت باشه که مسیر حتماً باید "/sub" داشته باشه. 156 | 157 | ## 3. تنظیمات فایل‌های clash و singbox 158 | 159 | - اگه می‌خوای فایل تنظیمات clash بگیری، `format=clash` رو اضافه کن. مثلاً: 160 | ```url 161 | https://sub.cmliussss.workers.dev/auto?format=clash 162 | https://sub.cmliussss.workers.dev/sub?format=clash&host=edgetunnel-2z2.pages.dev&uuid=30e9c5c8-ed28-4cd9-b008-dc67277f8b02&path=/?ed=2048 163 | ``` 164 | 165 | - اگه می‌خوای فایل تنظیمات singbox بگیری، `format=singbox` رو اضافه کن. مثلاً: 166 | ```url 167 | https://sub.cmliussss.workers.dev/auto?format=singbox 168 | https://sub.cmliussss.workers.dev/sub?format=singbox&host=edgetunnel-2z2.pages.dev&uuid=30e9c5c8-ed28-4cd9-b008-dc67277f8b02&path=/?ed=2048 169 | ``` 170 | 171 | # متغیرها چی هستن؟ 172 | 173 | خب، حالا یه لیست از متغیرهایی که می‌تونی استفاده کنی رو برات می‌نویسم: 174 | 175 | | متغیر | مثال | توضیح | 176 | |--------|---------|-----| 177 | | TOKEN | `auto` | مسیر اشتراک سریع واسه گره‌های داخلی /auto (می‌تونی چندتا بذاری، با `,` یا خط جدید جداشون کن) | 178 | | HOST | `edgetunnel-2z2.pages.dev` | دامنه مخفی واسه گره‌های داخلی اشتراک سریع (می‌تونی چندتا بذاری، موقع اشتراک یکی رندوم انتخاب میشه) | 179 | | UUID | `b7a392e2-4ef0-4496-90bc-1c37bb234904` | UUID گره VLESS داخلی واسه اشتراک سریع (با PASSWORD فرق داره، اگه هر دو باشن PASSWORD اولویت داره) | 180 | | PASSWORD | `bpb-trojan` | رمز عبور گره Trojan داخلی واسه اشتراک سریع (با UUID فرق داره، اگه هر دو باشن PASSWORD اولویت داره) | 181 | | PATH | `/?ed=2560` | اطلاعات مسیر گره داخلی واسه اشتراک سریع | 182 | | SNI | `www.10068.cn` | اطلاعات SNI گره داخلی واسه اشتراک سریع (اگه خالی باشه از همون `host` استفاده میکنه) | 183 | | TYPE | `splithttp` | پروتکل انتقال گره داخلی واسه اشتراک سریع (اگه خالی باشه از `ws` استفاده میکنه) | 184 | | ADD | `icook.tw:2053#دامنه رسمی بهینه` | مربوط به فیلد `addresses` (می‌تونی چندتا بذاری، با `,` یا خط جدید جداشون کن) | 185 | | ADDAPI | [https://raw.github.../addressesapi.txt](https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/addressesapi.txt) | مربوط به فیلد `addressesapi` (می‌تونی چندتا بذاری، با `,` یا خط جدید جداشون کن) | 186 | | ADDNOTLS | `icook.hk:8080#دامنه رسمی بهینه` | مربوط به فیلد `addressesnotls` (می‌تونی چندتا بذاری، با `,` یا خط جدید جداشون کن) | 187 | | ADDNOTLSAPI | [https://raw.github.../addressesapi.txt](https://raw.githubusercontent.com/cmliu/CFcdnVmess2sub/main/addressesapi.txt) | مربوط به فیلد `addressesnotlsapi` (می‌تونی چندتا بذاری، با `,` یا خط جدید جداشون کن) | 188 | | ADDCSV | [https://raw.github.../addressescsv.csv](https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/addressescsv.csv) | مربوط به فیلد `addressescsv` (می‌تونی چندتا بذاری، با `,` یا خط جدید جداشون کن) | 189 | | DLS | `8` | حداقل سرعت قابل قبول واسه نتایج تست سرعت `addressescsv` | 190 | | NOTLS | `false` | اگه بذاریش `true`، همیشه گره‌های noTLS رو برمی‌گردونه بدون اینکه دامنه رو چک کنه | 191 | | TGTOKEN | `6894123456:XXXXXXXXXX0qExVsBPUhHDAbXXXXXqWXgBA` | توکن ربات تلگرام واسه ارسال اعلان‌ها | 192 | | TGID | `6946912345` | شناسه عددی حساب تلگرام واسه دریافت اعلان‌ها | 193 | | SUBAPI | `subapi.fxxk.dedyn.io` | بک‌اند تبدیل اشتراک واسه clash، singbox و غیره | 194 | | SUBCONFIG | [https://raw.github.../ACL4SSR_Online_Full_MultiMode.ini](https://raw.githubusercontent.com/cmliu/ACL4SSR/main/Clash/config/ACL4SSR_Online_Full_MultiMode.ini) | فایل پیکربندی تبدیل اشتراک واسه clash، singbox و غیره | 195 | | SUBNAME | `WorkerVless2sub` | اسم تولیدکننده اشتراک | 196 | | SOCKS5DATA | [https://raw.github.../socks5Data](https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/socks5Data) | پول پروکسی Socks5 | 197 | | PS | `【لطفاً تست سرعت نکنید】` | پیام یادداشت واسه اسم گره | 198 | | PROXYIP | `proxyip.fxxk.dedyn.io` | ProxyIP پیش‌فرض، اگه چندتا باشه یکی رندوم انتخاب میشه (می‌تونی چندتا بذاری، با `,` یا خط جدید جداشون کن) | 199 | | CMPROXYIPS | `proxyip.aliyun.fxxk.dedyn.io#HK` | وقتی HK شناسایی بشه، ProxyIP مربوطه رو اختصاص میده (می‌تونی چندتا بذاری، با `,` یا خط جدید جداشون کن) | 200 | | CFPORTS | `2053`,`2096`,`8443` | لیست پورت‌های استاندارد حساب CF | 201 | 202 | خب، این بود همه چیزی که لازم داری بدونی. امیدوارم کمکت کرده باشه! اگه سوالی داری یا چیزی واست مبهمه، حتماً بپرس. خوشحال میشم کمکت کنم! 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🚀 优选订阅生成器 WorkerVless2sub 2 | ![sub](./sub.png) 3 | 这个是一个通过 Cloudflare Workers 搭建,自动化批量替换生成优选线路 VMess / VLESS / Trojan 节点的 **优选订阅生成器** [[实现原理]](https://www.youtube.com/watch?v=p-KhFJAC4WQ&t=70s) 4 | 5 | > [!WARNING] 6 | > 注意!这是一个**公益服务项目**,请不要将私人节点放入`LINK`变量,这会让所有人都能获得此节点!!! 7 | 8 | > Telegram交流群:[@CMLiussss](https://t.me/CMLiussss) 9 | ## 🔧 部署方法 10 | ### 🛠 Pages Github 部署 [视频教程](https://www.youtube.com/watch?v=p-KhFJAC4WQ&t=509s) 11 |
12 | 「 Pages Github 部署方法 」 13 | 14 | 1. 部署 Cloudflare Pages: 15 | - 在 Github 上先 Fork 本项目,并点上 Star !!! 16 | - 在 Cloudflare Pages 控制台中选择 `连接到 Git`后,选中 `WorkerVless2sub`项目后点击 `开始设置`。 17 | 18 | 2. 给 Pages绑定 自定义域: 19 | - 在 Pages控制台的 `自定义域`选项卡,下方点击 `设置自定义域`。 20 | - 填入你的自定义次级域名,注意不要使用你的根域名,例如: 21 | 您分配到的域名是 `fuck.cloudns.biz`,则添加自定义域填入 `sub.fuck.cloudns.biz`即可; 22 | - 按照 Cloudflare 的要求将返回你的域名DNS服务商,添加 该自定义域 `sub`的 CNAME记录 `WorkerVless2sub.pages.dev` 后,点击 `激活域`即可。 23 | 24 | 3. 修改 快速订阅入口 以及 添加内置节点信息: 25 | 26 | 例如您的pages项目域名为:`sub.fuck.cloudns.biz`; 27 | - 添加 `TOKEN` 变量,快速订阅访问入口,默认值为: `auto` ,获取订阅器默认节点订阅地址即 `/auto` ,例如 `https://sub.fuck.cloudns.biz/auto`; 28 | 29 | **添加 VLESS 内置节点信息** 30 | - 添加 `HOST` 变量,例如 `edgetunnel-2z2.pages.dev`; 31 | - 添加 `UUID` 变量,例如 `30e9c5c8-ed28-4cd9-b008-dc67277f8b02`; 32 | - 添加 `PATH` 变量,例如 `/?ed=2560`; 33 | 34 | **添加 Trojan 内置节点信息** 35 | - 添加 `HOST` 变量,例如 `hbpb.us.kg`; 36 | - 添加 `PASSWORD` 变量,例如 `bpb-trojan`; 37 | - 添加 `PATH` 变量,例如 `/tr?ed=2560`; 38 | 39 | 4. 添加你的专属优选线路: 40 | 41 | - 添加变量 `ADD`/`ADDNOTLS` 本地静态的优选线路,若不带端口号 TLS默认端口为443 / noTLS默认端口为80,#号后为备注别名,例如: 42 | ``` 43 | icook.tw:2053#优选域名 44 | cloudflare.cfgo.cc#优选官方线路 45 | ``` 46 | 47 | - 添加变量 `ADDAPI`/`ADDNOTLSAPI` 为 **优选IP地址txt文件** 的 URL。例如: 48 | ```url 49 | https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/addressesapi.txt 50 | https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/addressesipv6api.txt 51 | ``` 52 | 53 | - 添加变量 `ADDCSV` 为 **iptest测速结果csv文件地址** 的 URL。例如: 54 | ```js 55 | https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/addressescsv.csv 56 | ``` 57 | - 添加变量 `DLS` ,意为`ADDCSV`满足最低速度的要求,不满足改数值以上的IP将不会添加至优选订阅内容。注意:不考虑单位,只看数值,请按照您的测速结果而定。例如: 58 | ```js 59 | 8 60 | ``` 61 | 62 |
63 | 64 | ### ⚙️ Workers 部署方法 [视频教程](https://youtu.be/AtCF7eq0hcE) 65 | 66 |
67 | 「 Workers 部署方法 」 68 | 69 | 1. 部署 Cloudflare Worker: 70 | 71 | - 在 Cloudflare Worker 控制台中创建一个新的 Worker。 72 | - 将 [worker.js](https://github.com/cmliu/WorkerVless2sub/blob/main/_worker.js) 的内容粘贴到 Worker 编辑器中。 73 | 74 | 75 | 2. 修改 快速订阅入口 以及 添加内置节点信息: 76 | 77 | 例如您的workers项目域名为:`sub.cmliussss.workers.dev`; 78 | - 添加 `TOKEN` 变量,快速订阅访问入口,默认值为: `auto` ,获取订阅器默认节点订阅地址即 `/auto` ,例如 `https://sub.cmliussss.workers.dev/auto`; 79 | 80 | **添加 VLESS 内置节点信息** 81 | - 添加 `HOST` 变量,例如 `edgetunnel-2z2.pages.dev`; 82 | - 添加 `UUID` 变量,例如 `30e9c5c8-ed28-4cd9-b008-dc67277f8b02`; 83 | - 添加 `PATH` 变量,例如 `/?ed=2560`; 84 | 85 | **添加 Trojan 内置节点信息** 86 | - 添加 `HOST` 变量,例如 `hbpb.us.kg`; 87 | - 添加 `PASSWORD` 变量,例如 `bpb-trojan`; 88 | - 添加 `PATH` 变量,例如 `/tr?ed=2560`; 89 | 90 | 3. 添加你的专属优选线路: 91 | 92 | **3.1 修改 addresses 参数示例** 93 | 94 | - 修改 `addresses` 参数添加本地静态的优选线路,若不带端口号默认443,不支持生成非TLS订阅,#号后为备注别名,例如: 95 | ```js 96 | let addresses = [ 97 | 'icook.tw:2053#优选域名', 98 | 'cloudflare.cfgo.cc#优选官方线路', 99 | '185.221.160.203:443#电信优选IP', 100 | ]; 101 | ``` 102 | 该方式仅推荐添加优选域名的部分,频繁变更的优选推荐通过 `addressesapi` 来实现。 103 | 104 | 105 | **3.2 修改 addressesapi 参数示例** 106 | 107 | - 修改 `addressesapi` 参数,在脚本中设置 `addressesapi` 变量为 **优选IP地址txt文件** 的 URL。例如: 108 | ```js 109 | let addressesapi = [ 110 | 'https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/addressesapi.txt', 111 | 'https://addressesapi.090227.xyz/CloudFlareYes', 112 | ]; 113 | ``` 114 | 可参考 [addressesapi.txt](https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/addressesapi.txt) 内容格式 自行搭建。 115 | 116 | **3.3 修改 addressescsv 参数示例** 117 | 118 | - 修改 `addressescsv` 参数,在脚本中设置 `addressescsv` 变量为 **iptest测速结果csv文件地址** 的 URL。例如: 119 | ```js 120 | let DLS = 4;//速度下限 121 | let addressescsv = [ 122 | 'https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/addressescsv.csv', 123 | 'https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/addressescsv.csv', 124 | ]; 125 | ``` 126 | `DLS` 为要求满足的最低速度,不满足改数值以上的IP将不会添加至优选订阅内容。注意:不考虑单位,只看数值,请按照您的测速结果而定。 127 | 128 |
129 | 130 | --- 131 | 132 | ## 💡 如何使用 [视频教程](https://youtu.be/OjqCKeEY7DQ) 133 | 134 | 例如您的workers项目域名为:`sub.cmliussss.workers.dev`; 135 | 136 | ### 1. 快速订阅 137 | 138 | - 添加 `TOKEN` 变量,快速订阅访问入口,默认值为: `auto` ,获取订阅器默认节点订阅地址即 `/auto` ,例如: 139 | ```url 140 | https://sub.cmliussss.workers.dev/auto 141 | ``` 142 | 143 | ### 2. 自定义订阅 144 | 145 | **一键优选订阅** 146 | 147 | 例如您的workers项目域名为:`sub.cmliussss.workers.dev`; 148 | - 打开项目域名,填入已接入CDN的节点链接后点击`生成优选订阅`即可。 149 | 150 | **VLESS 手动订阅** 151 | - **自定义订阅格式** `https://[你的Workers域名]/sub?host=[你的Vless域名]&uuid=[你的UUID]&path=[你的ws路径]` 152 | - **host**:您的 VLESS 伪装域名,例如 `edgetunnel-2z2.pages.dev`; 153 | - **uuid**:您的 VLESS 客户端 UUID,例如 `30e9c5c8-ed28-4cd9-b008-dc67277f8b02`; 154 | - **path**(可选):您的 VLESS 路径(没有可留空不填),例如 `/?ed=2560`。 155 | - **sni**(可选):您的 VLESS 的SNI(留空则默认同`host`),例如 `www.10068.cn`。 156 | - **type**(可选):您的 VLESS 的传输协议(留空则默认为`ws`),例如 `splithttp`。 157 | - 自定义订阅地址如下: 158 | ```url 159 | https://sub.cmliussss.workers.dev/sub?host=edgetunnel-2z2.pages.dev&uuid=30e9c5c8-ed28-4cd9-b008-dc67277f8b02&path=/?ed=2560&sni=www.10068.cn&type=splithttp 160 | ``` 161 | - 注意路径必须包含 "/sub"。 162 | 163 | **Trojan 手动订阅** 164 | - **自定义订阅格式** `https://[你的Workers域名]/sub?host=[你的Trojan域名]&pw=[你的password]&path=[你的ws路径]` 165 | - **host**:您的 Trojan 伪装域名,例如 `hbpb.us.kg`; 166 | - **uuid**:您的 Trojan 客户端 Password,例如 `bpb-trojan`; 167 | - **path**(可选):您的 Trojan 路径(没有可留空不填),例如 `/tr?ed=2560`。 168 | - **sni**(可选):您的 Trojan 的SNI(留空则默认同`host`),例如 `www.10068.cn`。 169 | - **type**(可选):您的 Trojan 的传输协议(留空则默认为`ws`),例如 `splithttp`。 170 | - 自定义订阅地址如下: 171 | ```url 172 | https://sub.cmliussss.workers.dev/sub?host=hbpb.us.kg&pw=bpb-trojan&path=/tr?ed=2560 173 | ``` 174 | - 注意路径必须包含 "/sub"。 175 | 176 | ### 3. 指定 clash、singbox 配置文件 177 | 178 | - 添加 `format=clash` 键值,获取 clash 订阅配置,例如: 179 | ```url 180 | https://sub.cmliussss.workers.dev/auto?format=clash 181 | https://sub.cmliussss.workers.dev/sub?format=clash&host=edgetunnel-2z2.pages.dev&uuid=30e9c5c8-ed28-4cd9-b008-dc67277f8b02&path=/?ed=2048 182 | ``` 183 | 184 | - 添加 `format=singbox` 键值,获取 singbox 订阅配置,例如: 185 | ```url 186 | https://sub.cmliussss.workers.dev/auto?format=singbox 187 | https://sub.cmliussss.workers.dev/sub?format=singbox&host=edgetunnel-2z2.pages.dev&uuid=30e9c5c8-ed28-4cd9-b008-dc67277f8b02&path=/?ed=2048 188 | ``` 189 | 190 | ---- 191 | 192 | ## 🔑 变量说明 193 | | 变量名 | 示例 | 备注 | 194 | |--------|---------|-----| 195 | | TOKEN | `auto` | 快速订阅内置节点的订阅路径地址 /auto (支持多元素, 元素之间使用`,`或`换行`作间隔)| 196 | | HOST | `edgetunnel-2z2.pages.dev` | 快速订阅内置节点的伪装域名 (支持多元素, 订阅时随机获取, 元素之间使用`,`或`换行`作间隔) | 197 | | UUID | `b7a392e2-4ef0-4496-90bc-1c37bb234904` | 快速订阅内置VLESS节点的UUID (与变量`PASSWORD`冲突, 共存时优先使用`PASSWORD`) | 198 | | KEY | `token` | 动态UUID秘钥,使用变量`KEY`的时候,将不再启用变量`UUID`| 199 | | TIME | `7` | 动态UUID有效时间(单位:天)| 200 | | UPTIME | `3` | 动态UUID更新时间(默认:北京时间`3`点更新) | 201 | | PASSWORD | `bpb-trojan` | 快速订阅内置Trojan节点的password (与变量`UUID`冲突, 共存时优先使用`PASSWORD`) | 202 | | PATH | `/?ed=2560` | 快速订阅内置节点的路径信息 | 203 | | SNI | `www.10068.cn` | 快速订阅内置节点的SNI信息(留空则默认同`host`) | 204 | | TYPE | `splithttp` | 快速订阅内置节点的传输协议信息(留空则默认为`ws`) | 205 | | ALPN | `h3` | Alpn(留空则默认为`http/1.1`) | 206 | | ADD | `icook.tw:2053#官方优选域名` | 对应`addresses`字段 (支持多元素, 元素之间使用`,`或`换行`作间隔) | 207 | | ADDAPI | [https://raw.github.../addressesapi.txt](https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/addressesapi.txt) | 对应`addressesapi`字段 (支持多元素, 元素之间使用`,`或`换行`作间隔) | 208 | | ADDNOTLS | `icook.hk:8080#官方优选域名` | 对应`addressesnotls`字段 (支持多元素, 元素之间使用`,`或`换行`作间隔) | 209 | | ADDNOTLSAPI | [https://raw.github.../addressesapi.txt](https://raw.githubusercontent.com/cmliu/CFcdnVmess2sub/main/addressesapi.txt) | 对应`addressesnotlsapi`字段 (支持多元素, 元素之间使用`,`或`换行`作间隔) | 210 | | ADDCSV | [https://raw.github.../addressescsv.csv](https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/addressescsv.csv) | 对应`addressescsv`字段 (支持多元素, 元素之间使用`,`或`换行`作间隔) | 211 | | DLS | `8` |`addressescsv`测速结果满足速度下限 | 212 | | NOTLS | `false` | 改为`true`, 将不做域名判断 始终返回noTLS节点 | 213 | | TGTOKEN | `6894123456:XXXXXXXXXX0qExVsBPUhHDAbXXXXXqWXgBA` | 发送TG通知的机器人token | 214 | | TGID | `6946912345` | 接收TG通知的账户数字ID | 215 | | SUBAPI | `subapi.cmliussss.net` | clash、singbox等 订阅转换后端 | 216 | | SUBCONFIG | [https://raw.github.../ACL4SSR_Online_Full_MultiMode.ini](https://raw.githubusercontent.com/cmliu/ACL4SSR/main/Clash/config/ACL4SSR_Online_Full_MultiMode.ini) | clash、singbox等 订阅转换配置文件 | 217 | | SUBNAME | `优选订阅生成器` | 订阅生成器名称 | 218 | | ICO | `https://raw.cmliussss.com/favicon.ico` | 网站图标 | 219 | | PNG | `https://raw.cmliussss.com/img/CM512.png` | 网站LOGO | 220 | | IMG | `https://raw.cmliussss.com/keqing1080p.jpg` | 背景图片,多张图片将随机展示 (多元素`换行`作间隔) | 221 | | BEIAN | `提供维护: CMLiussss` | 主页维护信息 | 222 | | SOCKS5DATA | [https://raw.github.../socks5Data](https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/socks5Data) | Socks5代理池 | 223 | | PS | `【请勿测速】` | 节点名备注消息 | 224 | | PROXYIP | `proxyip.cmliussss.net` | 默认分配的ProxyIP, 多ProxyIP将随机分配(支持多元素, 元素之间使用`,`或`换行`作间隔) | 225 | | PROXYIPAPI | `https://raw.cmliussss.com/Serv00_ProxyIP.txt` | 不支持多元素 | 226 | | CMPROXYIPS | `proxyip.aliyun.cmliussss.net#HK` | 识别HK后分配对应的ProxyIP(支持多元素, 元素之间使用`,`或`换行`作间隔) | 227 | | CFPORTS | `2053`,`2096`,`8443` | CF账户标准端口列表 | 228 | | URL302 | `https://t.me/CMLiussss` | 主页302跳转(支持多url, url之间使用`,`或`换行`作间隔, 小白别用) | 229 | | URL | `https://blog.cmliussss.com` | 主页反代伪装(支持多url, url之间使用`,`或`换行`作间隔, 乱设容易触发反诈) | 230 | | LINK | `vless://b7a39...`,`vmess://ew0K...`,`https://sub...` | 补充的**公益节点链接**(不要填入私用节点), 可同时放入多个节点链接与多个订阅链接(支持多元素, 元素之间使用`,`或`换行`作间隔) | 231 | 232 | ---- 233 | 234 | ## ⭐ Star 星星走起 235 | [![Stargazers over time](https://starchart.cc/cmliu/WorkerVless2sub.svg?variant=adaptive)](https://starchart.cc/cmliu/WorkerVless2sub) 236 | 237 | # 🙏 特别鸣谢 238 | ### 💖 赞助支持 - 提供云服务器维持[订阅转换服务](https://sub.cmliussss.net/) 239 | - [Alice Networks LTD](https://url.cmliussss.com/alice) 240 | 241 | ### 🛠 开源代码引用 242 | - [SAKURA-YUMI](https://github.com/SAKURA-YUMI) 243 | - [EzSync](https://github.com/EzSync) 244 | - [ACL4SSR](https://github.com/ACL4SSR/ACL4SSR/tree/master/Clash/config) 245 | - [3Kmfi6HP](https://github.com/6Kmfi6HP/EDtunnel/blob/main/.github/workflows/obfuscator.yml) 246 | 247 | 248 | -------------------------------------------------------------------------------- /_worker.js: -------------------------------------------------------------------------------- 1 | 2 | let 快速订阅访问入口 = ['auto']; 3 | let addresses = []; 4 | let addressesapi = []; 5 | 6 | let addressesnotls = []; 7 | let addressesnotlsapi = []; 8 | 9 | let addressescsv = []; 10 | let DLS = 7; 11 | let remarkIndex = 1;//CSV备注所在列偏移量 12 | 13 | let subConverter = 'SUBAPI.cmliussss.net'; 14 | let subConfig = atob('aHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2NtbGl1L0FDTDRTU1IvbWFpbi9DbGFzaC9jb25maWcvQUNMNFNTUl9PbmxpbmVfRnVsbF9NdWx0aU1vZGUuaW5p'); 15 | let noTLS = 'false'; 16 | let link; 17 | let 隧道版本作者 = atob('ZWQ='); 18 | let 获取代理IP; 19 | let proxyIPs = [ 20 | atob('cHJveHlpcC5meHhrLmRlZHluLmlv'), 21 | ]; 22 | let 匹配PROXYIP = []; 23 | let socks5DataURL = ''; 24 | let BotToken = ''; 25 | let ChatID = ''; 26 | let 临时中转域名 = []; 27 | let 临时中转域名接口 = ''; 28 | let EndPS = ''; 29 | let 协议类型 = atob(`\u0056\u006b\u0078\u0046\u0055\u0031\u004d\u003d`); 30 | let FileName = '优选订阅生成器'; 31 | let SUBUpdateTime = 6; 32 | let total = 24; 33 | let timestamp = 4102329600000; 34 | const regex = /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|\[.*\]):?(\d+)?#?(.*)?$/; 35 | let fakeUserID; 36 | let fakeHostName; 37 | let httpsPorts = ["2053", "2083", "2087", "2096", "8443"]; 38 | let 有效时间 = 7; 39 | let 更新时间 = 3; 40 | let MamaJustKilledAMan = ['telegram', 'twitter', 'miaoko']; 41 | let proxyIPPool = []; 42 | let socks5Data; 43 | let alpn = 'h3'; 44 | let 网络备案 = `萌ICP备-20240707号`;//写你自己的维护者广告 45 | let 额外ID = '0'; 46 | let 加密方式 = 'auto'; 47 | let 网站图标, 网站头像, 网站背景, xhttp = ''; 48 | async function 整理优选列表(api) { 49 | if (!api || api.length === 0) return []; 50 | 51 | let newapi = ""; 52 | 53 | // 创建一个AbortController对象,用于控制fetch请求的取消 54 | const controller = new AbortController(); 55 | 56 | const timeout = setTimeout(() => { 57 | controller.abort(); // 取消所有请求 58 | }, 2000); // 2秒后触发 59 | 60 | try { 61 | // 使用Promise.allSettled等待所有API请求完成,无论成功或失败 62 | // 对api数组进行遍历,对每个API地址发起fetch请求 63 | const responses = await Promise.allSettled(api.map(apiUrl => fetch(apiUrl, { 64 | method: 'get', 65 | headers: { 66 | 'Accept': 'text/html,application/xhtml+xml,application/xml;', 67 | 'User-Agent': FileName + atob('IGNtbGl1L1dvcmtlclZsZXNzMnN1Yg==') 68 | }, 69 | signal: controller.signal // 将AbortController的信号量添加到fetch请求中,以便于需要时可以取消请求 70 | }).then(response => response.ok ? response.text() : Promise.reject()))); 71 | 72 | // 遍历所有响应 73 | for (const [index, response] of responses.entries()) { 74 | // 检查响应状态是否为'fulfilled',即请求成功完成 75 | if (response.status === 'fulfilled') { 76 | // 获取响应的内容 77 | const content = await response.value; 78 | 79 | const lines = content.split(/\r?\n/); 80 | let 节点备注 = ''; 81 | let 测速端口 = '443'; 82 | 83 | if (lines[0].split(',').length > 3) { 84 | const idMatch = api[index].match(/id=([^&]*)/); 85 | if (idMatch) 节点备注 = idMatch[1]; 86 | 87 | const portMatch = api[index].match(/port=([^&]*)/); 88 | if (portMatch) 测速端口 = portMatch[1]; 89 | 90 | for (let i = 1; i < lines.length; i++) { 91 | const columns = lines[i].split(',')[0]; 92 | if (columns) { 93 | newapi += `${columns}:${测速端口}${节点备注 ? `#${节点备注}` : ''}\n`; 94 | if (api[index].includes('proxyip=true')) proxyIPPool.push(`${columns}:${测速端口}`); 95 | } 96 | } 97 | } else { 98 | // 验证当前apiUrl是否带有'proxyip=true' 99 | if (api[index].includes('proxyip=true')) { 100 | // 如果URL带有'proxyip=true',则将内容添加到proxyIPPool 101 | proxyIPPool = proxyIPPool.concat((await 整理(content)).map(item => { 102 | const baseItem = item.split('#')[0] || item; 103 | if (baseItem.includes(':')) { 104 | const port = baseItem.split(':')[1]; 105 | if (!httpsPorts.includes(port)) { 106 | return baseItem; 107 | } 108 | } else { 109 | return `${baseItem}:443`; 110 | } 111 | return null; // 不符合条件时返回 null 112 | }).filter(Boolean)); // 过滤掉 null 值 113 | } 114 | // 将内容添加到newapi中 115 | newapi += content + '\n'; 116 | } 117 | } 118 | } 119 | } catch (error) { 120 | console.error(error); 121 | } finally { 122 | // 无论成功或失败,最后都清除设置的超时定时器 123 | clearTimeout(timeout); 124 | } 125 | 126 | const newAddressesapi = await 整理(newapi); 127 | 128 | // 返回处理后的结果 129 | return newAddressesapi; 130 | } 131 | 132 | async function 整理测速结果(tls) { 133 | // 参数验证 134 | if (!tls) { 135 | console.error('TLS参数不能为空'); 136 | return []; 137 | } 138 | 139 | // 检查CSV地址列表 140 | if (!Array.isArray(addressescsv) || addressescsv.length === 0) { 141 | console.warn('没有可用的CSV地址列表'); 142 | return []; 143 | } 144 | 145 | // CSV解析函数 146 | function parseCSV(text) { 147 | return text 148 | .replace(/\r\n/g, '\n') // 统一Windows换行 149 | .replace(/\r/g, '\n') // 处理老Mac换行 150 | .split('\n') // 按Unix/Linux风格分割 151 | .filter(line => line.trim() !== '') // 移除空行 152 | .map(line => line.split(',').map(cell => cell.trim())); 153 | } 154 | 155 | // 并行处理CSV 156 | const csvPromises = addressescsv.map(async (csvUrl) => { 157 | try { 158 | const response = await fetch(csvUrl); 159 | 160 | if (!response.ok) { 161 | throw new Error(`HTTP错误 ${response.status}: ${response.statusText}`); 162 | } 163 | 164 | const text = await response.text(); 165 | const rows = parseCSV(text); 166 | 167 | // 解构和验证CSV头部 168 | const [header, ...dataRows] = rows; 169 | const tlsIndex = header.findIndex(col => col.toUpperCase() === 'TLS'); 170 | 171 | if (tlsIndex === -1) { 172 | throw new Error('CSV文件缺少必需的字段'); 173 | } 174 | 175 | return dataRows 176 | .filter(row => { 177 | const tlsValue = row[tlsIndex].toUpperCase(); 178 | const speed = parseFloat(row[row.length - 1]); 179 | return tlsValue === tls.toUpperCase() && speed > DLS; 180 | }) 181 | .map(row => { 182 | const ipAddress = row[0]; 183 | const port = row[1]; 184 | const dataCenter = row[tlsIndex + remarkIndex]; 185 | const formattedAddress = `${ipAddress}:${port}#${dataCenter}`; 186 | 187 | // 处理代理IP池 188 | if (csvUrl.includes('proxyip=true') && 189 | row[tlsIndex].toUpperCase() === 'TRUE' && 190 | !httpsPorts.includes(port)) { 191 | proxyIPPool.push(`${ipAddress}:${port}`); 192 | } 193 | 194 | return formattedAddress; 195 | }); 196 | } catch (error) { 197 | console.error(`处理CSV ${csvUrl} 时出错:`, error); 198 | return []; 199 | } 200 | }); 201 | 202 | // 使用Promise.all并行处理并展平结果 203 | const results = await Promise.all(csvPromises); 204 | return results.flat(); 205 | } 206 | 207 | async function 整理(内容) { 208 | // 将制表符、双引号、单引号和换行符都替换为逗号 209 | // 然后将连续的多个逗号替换为单个逗号 210 | var 替换后的内容 = 内容.replace(/[ |"'\r\n]+/g, ',').replace(/,+/g, ','); 211 | 212 | // 删除开头和结尾的逗号(如果有的话) 213 | if (替换后的内容.charAt(0) == ',') 替换后的内容 = 替换后的内容.slice(1); 214 | if (替换后的内容.charAt(替换后的内容.length - 1) == ',') 替换后的内容 = 替换后的内容.slice(0, 替换后的内容.length - 1); 215 | 216 | // 使用逗号分割字符串,得到地址数组 217 | const 地址数组 = 替换后的内容.split(','); 218 | 219 | return 地址数组; 220 | } 221 | 222 | async function sendMessage(type, ip, add_data = "") { 223 | if (!BotToken || !ChatID) return; 224 | 225 | try { 226 | let msg = ""; 227 | const response = await fetch(`http://ip-api.com/json/${ip}?lang=zh-CN`); 228 | if (response.ok) { 229 | const ipInfo = await response.json(); 230 | msg = `${type}\nIP: ${ip}\n国家: ${ipInfo.country}\n城市: ${ipInfo.city}\n组织: ${ipInfo.org}\nASN: ${ipInfo.as}\n${add_data}`; 231 | } else { 232 | msg = `${type}\nIP: ${ip}\n${add_data}`; 233 | } 234 | 235 | const url = `https://api.telegram.org/bot${BotToken}/sendMessage?chat_id=${ChatID}&parse_mode=HTML&text=${encodeURIComponent(msg)}`; 236 | return fetch(url, { 237 | method: 'GET', 238 | headers: { 239 | 'Accept': 'text/html,application/xhtml+xml,application/xml;', 240 | 'Accept-Encoding': 'gzip, deflate, br', 241 | 'User-Agent': 'Mozilla/5.0 Chrome/90.0.4430.72' 242 | } 243 | }); 244 | } catch (error) { 245 | console.error('Error sending message:', error); 246 | } 247 | } 248 | 249 | async function nginx() { 250 | const text = ` 251 | 252 | 253 | 254 | Welcome to nginx! 255 | 262 | 263 | 264 |

Welcome to nginx!

265 |

If you see this page, the nginx web server is successfully installed and 266 | working. Further configuration is required.

267 | 268 |

For online documentation and support please refer to 269 | nginx.org.
270 | Commercial support is available at 271 | nginx.com.

272 | 273 |

Thank you for using nginx.

274 | 275 | 276 | ` 277 | return text; 278 | } 279 | 280 | function surge(content, url, path) { 281 | let 每行内容; 282 | if (content.includes('\r\n')) { 283 | 每行内容 = content.split('\r\n'); 284 | } else { 285 | 每行内容 = content.split('\n'); 286 | } 287 | 288 | let 输出内容 = ""; 289 | for (let x of 每行内容) { 290 | if (x.includes(atob('PSB0cm9qYW4s'))) { 291 | const host = x.split("sni=")[1].split(",")[0]; 292 | const 备改内容 = `skip-cert-verify=true, tfo=false, udp-relay=false`; 293 | const 正确内容 = `skip-cert-verify=true, ws=true, ws-path=${path}, ws-headers=Host:"${host}", tfo=false, udp-relay=false`; 294 | 输出内容 += x.replace(new RegExp(备改内容, 'g'), 正确内容).replace("[", "").replace("]", "") + '\n'; 295 | } else { 296 | 输出内容 += x + '\n'; 297 | } 298 | } 299 | 300 | 输出内容 = `#!MANAGED-CONFIG ${url.href} interval=86400 strict=false` + 输出内容.substring(输出内容.indexOf('\n')); 301 | return 输出内容; 302 | } 303 | 304 | function getRandomProxyByMatch(CC, socks5Data) { 305 | // 将匹配字符串转换为小写 306 | const lowerCaseMatch = CC.toLowerCase(); 307 | 308 | // 过滤出所有以指定匹配字符串结尾的代理字符串 309 | let filteredProxies = socks5Data.filter(proxy => proxy.toLowerCase().endsWith(`#${lowerCaseMatch}`)); 310 | 311 | // 如果没有匹配的代理,尝试匹配 "US" 312 | if (filteredProxies.length === 0) { 313 | filteredProxies = socks5Data.filter(proxy => proxy.toLowerCase().endsWith(`#us`)); 314 | } 315 | 316 | // 如果还是没有匹配的代理,从整个代理列表中随机选择一个 317 | if (filteredProxies.length === 0) { 318 | return socks5Data[Math.floor(Math.random() * socks5Data.length)]; 319 | } 320 | 321 | // 从匹配的代理中随机选择一个并返回 322 | const randomProxy = filteredProxies[Math.floor(Math.random() * filteredProxies.length)]; 323 | return randomProxy; 324 | } 325 | 326 | async function MD5MD5(text) { 327 | const encoder = new TextEncoder(); 328 | 329 | const firstPass = await crypto.subtle.digest('MD5', encoder.encode(text)); 330 | const firstPassArray = Array.from(new Uint8Array(firstPass)); 331 | const firstHex = firstPassArray.map(b => b.toString(16).padStart(2, '0')).join(''); 332 | 333 | const secondPass = await crypto.subtle.digest('MD5', encoder.encode(firstHex.slice(7, 27))); 334 | const secondPassArray = Array.from(new Uint8Array(secondPass)); 335 | const secondHex = secondPassArray.map(b => b.toString(16).padStart(2, '0')).join(''); 336 | 337 | return secondHex.toLowerCase(); 338 | } 339 | 340 | function revertFakeInfo(content, userID, hostName) { 341 | content = content.replace(new RegExp(fakeUserID, 'g'), userID).replace(new RegExp(fakeHostName, 'g'), hostName); 342 | return content; 343 | } 344 | 345 | function generateFakeInfo(content, userID, hostName) { 346 | content = content.replace(new RegExp(userID, 'g'), fakeUserID).replace(new RegExp(hostName, 'g'), fakeHostName); 347 | return content; 348 | } 349 | 350 | function isValidIPv4(address) { 351 | const ipv4Regex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; 352 | return ipv4Regex.test(address); 353 | } 354 | 355 | function 生成动态UUID(密钥) { 356 | const 时区偏移 = 8; // 北京时间相对于UTC的时区偏移+8小时 357 | const 起始日期 = new Date(2007, 6, 7, 更新时间, 0, 0); // 固定起始日期为2007年7月7日的凌晨3点 358 | const 一周的毫秒数 = 1000 * 60 * 60 * 24 * 有效时间; 359 | 360 | function 获取当前周数() { 361 | const 现在 = new Date(); 362 | const 调整后的现在 = new Date(现在.getTime() + 时区偏移 * 60 * 60 * 1000); 363 | const 时间差 = Number(调整后的现在) - Number(起始日期); 364 | return Math.ceil(时间差 / 一周的毫秒数); 365 | } 366 | 367 | function 生成UUID(基础字符串) { 368 | const 哈希缓冲区 = new TextEncoder().encode(基础字符串); 369 | return crypto.subtle.digest('SHA-256', 哈希缓冲区).then((哈希) => { 370 | const 哈希数组 = Array.from(new Uint8Array(哈希)); 371 | const 十六进制哈希 = 哈希数组.map(b => b.toString(16).padStart(2, '0')).join(''); 372 | return `${十六进制哈希.substr(0, 8)}-${十六进制哈希.substr(8, 4)}-4${十六进制哈希.substr(13, 3)}-${(parseInt(十六进制哈希.substr(16, 2), 16) & 0x3f | 0x80).toString(16)}${十六进制哈希.substr(18, 2)}-${十六进制哈希.substr(20, 12)}`; 373 | }); 374 | } 375 | 376 | const 当前周数 = 获取当前周数(); // 获取当前周数 377 | const 结束时间 = new Date(起始日期.getTime() + 当前周数 * 一周的毫秒数); 378 | 379 | // 生成两个 UUID 380 | const 当前UUIDPromise = 生成UUID(密钥 + 当前周数); 381 | const 上一个UUIDPromise = 生成UUID(密钥 + (当前周数 - 1)); 382 | 383 | // 格式化到期时间 384 | const 到期时间UTC = new Date(结束时间.getTime() - 时区偏移 * 60 * 60 * 1000); // UTC时间 385 | const 到期时间字符串 = `到期时间(UTC): ${到期时间UTC.toISOString().slice(0, 19).replace('T', ' ')} (UTC+8): ${结束时间.toISOString().slice(0, 19).replace('T', ' ')}\n`; 386 | 387 | return Promise.all([当前UUIDPromise, 上一个UUIDPromise, 到期时间字符串]); 388 | } 389 | 390 | async function getLink(重新汇总所有链接) { 391 | let 节点LINK = []; 392 | let 订阅链接 = []; 393 | for (let x of 重新汇总所有链接) { 394 | if (x.toLowerCase().startsWith('http')) { 395 | 订阅链接.push(x); 396 | } else { 397 | 节点LINK.push(x); 398 | } 399 | } 400 | 401 | if (订阅链接 && 订阅链接.length !== 0) { 402 | function base64Decode(str) { 403 | const bytes = new Uint8Array(atob(str).split('').map(c => c.charCodeAt(0))); 404 | const decoder = new TextDecoder('utf-8'); 405 | return decoder.decode(bytes); 406 | } 407 | const controller = new AbortController(); // 创建一个AbortController实例,用于取消请求 408 | 409 | const timeout = setTimeout(() => { 410 | controller.abort(); // 2秒后取消所有请求 411 | }, 2000); 412 | 413 | try { 414 | // 使用Promise.allSettled等待所有API请求完成,无论成功或失败 415 | const responses = await Promise.allSettled(订阅链接.map(apiUrl => fetch(apiUrl, { 416 | method: 'get', 417 | headers: { 418 | 'Accept': 'text/html,application/xhtml+xml,application/xml;', 419 | 'User-Agent': `\u0076\u0032\u0072\u0061\u0079\u004e\u002f${FileName + atob('IGNtbGl1L1dvcmtlclZsZXNzMnN1Yg==')}` 420 | }, 421 | signal: controller.signal // 将AbortController的信号量添加到fetch请求中 422 | }).then(response => response.ok ? response.text() : Promise.reject()))); 423 | 424 | // 遍历所有响应 425 | const modifiedResponses = responses.map((response, index) => { 426 | // 检查是否请求成功 427 | return { 428 | status: response.status, 429 | value: response.status === 'fulfilled' ? response.value : null, 430 | apiUrl: 订阅链接[index] // 将原始的apiUrl添加到返回对象中 431 | }; 432 | }); 433 | 434 | console.log(modifiedResponses); // 输出修改后的响应数组 435 | 436 | for (const response of modifiedResponses) { 437 | // 检查响应状态是否为'fulfilled' 438 | if (response.status === 'fulfilled') { 439 | const content = await response.value || 'null'; // 获取响应的内容 440 | if (content.includes('://')) { 441 | const lines = content.includes('\r\n') ? content.split('\r\n') : content.split('\n'); 442 | 节点LINK = 节点LINK.concat(lines); 443 | } else { 444 | const 尝试base64解码内容 = base64Decode(content); 445 | if (尝试base64解码内容.includes('://')) { 446 | const lines = 尝试base64解码内容.includes('\r\n') ? 尝试base64解码内容.split('\r\n') : 尝试base64解码内容.split('\n'); 447 | 节点LINK = 节点LINK.concat(lines); 448 | } 449 | } 450 | } 451 | } 452 | } catch (error) { 453 | console.error(error); // 捕获并输出错误信息 454 | } finally { 455 | clearTimeout(timeout); // 清除定时器 456 | } 457 | } 458 | 459 | return 节点LINK; 460 | } 461 | 462 | function utf8ToBase64(str) { 463 | return btoa(unescape(encodeURIComponent(str))); 464 | } 465 | 466 | export default { 467 | async fetch(request, env) { 468 | if (env.TOKEN) 快速订阅访问入口 = await 整理(env.TOKEN); 469 | BotToken = env.TGTOKEN || BotToken; 470 | ChatID = env.TGID || ChatID; 471 | subConverter = env.SUBAPI || subConverter; 472 | subConfig = env.SUBCONFIG || subConfig; 473 | FileName = env.SUBNAME || FileName; 474 | socks5DataURL = env.SOCKS5DATA || socks5DataURL; 475 | if (env.CMPROXYIPS) 匹配PROXYIP = await 整理(env.CMPROXYIPS);; 476 | if (env.CFPORTS) httpsPorts = await 整理(env.CFPORTS); 477 | EndPS = env.PS || EndPS; 478 | 网站图标 = env.ICO ? `` : ''; 479 | 网站头像 = env.PNG ? `
Logo
` : ''; 480 | if (env.IMG) { 481 | const imgs = await 整理(env.IMG); 482 | 网站背景 = `background-image: url('${imgs[Math.floor(Math.random() * imgs.length)]}');`; 483 | } else 网站背景 = ''; 484 | 网络备案 = env.BEIAN || env.BY || 网络备案; 485 | const userAgentHeader = request.headers.get('User-Agent'); 486 | const userAgent = userAgentHeader ? userAgentHeader.toLowerCase() : "null"; 487 | const url = new URL(request.url); 488 | const format = url.searchParams.get('format') ? url.searchParams.get('format').toLowerCase() : "null"; 489 | let host = ""; 490 | let uuid = ""; 491 | let path = ""; 492 | let sni = ""; 493 | let type = "ws"; 494 | alpn = env.ALPN || alpn; 495 | let UD = Math.floor(((timestamp - Date.now()) / timestamp * 99 * 1099511627776) / 2); 496 | if (env.UA) MamaJustKilledAMan = MamaJustKilledAMan.concat(await 整理(env.UA)); 497 | 498 | const currentDate = new Date(); 499 | const fakeUserIDMD5 = await MD5MD5(Math.ceil(currentDate.getTime())); 500 | fakeUserID = fakeUserIDMD5.slice(0, 8) + "-" + fakeUserIDMD5.slice(8, 12) + "-" + fakeUserIDMD5.slice(12, 16) + "-" + fakeUserIDMD5.slice(16, 20) + "-" + fakeUserIDMD5.slice(20); 501 | fakeHostName = fakeUserIDMD5.slice(6, 9) + "." + fakeUserIDMD5.slice(13, 19) + ".xyz"; 502 | 503 | total = total * 1099511627776; 504 | let expire = Math.floor(timestamp / 1000); 505 | 506 | link = env.LINK || link; 507 | 508 | if (env.ADD) addresses = await 整理(env.ADD); 509 | if (env.ADDAPI) addressesapi = await 整理(env.ADDAPI); 510 | if (env.ADDNOTLS) addressesnotls = await 整理(env.ADDNOTLS); 511 | if (env.ADDNOTLSAPI) addressesnotlsapi = await 整理(env.ADDNOTLSAPI); 512 | if (env.ADDCSV) addressescsv = await 整理(env.ADDCSV); 513 | DLS = Number(env.DLS) || DLS; 514 | remarkIndex = Number(env.CSVREMARK) || remarkIndex; 515 | 516 | if (socks5DataURL) { 517 | try { 518 | const response = await fetch(socks5DataURL); 519 | const socks5DataText = await response.text(); 520 | if (socks5DataText.includes('\r\n')) { 521 | socks5Data = socks5DataText.split('\r\n').filter(line => line.trim() !== ''); 522 | } else { 523 | socks5Data = socks5DataText.split('\n').filter(line => line.trim() !== ''); 524 | } 525 | } catch { 526 | socks5Data = null; 527 | } 528 | } 529 | 530 | let 临时proxyIPs = []; 531 | if (env.PROXYIP) 临时proxyIPs = await 整理(env.PROXYIP); 532 | if (env.PROXYIPAPI) { 533 | const proxyIPsapi = await 整理(env.PROXYIPAPI); 534 | if (proxyIPsapi.length > 0) { 535 | const response = await fetch(proxyIPsapi[0]); 536 | if (response.ok) { 537 | const 响应内容 = await response.text(); 538 | const 整理成数组 = await 整理(响应内容); 539 | if (整理成数组.length > 0) { 540 | 临时proxyIPs = 临时proxyIPs.concat(整理成数组); //追加到proxyIPs数组中 541 | } 542 | } 543 | } 544 | } 545 | //去重去除空元素 546 | 临时proxyIPs = [...new Set(临时proxyIPs.filter(item => item && item.trim() !== ''))]; 547 | if (临时proxyIPs.length > 0) proxyIPs = 临时proxyIPs; 548 | //console.log(proxyIPs); 549 | 550 | if (快速订阅访问入口.length > 0 && 快速订阅访问入口.some(token => url.pathname.includes(token))) { 551 | host = "null"; 552 | if (env.HOST) { 553 | const hosts = await 整理(env.HOST); 554 | host = hosts[Math.floor(Math.random() * hosts.length)]; 555 | } 556 | 557 | if (env.PASSWORD) { 558 | 协议类型 = atob('VHJvamFu'); 559 | uuid = env.PASSWORD 560 | } else { 561 | 协议类型 = atob(`\u0056\u006b\u0078\u0046\u0055\u0031\u004d\u003d`); 562 | if (env.KEY) { 563 | 有效时间 = Number(env.TIME) || 有效时间; 564 | 更新时间 = Number(env.UPTIME) || 更新时间; 565 | const userIDs = await 生成动态UUID(env.KEY); 566 | uuid = userIDs[0]; 567 | } else { 568 | uuid = env.UUID || "null"; 569 | } 570 | } 571 | 572 | path = env.PATH || "/?ed=2560"; 573 | sni = env.SNI || host; 574 | type = env.TYPE || type; 575 | 隧道版本作者 = env.ED || 隧道版本作者; 576 | 获取代理IP = env.RPROXYIP || 'false'; 577 | 578 | if (host == "null" || uuid == "null") { 579 | let 空字段; 580 | if (host == "null" && uuid == "null") 空字段 = "HOST/UUID"; 581 | else if (host == "null") 空字段 = "HOST"; 582 | else if (uuid == "null") 空字段 = "UUID"; 583 | EndPS += ` 订阅器内置节点 ${空字段} 未设置!!!`; 584 | } 585 | 586 | await sendMessage(`#获取订阅 ${FileName}`, request.headers.get('CF-Connecting-IP'), `UA: ${userAgentHeader}
\n域名: ${url.hostname}\n入口: ${url.pathname + url.search}`); 587 | } else { 588 | host = url.searchParams.get('host'); 589 | uuid = url.searchParams.get('uuid') || url.searchParams.get('password') || url.searchParams.get('pw'); 590 | path = url.searchParams.get('path'); 591 | sni = url.searchParams.get('sni') || host; 592 | type = url.searchParams.get('type') || type; 593 | const mode = url.searchParams.get('mode') || null; 594 | const extra = url.searchParams.get('extra') || null; 595 | xhttp = (mode ? `&mode=${mode}` : "") + (extra ? `&extra=${encodeURIComponent(extra)}` : ""); 596 | alpn = url.searchParams.get('alpn') || (xhttp ? "h3%2Ch2" : alpn); 597 | 隧道版本作者 = url.searchParams.get(atob('ZWRnZXR1bm5lbA==')) || url.searchParams.get(atob('ZXBlaXVz')) || 隧道版本作者; 598 | 获取代理IP = url.searchParams.get('proxyip') || 'false'; 599 | 600 | if (url.searchParams.has('alterid')) { 601 | 协议类型 = 'VMess'; 602 | 额外ID = url.searchParams.get('alterid') || 额外ID; 603 | 加密方式 = url.searchParams.get('security') || 加密方式; 604 | } else if (url.searchParams.has(atob('ZWRnZXR1bm5lbA==')) || url.searchParams.has('uuid')) { 605 | 协议类型 = atob('VkxFU1M='); 606 | } else if (url.searchParams.has(atob('ZXBlaXVz')) || url.searchParams.has('password') || url.searchParams.has('pw')) { 607 | 协议类型 = atob('VHJvamFu'); 608 | } 609 | 610 | if (!url.pathname.includes("/sub")) { 611 | const envKey = env.URL302 ? 'URL302' : (env.URL ? 'URL' : null); 612 | if (envKey) { 613 | const URLs = await 整理(env[envKey]); 614 | if (URLs.includes('nginx')) { 615 | return new Response(await nginx(), { 616 | headers: { 617 | 'Content-Type': 'text/html; charset=UTF-8', 618 | }, 619 | }); 620 | } 621 | const URL = URLs[Math.floor(Math.random() * URLs.length)]; 622 | return envKey === 'URL302' ? Response.redirect(URL, 302) : fetch(new Request(URL, request)); 623 | } 624 | return await subHtml(request); 625 | } 626 | 627 | if (!host || !uuid) { 628 | const responseText = ` 629 | 缺少必填参数:host 和 uuid 630 | Missing required parameters: host and uuid 631 | پارامترهای ضروری وارد نشده: هاست و یوآی‌دی 632 | 633 | ${url.origin}/sub?host=[your host]&uuid=[your uuid]&path=[your path] 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | ${atob('aHR0cHM6Ly9naXRodWIuY29tL2NtbGl1L3dvcmtlclZsZXNzMnN1Yg==')} 642 | `; 643 | 644 | return new Response(responseText, { 645 | status: 202, 646 | headers: { 'content-type': 'text/plain; charset=utf-8' }, 647 | }); 648 | } 649 | 650 | if (!path || path.trim() === '') { 651 | path = '/?ed=2560'; 652 | } else { 653 | // 如果第一个字符不是斜杠,则在前面添加一个斜杠 654 | path = (path[0] === '/') ? path : '/' + path; 655 | } 656 | } 657 | 658 | if (host.toLowerCase().includes('notls') || host.toLowerCase().includes('worker') || host.toLowerCase().includes('trycloudflare')) noTLS = 'true'; 659 | noTLS = env.NOTLS || noTLS; 660 | let subConverterUrl = generateFakeInfo(url.href, uuid, host); 661 | if (userAgent.includes('subconverter')) alpn = ''; 662 | if (!userAgent.includes('subconverter') && MamaJustKilledAMan.some(PutAGunAgainstHisHeadPulledMyTriggerNowHesDead => userAgent.includes(PutAGunAgainstHisHeadPulledMyTriggerNowHesDead)) && MamaJustKilledAMan.length > 0) { 663 | const envKey = env.URL302 ? 'URL302' : (env.URL ? 'URL' : null); 664 | if (envKey) { 665 | const URLs = await 整理(env[envKey]); 666 | if (URLs.includes('nginx')) { 667 | return new Response(await nginx(), { 668 | headers: { 669 | 'Content-Type': 'text/html; charset=UTF-8', 670 | }, 671 | }); 672 | } 673 | const URL = URLs[Math.floor(Math.random() * URLs.length)]; 674 | return envKey === 'URL302' ? Response.redirect(URL, 302) : fetch(new Request(URL, request)); 675 | } 676 | return await subHtml(request); 677 | } else if ((userAgent.includes('clash') || (format === 'clash' && !userAgent.includes('subconverter'))) && !userAgent.includes('nekobox') && !userAgent.includes('cf-workers-sub')) { 678 | subConverterUrl = `https://${subConverter}/sub?target=clash&url=${encodeURIComponent(subConverterUrl)}&insert=false&config=${encodeURIComponent(subConfig)}&emoji=true&list=false&tfo=false&scv=true&fdn=false&sort=false&new_name=true`; 679 | } else if ((userAgent.includes('sing-box') || userAgent.includes('singbox') || (format === 'singbox' && !userAgent.includes('subconverter'))) && !userAgent.includes('cf-workers-sub')) { 680 | if (协议类型 == 'VMess' && url.href.includes('path=')) { 681 | const 路径参数前部分 = url.href.split('path=')[0]; 682 | const parts = url.href.split('path=')[1].split('&'); 683 | const 路径参数后部分 = parts.slice(1).join('&') || ''; 684 | const 待处理路径参数 = url.href.split('path=')[1].split('&')[0] || ''; 685 | if (待处理路径参数.includes('%3F')) subConverterUrl = generateFakeInfo(路径参数前部分 + 'path=' + 待处理路径参数.split('%3F')[0] + '&' + 路径参数后部分, uuid, host); 686 | } 687 | subConverterUrl = `https://${subConverter}/sub?target=singbox&url=${encodeURIComponent(subConverterUrl)}&insert=false&config=${encodeURIComponent(subConfig)}&emoji=true&list=false&tfo=false&scv=true&fdn=false&sort=false&new_name=true`; 688 | } else { 689 | if (host.includes('workers.dev')) { 690 | if (临时中转域名接口) { 691 | try { 692 | const response = await fetch(临时中转域名接口); 693 | 694 | if (!response.ok) { 695 | console.error('获取地址时出错:', response.status, response.statusText); 696 | return; // 如果有错误,直接返回 697 | } 698 | 699 | const text = await response.text(); 700 | const lines = text.split('\n'); 701 | // 过滤掉空行或只包含空白字符的行 702 | const nonEmptyLines = lines.filter(line => line.trim() !== ''); 703 | 704 | 临时中转域名 = 临时中转域名.concat(nonEmptyLines); 705 | } catch (error) { 706 | console.error('获取地址时出错:', error); 707 | } 708 | } 709 | // 使用Set对象去重 710 | 临时中转域名 = [...new Set(临时中转域名)]; 711 | } 712 | 713 | const newAddressesapi = await 整理优选列表(addressesapi); 714 | const newAddressescsv = await 整理测速结果('TRUE'); 715 | const uniqueAddresses = Array.from(new Set(addresses.concat(newAddressesapi, newAddressescsv).filter(item => item && item.trim()))); 716 | 717 | let notlsresponseBody; 718 | if ((noTLS == 'true' && 协议类型 == atob(`\u0056\u006b\u0078\u0046\u0055\u0031\u004d\u003d`)) || 协议类型 == 'VMess') { 719 | const newAddressesnotlsapi = await 整理优选列表(addressesnotlsapi); 720 | const newAddressesnotlscsv = await 整理测速结果('FALSE'); 721 | const uniqueAddressesnotls = Array.from(new Set(addressesnotls.concat(newAddressesnotlsapi, newAddressesnotlscsv).filter(item => item && item.trim()))); 722 | 723 | notlsresponseBody = uniqueAddressesnotls.map(address => { 724 | let port = "-1"; 725 | let addressid = address; 726 | 727 | const match = addressid.match(regex); 728 | if (!match) { 729 | if (address.includes(':') && address.includes('#')) { 730 | const parts = address.split(':'); 731 | address = parts[0]; 732 | const subParts = parts[1].split('#'); 733 | port = subParts[0]; 734 | addressid = subParts[1]; 735 | } else if (address.includes(':')) { 736 | const parts = address.split(':'); 737 | address = parts[0]; 738 | port = parts[1]; 739 | } else if (address.includes('#')) { 740 | const parts = address.split('#'); 741 | address = parts[0]; 742 | addressid = parts[1]; 743 | } 744 | 745 | if (addressid.includes(':')) { 746 | addressid = addressid.split(':')[0]; 747 | } 748 | } else { 749 | address = match[1]; 750 | port = match[2] || port; 751 | addressid = match[3] || address; 752 | } 753 | 754 | const httpPorts = ["8080", "8880", "2052", "2082", "2086", "2095"]; 755 | if (!isValidIPv4(address) && port == "-1") { 756 | for (let httpPort of httpPorts) { 757 | if (address.includes(httpPort)) { 758 | port = httpPort; 759 | break; 760 | } 761 | } 762 | } 763 | if (port == "-1") port = "80"; 764 | //console.log(address, port, addressid); 765 | 766 | if (隧道版本作者.trim() === atob('Y21saXU=') && 获取代理IP.trim() === 'true') { 767 | // 将addressid转换为小写 768 | let lowerAddressid = addressid.toLowerCase(); 769 | // 初始化找到的proxyIP为null 770 | let foundProxyIP = null; 771 | 772 | if (socks5Data) { 773 | const socks5 = getRandomProxyByMatch(lowerAddressid, socks5Data); 774 | path = `/${socks5}`; 775 | } else { 776 | // 遍历匹配PROXYIP数组查找匹配项 777 | for (let item of 匹配PROXYIP) { 778 | if (item.includes('#') && item.split('#')[1] && lowerAddressid.includes(item.split('#')[1].toLowerCase())) { 779 | foundProxyIP = item.split('#')[0]; 780 | break; // 找到匹配项,跳出循环 781 | } else if (item.includes(':') && item.split(':')[1] && lowerAddressid.includes(item.split(':')[1].toLowerCase())) { 782 | foundProxyIP = item.split(':')[0]; 783 | break; // 找到匹配项,跳出循环 784 | } 785 | } 786 | 787 | if (foundProxyIP) { 788 | // 如果找到匹配的proxyIP,赋值给path 789 | path = atob('L3Byb3h5aXA9') + foundProxyIP; 790 | } else { 791 | // 如果没有找到匹配项,随机选择一个proxyIP 792 | const randomProxyIP = proxyIPs[Math.floor(Math.random() * proxyIPs.length)]; 793 | path = atob('L3Byb3h5aXA9') + randomProxyIP; 794 | } 795 | } 796 | } 797 | 798 | if (协议类型 == 'VMess') { 799 | const vmessLink = `vmess://${utf8ToBase64(`{"v":"2","ps":"${addressid + EndPS}","add":"${address}","port":"${port}","id":"${uuid}","aid":"${额外ID}","scy":"${加密方式}","net":"ws","type":"${type}","host":"${host}","path":"${path}","tls":"","sni":"","alpn":"${encodeURIComponent(alpn)}","fp":""}`)}`; 800 | return vmessLink; 801 | } else { 802 | const 维列斯Link = `${atob('dmxlc3M6Ly8=') + uuid}@${address}:${port + atob('P2VuY3J5cHRpb249bm9uZSZzZWN1cml0eT0mdHlwZT0=') + type}&host=${host}&path=${encodeURIComponent(path)}#${encodeURIComponent(addressid + EndPS)}`; 803 | return 维列斯Link; 804 | } 805 | 806 | }).join('\n'); 807 | } 808 | 809 | const responseBody = uniqueAddresses.map(address => { 810 | let port = "-1"; 811 | let addressid = address; 812 | 813 | const match = addressid.match(regex); 814 | if (!match) { 815 | if (address.includes(':') && address.includes('#')) { 816 | const parts = address.split(':'); 817 | address = parts[0]; 818 | const subParts = parts[1].split('#'); 819 | port = subParts[0]; 820 | addressid = subParts[1]; 821 | } else if (address.includes(':')) { 822 | const parts = address.split(':'); 823 | address = parts[0]; 824 | port = parts[1]; 825 | } else if (address.includes('#')) { 826 | const parts = address.split('#'); 827 | address = parts[0]; 828 | addressid = parts[1]; 829 | } 830 | 831 | if (addressid.includes(':')) { 832 | addressid = addressid.split(':')[0]; 833 | } 834 | } else { 835 | address = match[1]; 836 | port = match[2] || port; 837 | addressid = match[3] || address; 838 | } 839 | 840 | if (!isValidIPv4(address) && port == "-1") { 841 | for (let httpsPort of httpsPorts) { 842 | if (address.includes(httpsPort)) { 843 | port = httpsPort; 844 | break; 845 | } 846 | } 847 | } 848 | if (port == "-1") port = "443"; 849 | 850 | //console.log(address, port, addressid); 851 | 852 | if (隧道版本作者.trim() === atob('Y21saXU=') && 获取代理IP.trim() === 'true') { 853 | // 将addressid转换为小写 854 | let lowerAddressid = addressid.toLowerCase(); 855 | // 初始化找到的proxyIP为null 856 | let foundProxyIP = null; 857 | 858 | if (socks5Data) { 859 | const socks5 = getRandomProxyByMatch(lowerAddressid, socks5Data); 860 | path = `/${socks5}`; 861 | } else { 862 | // 遍历匹配PROXYIP数组查找匹配项 863 | for (let item of 匹配PROXYIP) { 864 | if (item.includes('#') && item.split('#')[1] && lowerAddressid.includes(item.split('#')[1].toLowerCase())) { 865 | foundProxyIP = item.split('#')[0]; 866 | break; // 找到匹配项,跳出循环 867 | } else if (item.includes(':') && item.split(':')[1] && lowerAddressid.includes(item.split(':')[1].toLowerCase())) { 868 | foundProxyIP = item.split(':')[0]; 869 | break; // 找到匹配项,跳出循环 870 | } 871 | } 872 | 873 | const matchingProxyIP = proxyIPPool.find(proxyIP => proxyIP.includes(address)); 874 | if (matchingProxyIP) { 875 | path = atob('L3Byb3h5aXA9') + matchingProxyIP; 876 | } else if (foundProxyIP) { 877 | // 如果找到匹配的proxyIP,赋值给path 878 | path = atob('L3Byb3h5aXA9') + foundProxyIP; 879 | } else { 880 | // 如果没有找到匹配项,随机选择一个proxyIP 881 | const randomProxyIP = proxyIPs[Math.floor(Math.random() * proxyIPs.length)]; 882 | path = atob('L3Byb3h5aXA9') + randomProxyIP; 883 | } 884 | } 885 | } 886 | 887 | let 伪装域名 = host; 888 | let 最终路径 = path; 889 | let 节点备注 = EndPS; 890 | if (临时中转域名.length > 0 && (host.includes('.workers.dev'))) { 891 | 最终路径 = `/${host}${path}`; 892 | 伪装域名 = 临时中转域名[Math.floor(Math.random() * 临时中转域名.length)]; 893 | 节点备注 = EndPS + atob('IOW3suWQr+eUqOS4tOaXtuWfn+WQjeS4rei9rOacjeWKoe+8jOivt+WwveW/q+e7keWumuiHquWumuS5ieWfn++8gQ=='); 894 | sni = 伪装域名; 895 | } 896 | 897 | if (协议类型 == 'VMess') { 898 | const vmessLink = `vmess://${utf8ToBase64(`{"v":"2","ps":"${addressid + 节点备注}","add":"${address}","port":"${port}","id":"${uuid}","aid":"${额外ID}","scy":"${加密方式}","net":"ws","type":"${type}","host":"${伪装域名}","path":"${最终路径}","tls":"tls","sni":"${sni}","alpn":"${encodeURIComponent(alpn)}","fp":"","allowInsecure":"1","fragment":"1,40-60,30-50,tlshello"}`)}`; 899 | return vmessLink; 900 | } else if (协议类型 == atob('VHJvamFu')) { 901 | const 特洛伊Link = `${atob('dHJvamFuOi8v') + uuid}@${address}:${port + atob('P3NlY3VyaXR5PXRscyZzbmk9') + sni}&alpn=${encodeURIComponent(alpn)}&fp=randomized&type=${type}&host=${伪装域名}&path=${encodeURIComponent(最终路径)}&allowInsecure=1&fragment=1,40-60,30-50,tlshello#${encodeURIComponent(addressid + 节点备注)}`; 902 | return 特洛伊Link; 903 | } else { 904 | const 维列斯Link = `${atob('dmxlc3M6Ly8=') + uuid}@${address}:${port + atob('P2VuY3J5cHRpb249bm9uZSZzZWN1cml0eT10bHMmc25pPQ==') + sni}&alpn=${encodeURIComponent(alpn)}&fp=random&type=${type}&host=${伪装域名}&path=${encodeURIComponent(最终路径) + xhttp}&allowInsecure=1&fragment=1,40-60,30-50,tlshello#${encodeURIComponent(addressid + 节点备注)}`; 905 | return 维列斯Link; 906 | } 907 | 908 | }).join('\n'); 909 | 910 | let combinedContent = responseBody; // 合并内容 911 | 912 | if (link) { 913 | const links = await 整理(link); 914 | const 整理节点LINK = (await getLink(links)).join('\n'); 915 | combinedContent += '\n' + 整理节点LINK; 916 | console.log("link: " + 整理节点LINK) 917 | } 918 | 919 | if (notlsresponseBody && noTLS == 'true') { 920 | combinedContent += '\n' + notlsresponseBody; 921 | console.log("notlsresponseBody: " + notlsresponseBody); 922 | } 923 | 924 | if (协议类型 == atob('VHJvamFu') && (userAgent.includes('surge') || (format === 'surge' && !userAgent.includes('subconverter'))) && !userAgent.includes('cf-workers-sub')) { 925 | const 特洛伊Links = combinedContent.split('\n'); 926 | const 特洛伊LinksJ8 = generateFakeInfo(特洛伊Links.join('|'), uuid, host); 927 | subConverterUrl = `https://${subConverter}/sub?target=surge&ver=4&url=${encodeURIComponent(特洛伊LinksJ8)}&insert=false&config=${encodeURIComponent(subConfig)}&emoji=true&list=false&xudp=false&udp=false&tfo=false&expand=true&scv=true&fdn=false`; 928 | } else { 929 | 930 | let base64Response; 931 | try { 932 | base64Response = btoa(combinedContent); // 重新进行 Base64 编码 933 | } catch (e) { 934 | function encodeBase64(data) { 935 | const binary = new TextEncoder().encode(data); 936 | let base64 = ''; 937 | const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; 938 | 939 | for (let i = 0; i < binary.length; i += 3) { 940 | const byte1 = binary[i]; 941 | const byte2 = binary[i + 1] || 0; 942 | const byte3 = binary[i + 2] || 0; 943 | 944 | base64 += chars[byte1 >> 2]; 945 | base64 += chars[((byte1 & 3) << 4) | (byte2 >> 4)]; 946 | base64 += chars[((byte2 & 15) << 2) | (byte3 >> 6)]; 947 | base64 += chars[byte3 & 63]; 948 | } 949 | 950 | const padding = 3 - (binary.length % 3 || 3); 951 | return base64.slice(0, base64.length - padding) + '=='.slice(0, padding); 952 | } 953 | 954 | base64Response = encodeBase64(combinedContent); 955 | } 956 | 957 | const response = new Response(base64Response, { 958 | headers: { 959 | //"Content-Disposition": `attachment; filename*=utf-8''${encodeURIComponent(FileName)}; filename=${FileName}`, 960 | "content-type": "text/plain; charset=utf-8", 961 | "Profile-Update-Interval": `${SUBUpdateTime}`, 962 | //"Subscription-Userinfo": `upload=${UD}; download=${UD}; total=${total}; expire=${expire}`, 963 | }, 964 | }); 965 | 966 | return response; 967 | } 968 | 969 | } 970 | 971 | try { 972 | const subConverterResponse = await fetch(subConverterUrl); 973 | 974 | if (!subConverterResponse.ok) { 975 | throw new Error(`Error fetching subConverterUrl: ${subConverterResponse.status} ${subConverterResponse.statusText}`); 976 | } 977 | 978 | let subConverterContent = await subConverterResponse.text(); 979 | 980 | if (协议类型 == atob('VHJvamFu') && (userAgent.includes('surge') || (format === 'surge' && !userAgent.includes('subconverter'))) && !userAgent.includes('cf-workers-sub')) { 981 | subConverterContent = surge(subConverterContent, host, path); 982 | } 983 | subConverterContent = revertFakeInfo(subConverterContent, uuid, host); 984 | return new Response(subConverterContent, { 985 | headers: { 986 | "Content-Disposition": `attachment; filename*=utf-8''${encodeURIComponent(FileName)}; filename=${FileName}`, 987 | "content-type": "text/plain; charset=utf-8", 988 | "Profile-Update-Interval": `${SUBUpdateTime}`, 989 | //"Subscription-Userinfo": `upload=${UD}; download=${UD}; total=${total}; expire=${expire}`, 990 | }, 991 | }); 992 | } catch (error) { 993 | return new Response(`Error: ${error.message}`, { 994 | status: 500, 995 | headers: { 'content-type': 'text/plain; charset=utf-8' }, 996 | }); 997 | } 998 | } 999 | }; 1000 | 1001 | async function subHtml(request) { 1002 | const url = new URL(request.url); 1003 | const HTML = ` 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | ${FileName} 1010 | ${网站图标} 1011 | 1312 | 1313 | 1314 | 1315 | 1316 | 1321 | 1322 |
1323 |
1324 | ${网站头像} 1325 |

${FileName}

1326 |
1327 |
1328 | 1329 | 1330 |
1331 | 1332 | 1333 | 1334 |
1335 |
1336 | 1337 |
1338 | ! 1339 |
1340 | 安全提示:使用优选订阅生成器时,需要您提交 节点配置信息 用于生成优选订阅链接。这意味着订阅器的维护者可能会获取到该节点信息。请自行斟酌使用风险。
1341 |
1342 | 订阅转换后端:${subConverter}
1343 | 订阅转换配置文件:${subConfig} 1344 |
1345 |
1346 |
1347 | 1348 | 1349 |
1350 |
${网络备案}
1351 |
1352 | 1353 | 1454 | 1455 | 1456 | `; 1457 | 1458 | return new Response(HTML, { 1459 | headers: { 1460 | "content-type": "text/html;charset=UTF-8", 1461 | }, 1462 | }); 1463 | } -------------------------------------------------------------------------------- /addressesapi.txt: -------------------------------------------------------------------------------- 1 | 16.162.37.167:443#HK 2 | 8.217.232.246:2096#HK 3 | 16.162.10.198:443#HK 4 | 8.217.232.246:2053#HK 5 | -------------------------------------------------------------------------------- /addressesipv6api.txt: -------------------------------------------------------------------------------- 1 | [2606:4700:3037:e1:a64b:6580:941f:e09]:80#官方优选IPv6 2 | [2606:4700:3035:d692:2d67:7f9:cf4b:162b]:80#官方优选IPv6 3 | [2606:4700:3038:0:aa27:d7c9:4240:90e0]:80#官方优选IPv6 4 | [2606:4700:3035:1249:bf57:9983:fba9:2108]:80#官方优选IPv6 5 | [2606:4700:3038:0:a2:c0ff:1c7b:9958]:80#官方优选IPv6 6 | [2606:4700:3035:1249:bfe2:dd:1d08:2554]:80#官方优选IPv6 7 | [2606:4700:3038:0:f1f0:3da1:2768:ca09]:80#官方优选IPv6 8 | [2606:4700:3037:0:d5d5:b929:61b7:f322]:80#官方优选IPv6 9 | [2606:4700:3036::71:65db:29e5]:80#官方优选IPv6 10 | [2606:4700:3036:d295:9da4:d2ed:ea7b:bc3b]:80#官方优选IPv6 11 | -------------------------------------------------------------------------------- /socks5Data: -------------------------------------------------------------------------------- 1 | socks5://173.249.7.118:2276#ZZ 2 | socks5://46.10.229.243:7777#ZZ 3 | socks5://163.53.204.178:9813#ZZ 4 | socks5://51.38.50.249:9224#ZZ 5 | socks5://149.129.135.57:6666#ZZ 6 | socks5://82.165.198.169:1245#ZZ 7 | socks5://87.117.11.57:1080#ZZ 8 | socks5://81.21.82.116:1080#ZZ 9 | socks5://162.144.103.99:2654#ZZ 10 | socks5://46.0.203.140:4890#ZZ 11 | socks5://72.206.181.123:4145#US 12 | socks5://184.178.172.14:4145#US 13 | socks5://192.252.220.92:17328#US 14 | socks5://184.181.217.206:4145#US 15 | socks5://192.111.129.145:16894#CA 16 | socks5://192.111.139.163:19404#CA 17 | socks5://72.210.252.134:46164#US 18 | socks5://72.195.34.35:27360#US 19 | socks5://98.162.25.4:31654#US 20 | socks5://98.162.25.29:31679#US 21 | socks5://174.77.111.198:49547#US 22 | socks5://98.178.72.21:10919#US 23 | socks5://72.195.34.60:27391#US 24 | socks5://184.178.172.28:15294#US 25 | socks5://184.178.172.25:15291#US 26 | socks5://184.178.172.18:15280#US 27 | socks5://198.8.94.170:4145#CA 28 | socks5://98.181.137.83:4145#US 29 | socks5://184.170.248.5:4145#US 30 | socks5://199.58.184.97:4145#US 31 | socks5://199.116.114.11:4145#US 32 | socks5://199.102.106.94:4145#US 33 | socks5://70.166.167.38:57728#US 34 | socks5://184.178.172.13:15311#US 35 | socks5://72.206.181.105:64935#US 36 | socks5://31.170.22.127:1080#LV 37 | socks5://23.19.244.109:1080#US 38 | socks5://35.229.105.131:11080#US 39 | socks5://178.62.7.98:44549#RU 40 | socks5://45.91.92.45:28220#KR 41 | socks5://49.13.73.161:2025#DE 42 | socks5://174.138.44.248:24737#US 43 | socks5://178.251.162.20:40109#LU 44 | socks5://51.161.131.84:29192#AU 45 | socks5://45.91.92.45:19011#RU 46 | socks5://148.72.214.53:43930#SG 47 | socks5://212.83.138.60:39482#FR 48 | socks5://162.214.75.237:23654#US 49 | -------------------------------------------------------------------------------- /sub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmliu/WorkerVless2sub/ba08748d123d89d1ac8866d5f3c5008fad24da66/sub.png --------------------------------------------------------------------------------