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 '<br />' in ips_str:
return [ip.strip() for ip in ips_str.split('<br />') 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
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
SYMBOL INDEX (18 symbols across 2 files) FILE: check_tmdb_github.py function write_file (line 46) | def write_file(ipv4_hosts_content: str, ipv6_hosts_content: str, update_... function write_host_file (line 95) | def write_host_file(hosts_content: str, filename: str) -> None: function get_github_hosts (line 104) | def get_github_hosts() -> None: function is_ci_environment (line 129) | def is_ci_environment(): function get_csrf_token (line 143) | def get_csrf_token(udp): function get_domain_ips (line 164) | def get_domain_ips(domain, csrf_token, udp, argument): function ping_ip (line 188) | def ping_ip(ip, port=80): function find_fastest_ip (line 201) | def find_fastest_ip(ips): function main (line 235) | def main(): FILE: check_tmdb_github_dnschecked.py function write_file (line 52) | def write_file(ipv4_hosts_content: str, ipv6_hosts_content: str, update_... function validate_ip (line 99) | def validate_ip(ip): function write_host_file (line 118) | def write_host_file(hosts_content: str, filename: str) -> None: function get_github_hosts (line 127) | def get_github_hosts() -> None: function is_ci_environment (line 152) | def is_ci_environment(): function get_domain_ips (line 165) | def get_domain_ips(domain, record_type): function ping_ip (line 237) | def ping_ip(ip, port=80): function find_fastest_ip (line 250) | def find_fastest_ip(ips): function main (line 284) | def main():
Condensed preview — 9 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (43K chars).
[
{
"path": ".github/workflows/main.yml",
"chars": 1143,
"preview": "name: Check TMDB IP\n\non:\n workflow_dispatch:\n schedule:\n - cron: '0 10,22 * * *' # 每天 10:00 和 22:00 执行\n\npermission"
},
{
"path": "LICENSE",
"chars": 1064,
"preview": "MIT License\n\nCopyright (c) 2024 cnwikee\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof"
},
{
"path": "README.md",
"chars": 5716,
"preview": "# CheckTMDB\n\n每日自动更新TMDB,themoviedb、thetvdb 国内可正常连接IP,解决DNS污染,供tinyMediaManager(TMM削刮器)、Kodi的刮削器、群晖VideoStation的海报墙、Plex "
},
{
"path": "README_template.md",
"chars": 2782,
"preview": "# CheckTMDB\n\n每日自动更新TMDB,themoviedb、thetvdb 国内可正常连接IP,解决DNS污染,供tinyMediaManager(TMM削刮器)、Kodi的刮削器、群晖VideoStation的海报墙、Plex "
},
{
"path": "Tmdb_host_ipv4",
"chars": 1552,
"preview": "# Tmdb Hosts Start\n18.160.10.119 tmdb.org\n3.170.19.81 api.tmdb.org\n3.170.42.125 "
},
{
"path": "Tmdb_host_ipv6",
"chars": 1390,
"preview": "# Tmdb Hosts Start\n2600:9000:250a:8c00:10:db24:6940:93a1 tmdb.org\n2600:9000:286d:2e00:10:fb02:4000:93a1 "
},
{
"path": "check_tmdb_github.py",
"chars": 10808,
"preview": "import requests\nfrom time import sleep\nimport random\nimport time\nimport os\nimport sys\nfrom datetime import datetime, tim"
},
{
"path": "check_tmdb_github_dnschecked.py",
"chars": 12311,
"preview": "import requests\nfrom time import sleep\nimport random\nimport time\nimport os\nimport sys\nimport re # 导入正则模块用于IP验证\nfrom dat"
},
{
"path": "requirements.txt",
"chars": 61,
"preview": "requests>=2.31.0\npythonping==1.1.4\nretry==0.9.2\nping3==4.0.8\n"
}
]
About this extraction
This page contains the full source code of the cnwikee/CheckTMDB GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 9 files (36.0 KB), approximately 11.9k tokens, and a symbol index with 18 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.