Repository: cnwikee/CheckTMDB Branch: main Commit: bebc763f46c6 Files: 9 Total size: 36.0 KB Directory structure: gitextract_5rocd69t/ ├── .github/ │ └── workflows/ │ └── main.yml ├── LICENSE ├── README.md ├── README_template.md ├── Tmdb_host_ipv4 ├── Tmdb_host_ipv6 ├── check_tmdb_github.py ├── check_tmdb_github_dnschecked.py └── requirements.txt ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/main.yml ================================================ name: Check TMDB IP on: workflow_dispatch: schedule: - cron: '0 10,22 * * *' # 每天 10:00 和 22:00 执行 permissions: contents: write # 确保有写入权限 jobs: build: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v2 - name: Set up Python uses: actions/setup-python@v2 with: python-version: '3.10' - name: Install dependencies run: | sudo apt update sudo apt install --only-upgrade python3-pip if [ -f requirements.txt ]; then sudo pip install -r requirements.txt; fi - name: Run Python script run: | sudo python check_tmdb_github_dnschecked.py - name: 提交更改 run: | git config --global user.name 'GitHub Action' git config --global user.email 'action@github.com' git add README.md Tmdb_host_ipv4 Tmdb_host_ipv6 git commit -m "Update TMDB IP [action]" || echo "No changes to commit" continue-on-error: true - name: Push changes env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: git push origin main ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2024 cnwikee Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # CheckTMDB 每日自动更新TMDB,themoviedb、thetvdb 国内可正常连接IP,解决DNS污染,供tinyMediaManager(TMM削刮器)、Kodi的刮削器、群晖VideoStation的海报墙、Plex Server的元数据代理、Emby Server元数据下载器、Infuse、Nplayer等正常削刮影片信息。 ## 一、前景 自从我早两年使用了黑群NAS以后,下了好多的电影电视剧,发现电视端无法生成正常的海报墙。查找资料得知应该是 themoviedb.org、tmdb.org 无法正常访问,因为DNS受到了污染无法正确解析到TMDB的IP,故依葫芦画瓢写了一个python脚本,每日定时通过[dnschecker](https://dnschecker.org/)查询出最佳IP,并自动同步到路由器外挂hosts,可正常削刮。 **本项目无需安装任何程序** 通过修改本地、路由器 hosts 文件,即可正常削刮影片信息。 ## 文件地址 - TMDB IPv4 hosts:`https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv4` ,[链接](https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv4) - TMDB IPv6 hosts:`https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv6` ,[链接](https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv6) ## 二、使用方法 ### 2.1 手动方式 #### 2.1.1 IPv4地址复制下面的内容 ```bash # Tmdb Hosts Start 18.160.10.119 tmdb.org 3.170.19.81 api.tmdb.org 3.170.42.125 files.tmdb.org 3.171.38.81 themoviedb.org 3.170.19.106 api.themoviedb.org 3.171.38.81 www.themoviedb.org 3.170.3.12 auth.themoviedb.org 185.93.1.249 image.tmdb.org 169.150.236.107 images.tmdb.org 98.82.155.134 imdb.com 18.67.70.32 www.imdb.com 98.82.155.134 secure.imdb.com 18.67.70.32 s.media-imdb.com 98.82.158.179 us.dd.imdb.com 18.67.70.32 www.imdb.to 98.82.155.134 origin-www.imdb.com 23.207.202.24 ia.media-imdb.com 3.171.75.86 thetvdb.com 3.170.35.80 api.thetvdb.com 151.101.1.16 ia.media-imdb.com 151.101.1.16 f.media-amazon.com 18.67.76.79 imdb-video.media-imdb.com 148.113.196.166 webservice.fanart.tv 172.67.74.146 images.fanart.tv 158.69.209.125 assets.fanart.tv 172.67.74.146 fanart.tv 104.20.14.80 api.trakt.tv 104.20.14.80 trakt.tv # Update time: 2026-04-24T19:13:55+08:00 # IPv4 Update url: https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv4 # IPv6 Update url: https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv6 # Star me: https://github.com/cnwikee/CheckTMDB # Tmdb Hosts End ``` 该内容会自动定时更新, 数据更新时间:2026-04-24T19:13:55+08:00 #### 2.1.2 IPv6地址复制下面的内容 ```bash # Tmdb Hosts Start 2600:9000:250a:8c00:10:db24:6940:93a1 tmdb.org 2600:9000:286d:2e00:10:fb02:4000:93a1 api.tmdb.org 2600:9000:2870:ca00:5:da10:7440:93a1 files.tmdb.org 2600:9000:28a0:e00:e:5373:440:93a1 themoviedb.org 2600:9000:286d:3000:c:174a:c400:93a1 api.themoviedb.org 2600:9000:28a0:9200:e:5373:440:93a1 www.themoviedb.org 2600:9000:286a:b000:16:e4a1:eb00:93a1 auth.themoviedb.org 2400:52e0:1a00::1029:1 image.tmdb.org 2400:52e0:1a00::1233:1 images.tmdb.org 2a04:4e42:400::272 ia.media-imdb.com 2a04:4e42:400::272 ia.media-imdb.com 2a04:4e42:400::272 f.media-amazon.com 2606:4700:20::681a:d7e images.fanart.tv 2606:4700:20::681a:d7e fanart.tv 2606:4700:10::6814:e50 api.trakt.tv 2606:4700:10::6814:e50 trakt.tv # Update time: 2026-04-24T19:13:55+08:00 # IPv4 Update url: https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv4 # IPv6 Update url: https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv6 # Star me: https://github.com/cnwikee/CheckTMDB # Tmdb Hosts End ``` 该内容会自动定时更新, 数据更新时间:2026-04-24T19:13:55+08:00 > [!NOTE] > 由于项目搭建在Github Aciton,延时数据获取于Github Action 虚拟主机网络环境,请自行测试可用性,建议使用本地网络环境自动设置。 #### 2.1.3 修改 hosts 文件 hosts 文件在每个系统的位置不一,详情如下: - Windows 系统:`C:\Windows\System32\drivers\etc\hosts` - Linux 系统:`/etc/hosts` - Mac(苹果电脑)系统:`/etc/hosts` - Android(安卓)系统:`/system/etc/hosts` - iPhone(iOS)系统:`/etc/hosts` 修改方法,把第一步的内容复制到文本末尾: 1. Windows 使用记事本。 2. Linux、Mac 使用 Root 权限:`sudo vi /etc/hosts`。 3. iPhone、iPad 须越狱、Android 必须要 root。 #### 2.1.4 激活生效 大部分情况下是直接生效,如未生效可尝试下面的办法,刷新 DNS: 1. Windows:在 CMD 窗口输入:`ipconfig /flushdns` 2. Linux 命令:`sudo nscd restart`,如报错则须安装:`sudo apt install nscd` 或 `sudo /etc/init.d/nscd restart` 3. Mac 命令:`sudo killall -HUP mDNSResponder` **Tips:** 上述方法无效可以尝试重启机器。 ### 2.2 自动方式 #### 2.2.1 安装 SwitchHosts GitHub 发行版:https://github.com/oldj/SwitchHosts/releases/latest #### 2.2.2 添加 hosts 点击左上角“+”,并进行以下配置: - Hosts 类型:`远程` - Hosts 标题:任意 - URL - IPv4:`https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv4` - IPv6:`https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv6` - 自动刷新:`1 小时` #### 2.2.3 启用 hosts 在左侧边栏启用 hosts,首次使用时软件会自动获取内容。如果无法连接到 GitHub,可以尝试用同样的方法添加 [GitHub520](https://github.com/521xueweihan/GitHub520) hosts。 ## 三、参数说明 1. 直接执行`check_tmdb_github.py`脚本,同时查询IPv4及IPv6地址,目录生成`Tmdb_host_ipv4`文件,及`Tmdb_host_ipv6`文件; 2. 带`-G` 参数执行:`check_tmdb_github.py -G`,会在`Tmdb_host_ipv4`文件,及`Tmdb_host_ipv6`文件中追加 Github IPv4 地址; ## 其他 - [x] 自学薄弱编程基础,大部分代码基于AI辅助生成,此项目过程中,主要人为解决的是:通过 [dnschecker](https://dnschecker.org/) 提交时,通过计算出正确的udp参数,获取正确的csrftoken,携带正确的referer提交! - [x] README.md 及 部分代码 参考[GitHub520](https://github.com/521xueweihan/GitHub520) - [x] * 本项目仅在本机测试通过,如有问题欢迎提 [issues](https://github.com/cnwikee/CheckTMDB/issues/new) ================================================ FILE: README_template.md ================================================ # CheckTMDB 每日自动更新TMDB,themoviedb、thetvdb 国内可正常连接IP,解决DNS污染,供tinyMediaManager(TMM削刮器)、Kodi的刮削器、群晖VideoStation的海报墙、Plex Server的元数据代理、Emby Server元数据下载器、Infuse、Nplayer等正常削刮影片信息。 ## 一、前景 自从我早两年使用了黑群NAS以后,下了好多的电影电视剧,发现电视端无法生成正常的海报墙。查找资料得知应该是 themoviedb.org、tmdb.org 无法正常访问,因为DNS受到了污染无法正确解析到TMDB的IP,故依葫芦画瓢写了一个python脚本,每日定时通过[dnschecker](https://dnschecker.org/)查询出最佳IP,并自动同步到路由器外挂hosts,可正常削刮。 **本项目无需安装任何程序** 通过修改本地、路由器 hosts 文件,即可正常削刮影片信息。 ## 文件地址 - TMDB IPv4 hosts:`https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv4` ,[链接](https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv4) - TMDB IPv6 hosts:`https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv6` ,[链接](https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv6) ## 二、使用方法 ### 2.1 手动方式 #### 2.1.1 IPv4地址复制下面的内容 ```bash {ipv4_hosts_str} ``` 该内容会自动定时更新, 数据更新时间:{update_time} #### 2.1.2 IPv6地址复制下面的内容 ```bash {ipv6_hosts_str} ``` 该内容会自动定时更新, 数据更新时间:{update_time} > [!NOTE] > 由于项目搭建在Github Aciton,延时数据获取于Github Action 虚拟主机网络环境,请自行测试可用性,建议使用本地网络环境自动设置。 #### 2.1.3 修改 hosts 文件 hosts 文件在每个系统的位置不一,详情如下: - Windows 系统:`C:\Windows\System32\drivers\etc\hosts` - Linux 系统:`/etc/hosts` - Mac(苹果电脑)系统:`/etc/hosts` - Android(安卓)系统:`/system/etc/hosts` - iPhone(iOS)系统:`/etc/hosts` 修改方法,把第一步的内容复制到文本末尾: 1. Windows 使用记事本。 2. Linux、Mac 使用 Root 权限:`sudo vi /etc/hosts`。 3. iPhone、iPad 须越狱、Android 必须要 root。 #### 2.1.4 激活生效 大部分情况下是直接生效,如未生效可尝试下面的办法,刷新 DNS: 1. Windows:在 CMD 窗口输入:`ipconfig /flushdns` 2. Linux 命令:`sudo nscd restart`,如报错则须安装:`sudo apt install nscd` 或 `sudo /etc/init.d/nscd restart` 3. Mac 命令:`sudo killall -HUP mDNSResponder` **Tips:** 上述方法无效可以尝试重启机器。 ### 2.2 自动方式 #### 2.2.1 安装 SwitchHosts GitHub 发行版:https://github.com/oldj/SwitchHosts/releases/latest #### 2.2.2 添加 hosts 点击左上角“+”,并进行以下配置: - Hosts 类型:`远程` - Hosts 标题:任意 - URL - IPv4:`https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv4` - IPv6:`https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv6` - 自动刷新:`1 小时` #### 2.2.3 启用 hosts 在左侧边栏启用 hosts,首次使用时软件会自动获取内容。如果无法连接到 GitHub,可以尝试用同样的方法添加 [GitHub520](https://github.com/521xueweihan/GitHub520) hosts。 ## 三、参数说明 1. 直接执行`check_tmdb_github.py`脚本,同时查询IPv4及IPv6地址,目录生成`Tmdb_host_ipv4`文件,及`Tmdb_host_ipv6`文件; 2. 带`-G` 参数执行:`check_tmdb_github.py -G`,会在`Tmdb_host_ipv4`文件,及`Tmdb_host_ipv6`文件中追加 Github IPv4 地址; ## 其他 - [x] 自学薄弱编程基础,大部分代码基于AI辅助生成,此项目过程中,主要人为解决的是:通过 [dnschecker](https://dnschecker.org/) 提交时,通过计算出正确的udp参数,获取正确的csrftoken,携带正确的referer提交! - [x] README.md 及 部分代码 参考[GitHub520](https://github.com/521xueweihan/GitHub520) - [x] * 本项目仅在本机测试通过,如有问题欢迎提 [issues](https://github.com/cnwikee/CheckTMDB/issues/new) ================================================ FILE: Tmdb_host_ipv4 ================================================ # Tmdb Hosts Start 18.160.10.119 tmdb.org 3.170.19.81 api.tmdb.org 3.170.42.125 files.tmdb.org 3.171.38.81 themoviedb.org 3.170.19.106 api.themoviedb.org 3.171.38.81 www.themoviedb.org 3.170.3.12 auth.themoviedb.org 185.93.1.249 image.tmdb.org 169.150.236.107 images.tmdb.org 98.82.155.134 imdb.com 18.67.70.32 www.imdb.com 98.82.155.134 secure.imdb.com 18.67.70.32 s.media-imdb.com 98.82.158.179 us.dd.imdb.com 18.67.70.32 www.imdb.to 98.82.155.134 origin-www.imdb.com 23.207.202.24 ia.media-imdb.com 3.171.75.86 thetvdb.com 3.170.35.80 api.thetvdb.com 151.101.1.16 ia.media-imdb.com 151.101.1.16 f.media-amazon.com 18.67.76.79 imdb-video.media-imdb.com 148.113.196.166 webservice.fanart.tv 172.67.74.146 images.fanart.tv 158.69.209.125 assets.fanart.tv 172.67.74.146 fanart.tv 104.20.14.80 api.trakt.tv 104.20.14.80 trakt.tv # Update time: 2026-04-24T19:13:55+08:00 # IPv4 Update url: https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv4 # IPv6 Update url: https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv6 # Star me: https://github.com/cnwikee/CheckTMDB # Tmdb Hosts End ================================================ FILE: Tmdb_host_ipv6 ================================================ # Tmdb Hosts Start 2600:9000:250a:8c00:10:db24:6940:93a1 tmdb.org 2600:9000:286d:2e00:10:fb02:4000:93a1 api.tmdb.org 2600:9000:2870:ca00:5:da10:7440:93a1 files.tmdb.org 2600:9000:28a0:e00:e:5373:440:93a1 themoviedb.org 2600:9000:286d:3000:c:174a:c400:93a1 api.themoviedb.org 2600:9000:28a0:9200:e:5373:440:93a1 www.themoviedb.org 2600:9000:286a:b000:16:e4a1:eb00:93a1 auth.themoviedb.org 2400:52e0:1a00::1029:1 image.tmdb.org 2400:52e0:1a00::1233:1 images.tmdb.org 2a04:4e42:400::272 ia.media-imdb.com 2a04:4e42:400::272 ia.media-imdb.com 2a04:4e42:400::272 f.media-amazon.com 2606:4700:20::681a:d7e images.fanart.tv 2606:4700:20::681a:d7e fanart.tv 2606:4700:10::6814:e50 api.trakt.tv 2606:4700:10::6814:e50 trakt.tv # Update time: 2026-04-24T19:13:55+08:00 # IPv4 Update url: https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv4 # IPv6 Update url: https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv6 # Star me: https://github.com/cnwikee/CheckTMDB # Tmdb Hosts End ================================================ FILE: check_tmdb_github.py ================================================ import requests from time import sleep import random import time import os import sys from datetime import datetime, timezone, timedelta from retry import retry import socket country_code = 'jp' #节点 DOMAINS = [ 'tmdb.org', 'api.tmdb.org', 'files.tmdb.org', 'themoviedb.org', 'api.themoviedb.org', 'www.themoviedb.org', 'auth.themoviedb.org', 'image.tmdb.org', 'images.tmdb.org', 'imdb.com', 'www.imdb.com', 'secure.imdb.com', 's.media-imdb.com', 'us.dd.imdb.com', 'www.imdb.to', 'origin-www.imdb.com', 'ia.media-imdb.com', 'thetvdb.com', 'api.thetvdb.com', 'ia.media-imdb.com', 'f.media-amazon.com', 'imdb-video.media-imdb.com' ] Tmdb_Host_TEMPLATE = """# Tmdb Hosts Start {content} # Update time: {update_time} # IPv4 Update url: https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv4 # IPv6 Update url: https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv6 # Star me: https://github.com/cnwikee/CheckTMDB # Tmdb Hosts End\n""" def write_file(ipv4_hosts_content: str, ipv6_hosts_content: str, update_time: str) -> bool: output_doc_file_path = os.path.join(os.path.dirname(__file__), "README.md") template_path = os.path.join(os.path.dirname(__file__), "README_template.md") if os.path.exists(output_doc_file_path): with open(output_doc_file_path, "r", encoding='utf-8') as old_readme_md: old_readme_md_content = old_readme_md.read() if old_readme_md_content: old_ipv4_block = old_readme_md_content.split("```bash")[1].split("```")[0].strip() old_ipv4_hosts = old_ipv4_block.split("# Update time:")[0].strip() old_ipv6_block = old_readme_md_content.split("```bash")[2].split("```")[0].strip() old_ipv6_hosts = old_ipv6_block.split("# Update time:")[0].strip() if ipv4_hosts_content != "": new_ipv4_hosts = ipv4_hosts_content.split("# Update time:")[0].strip() if old_ipv4_hosts == new_ipv4_hosts: print("ipv4 host not change") w_ipv4_block = old_ipv4_block else: w_ipv4_block = ipv4_hosts_content write_host_file(ipv4_hosts_content, 'ipv4') else: print("ipv4_hosts_content is null") w_ipv4_block = old_ipv4_block if ipv6_hosts_content != "": new_ipv6_hosts = ipv6_hosts_content.split("# Update time:")[0].strip() if old_ipv6_hosts == new_ipv6_hosts: print("ipv6 host not change") w_ipv6_block = old_ipv6_block else: w_ipv6_block = ipv6_hosts_content write_host_file(ipv6_hosts_content, 'ipv6') else: print("ipv6_hosts_content is null") w_ipv6_block = old_ipv6_block with open(template_path, "r", encoding='utf-8') as temp_fb: template_str = temp_fb.read() hosts_content = template_str.format(ipv4_hosts_str=w_ipv4_block, ipv6_hosts_str=w_ipv6_block, update_time=update_time) with open(output_doc_file_path, "w", encoding='utf-8') as output_fb: output_fb.write(hosts_content) return True return False def write_host_file(hosts_content: str, filename: str) -> None: output_file_path = os.path.join(os.path.dirname(__file__), "Tmdb_host_" + filename) if len(sys.argv) >= 2 and sys.argv[1].upper() == '-G': print("\n~追加Github ip~") hosts_content = hosts_content + "\n" + (get_github_hosts() or "") with open(output_file_path, "w", encoding='utf-8') as output_fb: output_fb.write(hosts_content) print("\n~最新TMDB" + filename + "地址已更新~") def get_github_hosts() -> None: github_hosts_urls = [ "https://hosts.gitcdn.top/hosts.txt", "https://raw.githubusercontent.com/521xueweihan/GitHub520/refs/heads/main/hosts", "https://gitlab.com/ineo6/hosts/-/raw/master/next-hosts", "https://raw.githubusercontent.com/ittuann/GitHub-IP-hosts/refs/heads/main/hosts_single" ] all_failed = True for url in github_hosts_urls: try: response = requests.get(url) if response.status_code == 200: github_hosts = response.text all_failed = False break else: print(f"\n从 {url} 获取GitHub hosts失败: HTTP {response.status_code}") except Exception as e: print(f"\n从 {url} 获取GitHub hosts时发生错误: {str(e)}") if all_failed: print("\n获取GitHub hosts失败: 所有Url项目失败!") return else: return github_hosts def is_ci_environment(): ci_environment_vars = { 'GITHUB_ACTIONS': 'true', 'TRAVIS': 'true', 'CIRCLECI': 'true' } for env_var, expected_value in ci_environment_vars.items(): env_value = os.getenv(env_var) if env_value is not None and str(env_value).lower() == expected_value.lower(): return True return False @retry(tries=3) def get_csrf_token(udp): """获取CSRF Token""" try: url = f'https://dnschecker.org/ajax_files/gen_csrf.php?udp={udp}' headers = { 'referer': 'https://dnschecker.org/country/{country_code}/','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0' } response = requests.get(url, headers=headers) if response.status_code == 200: csrf = response.json().get('csrf') print(f"获取到的CSRF Token: {csrf}") return csrf else: print(f"获取CSRF Token失败,HTTP状态码: {response.status_code}") return None except Exception as e: print(f"获取CSRF Token时发生错误: {str(e)}") return None @retry(tries=3) def get_domain_ips(domain, csrf_token, udp, argument): url = f'https://dnschecker.org/ajax_files/api/220/{argument}/{domain}?dns_key=country&dns_value={country_code}&v=0.36&cd_flag=1&upd={udp}' headers = {'csrftoken': csrf_token, 'referer':f'https://dnschecker.org/country/{country_code}/','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0'} try: response = requests.get(url, headers=headers) if response.status_code == 200: data = response.json() if 'result' in data and 'ips' in data['result']: ips_str = data['result']['ips'] if '
' in ips_str: return [ip.strip() for ip in ips_str.split('
') if ip.strip()] else: return [ips_str.strip()] if ips_str.strip() else [] else: print(f"获取 {domain} 的IP列表失败:返回数据格式不正确") return [] else: print(f"获取 {domain} 的IP列表失败,HTTP状态码: {response.status_code}") return [] except Exception as e: print(f"获取 {domain} 的IP列表时发生错误: {str(e)}") return [] def ping_ip(ip, port=80): print(f"使用TCP连接测试IP地址的延迟(毫秒)") try: print(f"\n开始 ping {ip}...") start_time = time.time() with socket.create_connection((ip, port), timeout=2) as sock: latency = (time.time() - start_time) * 1000 # 转换为毫秒 print(f"IP: {ip} 的平均延迟: {latency}ms") return latency except Exception as e: print(f"Ping {ip} 时发生错误: {str(e)}") return float('inf') def find_fastest_ip(ips): """找出延迟最低的IP地址""" if not ips: return None fastest_ip = None min_latency = float('inf') ip_latencies = [] # 存储所有IP及其延迟 for ip in ips: ip = ip.strip() if not ip: continue print(f"正在测试 IP: {ip}") latency = ping_ip(ip) ip_latencies.append((ip, latency)) print(f"IP: {ip} 延迟: {latency}ms") if latency < min_latency: min_latency = latency fastest_ip = ip sleep(0.5) print("\n所有IP延迟情况:") for ip, latency in ip_latencies: print(f"IP: {ip} - 延迟: {latency}ms") if fastest_ip: print(f"\n最快的IP是: {fastest_ip},延迟: {min_latency}ms") return fastest_ip def main(): print("开始检测TMDB相关域名的最快IP...") udp = random.random() * 1000 + (int(time.time() * 1000) % 1000) # 获取CSRF Token csrf_token = get_csrf_token(udp) if not csrf_token: print("无法获取CSRF Token,程序退出") sys.exit(1) ipv4_ips, ipv6_ips, ipv4_results, ipv6_results = [], [], [], [] for domain in DOMAINS: print(f"\n正在处理域名: {domain}") ipv4_ips = get_domain_ips(domain, csrf_token, udp, "A") ipv6_ips = get_domain_ips(domain, csrf_token, udp, "AAAA") if not ipv4_ips and not ipv6_ips: print(f"无法获取 {domain} 的IP列表,跳过该域名") continue # 处理 IPv4 地址 if ipv4_ips: fastest_ipv4 = find_fastest_ip(ipv4_ips) if fastest_ipv4: ipv4_results.append([fastest_ipv4, domain]) print(f"域名 {domain} 的最快IPv4是: {fastest_ipv4}") else: ipv4_results.append([ipv4_ips[0], domain]) # 处理 IPv6 地址 if ipv6_ips: fastest_ipv6 = find_fastest_ip(ipv6_ips) if fastest_ipv6: ipv6_results.append([fastest_ipv6, domain]) print(f"域名 {domain} 的最快IPv6是: {fastest_ipv6}") else: # 兜底:可能存在无法正确获取 fastest_ipv6 的情况,则将第一个IP赋值 ipv6_results.append([ipv6_ips[0], domain]) sleep(1) # 避免请求过于频繁 # 保存结果到文件 if not ipv4_results and not ipv6_results: print(f"程序出错:未获取任何domain及对应IP,请检查接口~") sys.exit(1) # 生成更新时间 update_time = datetime.now(timezone(timedelta(hours=8))).replace(microsecond=0).isoformat() ipv4_hosts_content = Tmdb_Host_TEMPLATE.format(content="\n".join(f"{ip:<27} {domain}" for ip, domain in ipv4_results), update_time=update_time) if ipv4_results else "" ipv6_hosts_content = Tmdb_Host_TEMPLATE.format(content="\n".join(f"{ip:<50} {domain}" for ip, domain in ipv6_results), update_time=update_time) if ipv6_results else "" write_file(ipv4_hosts_content, ipv6_hosts_content, update_time) if __name__ == "__main__": main() ================================================ FILE: check_tmdb_github_dnschecked.py ================================================ import requests from time import sleep import random import time import os import sys import re # 导入正则模块用于IP验证 from datetime import datetime, timezone, timedelta from retry import retry import socket DOMAINS = [ 'tmdb.org', 'api.tmdb.org', 'files.tmdb.org', 'themoviedb.org', 'api.themoviedb.org', 'www.themoviedb.org', 'auth.themoviedb.org', 'image.tmdb.org', 'images.tmdb.org', 'imdb.com', 'www.imdb.com', 'secure.imdb.com', 's.media-imdb.com', 'us.dd.imdb.com', 'www.imdb.to', 'origin-www.imdb.com', 'ia.media-imdb.com', 'thetvdb.com', 'api.thetvdb.com', 'ia.media-imdb.com', 'f.media-amazon.com', 'imdb-video.media-imdb.com', 'webservice.fanart.tv', 'images.fanart.tv', 'assets.fanart.tv', 'fanart.tv', 'api.trakt.tv', 'api-staging.trakt.tv', 'trakt.tv' ] Tmdb_Host_TEMPLATE = """# Tmdb Hosts Start {content} # Update time: {update_time} # IPv4 Update url: https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv4 # IPv6 Update url: https://raw.githubusercontent.com/cnwikee/CheckTMDB/refs/heads/main/Tmdb_host_ipv6 # Star me: https://github.com/cnwikee/CheckTMDB # Tmdb Hosts End\n""" def write_file(ipv4_hosts_content: str, ipv6_hosts_content: str, update_time: str) -> bool: output_doc_file_path = os.path.join(os.path.dirname(__file__), "README.md") template_path = os.path.join(os.path.dirname(__file__), "README_template.md") if os.path.exists(output_doc_file_path): with open(output_doc_file_path, "r", encoding='utf-8') as old_readme_md: old_readme_md_content = old_readme_md.read() if old_readme_md_content: old_ipv4_block = old_readme_md_content.split("```bash")[1].split("```")[0].strip() old_ipv4_hosts = old_ipv4_block.split("# Update time:")[0].strip() old_ipv6_block = old_readme_md_content.split("```bash")[2].split("```")[0].strip() old_ipv6_hosts = old_ipv6_block.split("# Update time:")[0].strip() if ipv4_hosts_content != "": new_ipv4_hosts = ipv4_hosts_content.split("# Update time:")[0].strip() if old_ipv4_hosts == new_ipv4_hosts: print("ipv4 host not change") w_ipv4_block = old_ipv4_block else: w_ipv4_block = ipv4_hosts_content write_host_file(ipv4_hosts_content, 'ipv4') else: print("ipv4_hosts_content is null") w_ipv4_block = old_ipv4_block if ipv6_hosts_content != "": new_ipv6_hosts = ipv6_hosts_content.split("# Update time:")[0].strip() if old_ipv6_hosts == new_ipv6_hosts: print("ipv6 host not change") w_ipv6_block = old_ipv6_block else: w_ipv6_block = ipv6_hosts_content write_host_file(ipv6_hosts_content, 'ipv6') else: print("ipv6_hosts_content is null") w_ipv6_block = old_ipv6_block with open(template_path, "r", encoding='utf-8') as temp_fb: template_str = temp_fb.read() hosts_content = template_str.format(ipv4_hosts_str=w_ipv4_block, ipv6_hosts_str=w_ipv6_block, update_time=update_time) with open(output_doc_file_path, "w", encoding='utf-8') as output_fb: output_fb.write(hosts_content) return True return False def validate_ip(ip): """ 验证IP是否为合法的IPv4或IPv6地址 :param ip: 待验证的IP字符串 :return: True(合法)/False(非法) """ # IPv4正则(严格验证:每个段0-255,无前置零(除0.0.0.0等合法场景)) ipv4_pattern = r'^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$' # IPv6正则(兼容压缩格式、本地链路地址、IPv4映射地址等所有合法格式) ipv6_pattern = r'^(?:(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,7}:|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:(?:(?::[0-9a-fA-F]{1,4}){1,6})|:(?:(?::[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(?::[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(?:ffff(?::0{1,4}){0,1}:){0,1}(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])|(?:[0-9a-fA-F]{1,4}:){1,4}:(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$' # 忽略大小写验证IPv6,优先验证IPv4 if re.match(ipv4_pattern, ip): return True elif re.match(ipv6_pattern, ip, re.IGNORECASE): return True else: return False def write_host_file(hosts_content: str, filename: str) -> None: output_file_path = os.path.join(os.path.dirname(__file__), "Tmdb_host_" + filename) if len(sys.argv) >= 2 and sys.argv[1].upper() == '-G': print("\n~追加Github ip~") hosts_content = hosts_content + "\n" + (get_github_hosts() or "") with open(output_file_path, "w", encoding='utf-8') as output_fb: output_fb.write(hosts_content) print("\n~最新TMDB" + filename + "地址已更新~") def get_github_hosts() -> None: github_hosts_urls = [ "https://hosts.gitcdn.top/hosts.txt", "https://raw.githubusercontent.com/521xueweihan/GitHub520/refs/heads/main/hosts", "https://gitlab.com/ineo6/hosts/-/raw/master/next-hosts", "https://raw.githubusercontent.com/ittuann/GitHub-IP-hosts/refs/heads/main/hosts_single" ] all_failed = True for url in github_hosts_urls: try: response = requests.get(url) if response.status_code == 200: github_hosts = response.text all_failed = False break else: print(f"\n从 {url} 获取GitHub hosts失败: HTTP {response.status_code}") except Exception as e: print(f"\n从 {url} 获取GitHub hosts时发生错误: {str(e)}") if all_failed: print("\n获取GitHub hosts失败: 所有Url项目失败!") return else: return github_hosts def is_ci_environment(): ci_environment_vars = { 'GITHUB_ACTIONS': 'true', 'TRAVIS': 'true', 'CIRCLECI': 'true' } for env_var, expected_value in ci_environment_vars.items(): env_value = os.getenv(env_var) if env_value is not None and str(env_value).lower() == expected_value.lower(): return True return False @retry(tries=3) def get_domain_ips(domain, record_type): """ 从Google DNS获取域名的A/AAAA记录IP列表 :param domain: 目标域名(如 tmdb.org) :param record_type: 记录类型(A/AAAA,或数字1/28) :return: 去重后的IP列表 """ all_ips = [] # 存储所有DNS服务器返回的IP print(f"正在从Google DNS获取 {domain} 的{record_type}记录...") url = f'https://dns.google/resolve' headers = { "accept": "*/*", "accept-encoding": "gzip, deflate, br, zstd", "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", "content-type": "application/json; charset=UTF-8", # 关键:指定JSON格式负载 "referer": f"https://dns.google/query?name={domain}&rr_type={record_type}&ecs=", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" } params = { 'name': domain, 'type': record_type } # 初始化IP列表(默认空列表,确保后续使用安全) ips_str = [] try: # 改用GET请求(Google DNS resolve接口标准用法) response = requests.get(url, headers=headers, params=params, timeout=10) response.raise_for_status() # 主动抛出HTTP错误(如4xx/5xx) # 解析JSON响应 data = response.json() if not isinstance(data, dict): print("返回数据不是字典格式,无法解析") return all_ips # 核心:提取Answer数组中的data字段(IP地址) answer_list = data.get("Answer", []) if not answer_list: print(f"未找到 {domain} 的{record_type}记录(Answer字段为空)") return all_ips # 遍历Answer数组,提取每个条目的data值(IP) for answer in answer_list: ip = answer.get("data") if not ip: # 过滤空值 continue # 验证IP格式合法性 if validate_ip(ip): all_ips.append(ip) print(f"提取到合法IP:{ip}") else: print(f"跳过非法IP格式:{ip}") except requests.exceptions.RequestException as e: # 捕获所有网络/请求异常 print(f"请求Google DNS失败:{e}") if hasattr(e, 'response') and e.response: print(f"响应内容:{e.response.text[:500]}") # 打印前500字符避免过长 except ValueError: # JSON解析失败 print(f"响应内容不是有效的JSON格式:{response.text[:500]}") time.sleep(1) # 去重并返回(保持列表格式) unique_ips = list(set(all_ips)) print(f"最终提取到 {domain} 的{record_type}记录IP(去重后):{unique_ips}") return unique_ips def ping_ip(ip, port=80): print(f"使用TCP连接测试IP地址的延迟(毫秒)") try: print(f"\n开始 ping {ip}...") start_time = time.time() with socket.create_connection((ip, port), timeout=2) as sock: latency = (time.time() - start_time) * 1000 # 转换为毫秒 print(f"IP: {ip} 的平均延迟: {latency}ms") return latency except Exception as e: print(f"Ping {ip} 时发生错误: {str(e)}") return float('inf') def find_fastest_ip(ips): """找出延迟最低的IP地址""" if not ips: return None fastest_ip = None min_latency = float('inf') ip_latencies = [] # 存储所有IP及其延迟 for ip in ips: ip = ip.strip() if not ip: continue print(f"正在测试 IP: {ip}") latency = ping_ip(ip) ip_latencies.append((ip, latency)) print(f"IP: {ip} 延迟: {latency}ms") if latency < min_latency: min_latency = latency fastest_ip = ip sleep(0.5) print("\n所有IP延迟情况:") for ip, latency in ip_latencies: print(f"IP: {ip} - 延迟: {latency}ms") if fastest_ip: print(f"\n最快的IP是: {fastest_ip},延迟: {min_latency}ms") return fastest_ip def main(): print("开始检测TMDB相关域名的最快IP...") ipv4_ips, ipv6_ips, ipv4_results, ipv6_results = [], [], [], [] for domain in DOMAINS: print(f"\n正在处理域名: {domain}") ipv4_ips = get_domain_ips(domain, "A") ipv6_ips = get_domain_ips(domain, "AAAA") if not ipv4_ips and not ipv6_ips: print(f"无法获取 {domain} 的IP列表,跳过该域名") continue # 处理 IPv4 地址 if ipv4_ips: fastest_ipv4 = find_fastest_ip(ipv4_ips) if fastest_ipv4: ipv4_results.append([fastest_ipv4, domain]) print(f"域名 {domain} 的最快IPv4是: {fastest_ipv4}") else: ipv4_results.append([ipv4_ips[0], domain]) # 处理 IPv6 地址 if ipv6_ips: fastest_ipv6 = find_fastest_ip(ipv6_ips) if fastest_ipv6: ipv6_results.append([fastest_ipv6, domain]) print(f"域名 {domain} 的最快IPv6是: {fastest_ipv6}") else: # 兜底:可能存在无法正确获取 fastest_ipv6 的情况,则将第一个IP赋值 ipv6_results.append([ipv6_ips[0], domain]) sleep(1) # 避免请求过于频繁 # 保存结果到文件 if not ipv4_results and not ipv6_results: print(f"程序出错:未获取任何domain及对应IP,请检查接口~") sys.exit(1) # 生成更新时间 update_time = datetime.now(timezone(timedelta(hours=8))).replace(microsecond=0).isoformat() ipv4_hosts_content = Tmdb_Host_TEMPLATE.format(content="\n".join(f"{ip:<27} {domain}" for ip, domain in ipv4_results), update_time=update_time) if ipv4_results else "" ipv6_hosts_content = Tmdb_Host_TEMPLATE.format(content="\n".join(f"{ip:<50} {domain}" for ip, domain in ipv6_results), update_time=update_time) if ipv6_results else "" write_file(ipv4_hosts_content, ipv6_hosts_content, update_time) if __name__ == "__main__": main() ================================================ FILE: requirements.txt ================================================ requests>=2.31.0 pythonping==1.1.4 retry==0.9.2 ping3==4.0.8