├── _config.yml ├── script ├── my_gfwlist.txt ├── my_chinalist.txt └── main.py ├── .github ├── dependabot.yml └── workflows │ ├── codeql.yml │ └── update-chinalist.yml └── README.md /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /script/my_gfwlist.txt: -------------------------------------------------------------------------------- 1 | google.com 2 | googleapis.com 3 | gstatic.com -------------------------------------------------------------------------------- /script/my_chinalist.txt: -------------------------------------------------------------------------------- 1 | chei.com.cn 2 | chsi.com.cn 3 | edu.cn 4 | gov.cn 5 | 58cdn.com.cn 6 | kcna.kp 7 | cloudfront.net 8 | cipunited.com 9 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | target-branch: "main" 11 | schedule: 12 | interval: "daily" 13 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | schedule: 9 | - cron: "34 10 * * 1" 10 | 11 | jobs: 12 | analyze: 13 | name: Analyze 14 | runs-on: ubuntu-latest 15 | permissions: 16 | actions: read 17 | contents: read 18 | security-events: write 19 | 20 | strategy: 21 | fail-fast: false 22 | matrix: 23 | language: [ python ] 24 | 25 | steps: 26 | - name: Checkout 27 | uses: actions/checkout@v4 28 | 29 | - name: Initialize CodeQL 30 | uses: github/codeql-action/init@v3 31 | with: 32 | languages: ${{ matrix.language }} 33 | queries: +security-and-quality 34 | 35 | - name: Autobuild 36 | uses: github/codeql-action/autobuild@v3 37 | 38 | - name: Perform CodeQL Analysis 39 | uses: github/codeql-action/analyze@v3 40 | with: 41 | category: "/language:${{ matrix.language }}" 42 | -------------------------------------------------------------------------------- /.github/workflows/update-chinalist.yml: -------------------------------------------------------------------------------- 1 | name: Update chinalist 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | schedule: 7 | - cron: "0 0 * * *" 8 | 9 | jobs: 10 | update: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Get current time 15 | uses: srfrnk/current-time@master 16 | id: current-time 17 | with: 18 | format: "YYYY-MM-DD HH:mm" 19 | 20 | - name: Checkout 21 | uses: actions/checkout@v4 22 | 23 | - name: Set up PyPy 3.9 24 | uses: actions/setup-python@v5 25 | with: 26 | python-version: pypy-3.9 27 | 28 | - name: Update 29 | run: | 30 | python script/main.py 31 | 32 | - name: Push 33 | uses: JamesIves/github-pages-deploy-action@v4 34 | with: 35 | branch: main 36 | folder: . 37 | git-config-name: github-actions[bot] 38 | git-config-email: 41898282+github-actions[bot]@users.noreply.github.com 39 | commit-message: updated ${{ steps.current-time.outputs.formattedTime }} UTC 40 | 41 | - name: Purge jsDelivr cache 42 | run: | 43 | wget -q -O - https://purge.jsdelivr.net/gh/Rongronggg9/chinalist@latest/chinalist_smart.txt 44 | wget -q -O - https://purge.jsdelivr.net/gh/Rongronggg9/chinalist@latest/chinalist_omega.txt 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # chinalist 2 | [![GitHub last commit](https://img.shields.io/github/last-commit/Rongronggg9/chinalist?label=updated)](https://github.com/Rongronggg9/chinalist/commits) 3 | [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/Rongronggg9/chinalist/update-chinalist.yml)](https://github.com/Rongronggg9/chinalist/actions/workflows/update-chinalist.yml) 4 | 5 | ## Usage 6 | ### [SwitchyOmega](https://github.com/FelisCatus/SwitchyOmega) 7 | 1. Open SwitchyOmega settings 8 | 1. Go to an auto-switching profile configuration page (create one if needed) 9 | 1. Set `Rule List Format` to `AutoProxy` 10 | 1. Fill in `Rule List URL` with the URL of [chinalist_omega.txt](https://raw.githubusercontent.com/Rongronggg9/chinalist/main/chinalist_omega.txt) 11 | (or you may use [jsDelivr CDN](https://cdn.jsdelivr.net/gh/Rongronggg9/chinalist@latest/chinalist_omega.txt)) 12 | 1. Set `Rule list rules` to `DIRECT`, `Default` to a proxy server profile 13 | 1. Click on `Download Profile Now` and then click on `Apply changes` 14 | 1. Switch to this auto-switching profile 15 | 16 | ### [SmartProxy](https://github.com/salarcode/SmartProxy) 17 | 1. Open SmartProxy settings 18 | 1. Go to `Proxy Rules Subscriptions` 19 | 1. Click on `Subscribe to a rules list` 20 | 1. Fill in `Url` with the URL of [chinalist_smart.txt](https://raw.githubusercontent.com/Rongronggg9/chinalist/main/chinalist_smart.txt) 21 | (or you may use [jsDelivr CDN](https://cdn.jsdelivr.net/gh/Rongronggg9/chinalist@latest/chinalist_smart.txt)) 22 | 1. Set `Obfuscation` to `None` 23 | 1. Set `Format` to `AutoProxy/GFWList` 24 | 1. Leave `Username` and `Password` blank 25 | 1. Save 26 | 1. Save 27 | 1. Go to `Proxy Rules` 28 | 1. Click on `Add Rule` 29 | 1. Set `Rule Type` to `Host regex` 30 | 1. Leave `Rule Source Domain` blank 31 | 1. Fill `Url Regex` with `.*` 32 | 1. Set `Proxy Server` to `[General]`, `Action` to `Apply proxy` 33 | 1. Save 34 | 1. Save 35 | 1. Switch to Smart Proxy mode 36 | 37 | 38 | ## Thanks 39 | [pexcn/daily](https://github.com/pexcn/daily) -------------------------------------------------------------------------------- /script/main.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | from typing import NoReturn 3 | 4 | import logging 5 | from datetime import datetime 6 | from functools import reduce 7 | from urllib.request import urlopen 8 | from http.client import HTTPResponse 9 | 10 | DAILY_CHINALIST_URL = 'https://raw.githubusercontent.com/pexcn/daily/gh-pages/chinalist/chinalist.txt' 11 | DAILY_GFWLIST_URL = 'https://raw.githubusercontent.com/pexcn/daily/gh-pages/gfwlist/gfwlist.txt' 12 | MY_CHINALIST_PATH = 'script/my_chinalist.txt' 13 | MY_GFWLIST_PATH = 'script/my_gfwlist.txt' 14 | 15 | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') 16 | 17 | 18 | def get_online_list(url: str) -> list[str]: 19 | logging.info(f'Fetching online list... ({url})') 20 | try: 21 | response: HTTPResponse = urlopen(url, timeout=10) 22 | online_list = response.read().decode('utf-8').split() 23 | logging.info(f'Fetched {len(online_list)} URLs.') 24 | return online_list 25 | except ConnectionError: 26 | logging.critical('Connection error.') 27 | exit(1) 28 | 29 | 30 | def get_local_list(path: str) -> list[str]: 31 | logging.info(f'Reading local list... ({path})') 32 | try: 33 | with open(path) as file: 34 | local_list = file.read().split() 35 | except FileNotFoundError: 36 | local_list = [] 37 | logging.info(f'Read {len(local_list)} URLs from {path}.') 38 | return local_list 39 | 40 | 41 | def joint_list(*lists: list[str]) -> list[str]: 42 | logging.info('Jointing lists...') 43 | jointed_list = set() 44 | jointed_list.update(*lists) 45 | # noinspection PyTypeChecker 46 | logging.info(f'Got {reduce(lambda a, b: f"{a}+{b}", [len(l) for l in lists])}={sum(len(l) for l in lists)} URLs. ' 47 | f'After jointing, remain {len(jointed_list)} URLs.') 48 | return sorted(jointed_list) 49 | 50 | 51 | def filter_list(ori_list: list[str], filter_out_list: list[str]) -> list[str]: 52 | logging.info('Filtering list...') 53 | f_list = set(filter_out_list) 54 | df_list = set('.' + f for f in f_list) 55 | filtered_list = list( 56 | filter( 57 | lambda o: ( 58 | o not in f_list 59 | and 60 | ( 61 | o.count('.') <= 1 # TLD/2LD, shortcut 62 | or 63 | all(not o.endswith(d) for d in df_list) # match subdomain 64 | ) 65 | ), 66 | ori_list 67 | ) 68 | ) 69 | logging.info(f'Got {len(ori_list)} URLs to be filtered, {len(filter_out_list)} URLs to be filtered out. ' 70 | f'After filtering, remain {len(filtered_list)} URLs.') 71 | return filtered_list 72 | 73 | 74 | def update_txt(new_list: list[str], path: str) -> NoReturn: 75 | logging.info(f'Updating {path}...') 76 | with open(path, 'w') as file: 77 | file.write('\n'.join(new_list)) 78 | 79 | 80 | def main(): 81 | old_list = get_local_list('chinalist_plain.txt') 82 | 83 | daily_chinalist = get_online_list(DAILY_CHINALIST_URL) 84 | daily_gfwlist = get_online_list(DAILY_GFWLIST_URL) 85 | my_gfwlist = get_local_list(MY_GFWLIST_PATH) 86 | filtered_list = filter_list(daily_chinalist, joint_list(daily_gfwlist, my_gfwlist)) 87 | 88 | my_list = get_local_list(MY_CHINALIST_PATH) 89 | jointed_list = joint_list(filtered_list, my_list) 90 | 91 | if jointed_list == old_list: 92 | logging.info('No update.') 93 | return 94 | 95 | info = f'[AutoProxy 0.2.9]\n! Updated: {datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")}' 96 | omega_list = [info, '! This chinalist only works with SwitchyOmega.', 97 | '! For other versions, please check https://github.com/Rongronggg9/chinalist'] 98 | smart_list = [info, '! This chinalist is expected to be used on SmartProxy.', 99 | '! For other versions, please check https://github.com/Rongronggg9/chinalist'] 100 | for url in jointed_list: 101 | omega_list.append(f'||{url}') 102 | smart_list.append(f'@@||{url}') 103 | 104 | update_txt(omega_list, 'chinalist_omega.txt') 105 | update_txt(smart_list, 'chinalist_smart.txt') 106 | update_txt(jointed_list, 'chinalist_plain.txt') 107 | 108 | logging.info('Update finished.') 109 | 110 | 111 | if __name__ == '__main__': 112 | main() 113 | --------------------------------------------------------------------------------