From 419731448cc6dea9a2f96bf011e901e6c6cf36dc Mon Sep 17 00:00:00 2001 From: "guorong.zheng" <360996299@qq.com> Date: Fri, 15 Nov 2024 14:09:31 +0800 Subject: [PATCH 1/4] chore:run service --- main.py | 27 +++++++++++++++++---------- tkinter_ui/tkinter_ui.py | 10 ++++++++-- utils/tools.py | 15 +++++++++------ 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/main.py b/main.py index 7088327d408..a75188fca14 100644 --- a/main.py +++ b/main.py @@ -224,8 +224,6 @@ async def main(self): True, url=f"{get_ip_address()}" if open_service else None, ) - if open_service: - run_service() except asyncio.exceptions.CancelledError: print("Update cancelled!") @@ -253,14 +251,23 @@ def scheduled_task(): def run_service(): - if not os.environ.get("GITHUB_ACTIONS"): - ip_address = get_ip_address() - print(f"📄 Result detail: {ip_address}/result") - print(f"📄 Log detail: {ip_address}/log") - print(f"✅ You can use this url to watch IPTV 📺: {ip_address}") - app.run(host="0.0.0.0", port=8000) + try: + if not os.environ.get("GITHUB_ACTIONS"): + ip_address = get_ip_address() + print(f"📄 Result detail: {ip_address}/result") + print(f"📄 Log detail: {ip_address}/log") + print(f"✅ You can use this url to watch IPTV 📺: {ip_address}") + app.run(host="0.0.0.0", port=8000) + except Exception as e: + print(f"❌ Service start failed: {e}") if __name__ == "__main__": - if len(sys.argv) == 1 or (len(sys.argv) > 1 and sys.argv[1] == "scheduled_task"): - scheduled_task() + if len(sys.argv) == 1 and config.open_service: + loop = asyncio.new_event_loop() + + async def run_service_async(): + loop.run_in_executor(None, run_service) + + asyncio.run(run_service_async()) + scheduled_task() diff --git a/tkinter_ui/tkinter_ui.py b/tkinter_ui/tkinter_ui.py index f5388088002..b5905282a0a 100644 --- a/tkinter_ui/tkinter_ui.py +++ b/tkinter_ui/tkinter_ui.py @@ -7,7 +7,7 @@ from PIL import Image, ImageTk from utils.config import config from utils.tools import resource_path -from main import UpdateSource +from main import UpdateSource, run_service import asyncio import threading import webbrowser @@ -113,11 +113,17 @@ async def run_update(self): self.progress_label.pack_forget() def on_run_update(self): + loop = asyncio.new_event_loop() + + async def run_service_async(): + loop.run_in_executor(None, run_service) + def run_loop(): - loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) loop.run_until_complete(self.run_update()) + if config.open_service: + asyncio.run(run_service_async()) self.thread = threading.Thread(target=run_loop, daemon=True) self.thread.start() diff --git a/utils/tools.py b/utils/tools.py index f38f2052942..db93397c85d 100644 --- a/utils/tools.py +++ b/utils/tools.py @@ -400,12 +400,15 @@ def get_result_file_content(show_result=False): Get the content of the result file """ user_final_file = resource_path(config.final_file) - if config.open_m3u_result: - user_final_file = os.path.splitext(user_final_file)[0] + ".m3u" - if show_result == False: - return send_file(user_final_file, as_attachment=True) - with open(user_final_file, "r", encoding="utf-8") as file: - content = file.read() + if os.path.exists(user_final_file): + if config.open_m3u_result: + user_final_file = os.path.splitext(user_final_file)[0] + ".m3u" + if show_result == False: + return send_file(user_final_file, as_attachment=True) + with open(user_final_file, "r", encoding="utf-8") as file: + content = file.read() + else: + content = "🔍️正在更新,请耐心等待更新完成..." return render_template_string( "
{{ content }}
", content=content, From 2754b45fbbb072c88e01a79f7aba4a2d29a05116 Mon Sep 17 00:00:00 2001 From: "guorong.zheng" <360996299@qq.com> Date: Fri, 15 Nov 2024 15:17:14 +0800 Subject: [PATCH 2/4] remove:domain_blacklist --- config/config.ini | 3 +-- docs/config.md | 1 - docs/config_en.md | 1 - tkinter_ui/default.py | 24 ------------------------ tkinter_ui/tkinter_ui.py | 1 - utils/config.py | 10 ---------- utils/tools.py | 18 +----------------- 7 files changed, 2 insertions(+), 56 deletions(-) diff --git a/config/config.ini b/config/config.ini index e7529ba5955..d63c7a9a360 100644 --- a/config/config.ini +++ b/config/config.ini @@ -20,9 +20,8 @@ ipv_type = 全部 ipv_type_prefer = 自动 ipv4_num = 5 ipv6_num = 5 -domain_blacklist = epg.pw,skype.serv00.net,iptv.yjxfz.com,live-hls-web-ajb.getaj.net,live.goodiptv.club,hc73k3dhwo5gfkt.wcetv.com,stream1.freetv.fun,zw9999.cnstream.top open_m3u_result = True -url_keywords_blacklist = +url_keywords_blacklist = epg.pw,skype.serv00.net,iptv.yjxfz.com,live-hls-web-ajb.getaj.net,live.goodiptv.club,hc73k3dhwo5gfkt.wcetv.com,stream1.freetv.fun,zw9999.cnstream.top open_subscribe = True subscribe_urls = https://live.fanmingming.com/tv/m3u/ipv6.m3u,https://ghp.ci/https://raw.githubusercontent.com/joevess/IPTV/main/home.m3u8,https://aktv.top/live.txt,http://175.178.251.183:6689/live.txt,https://ghproxy.net/https://raw.githubusercontent.com/kimwang1978/collect-tv-txt/main/merged_output.txt,https://m3u.ibert.me/txt/fmml_dv6.txt,https://m3u.ibert.me/txt/o_cn.txt,https://m3u.ibert.me/txt/j_iptv.txt,https://github.moeyy.xyz/https://raw.githubusercontent.com/PizazzGY/TVBox/main/live.txt,https://ghproxy.net/https://raw.githubusercontent.com/xzw832/cmys/main/S_CCTV.txt,https://ghproxy.net/https://raw.githubusercontent.com/xzw832/cmys/main/S_weishi.txt,http://itv.22m.top/ITVBox/tv/tvonline.txt open_multicast = True diff --git a/docs/config.md b/docs/config.md index a58a429cfd2..06c75118443 100644 --- a/docs/config.md +++ b/docs/config.md @@ -24,7 +24,6 @@ | ipv_type_prefer | 自动 | 接口协议类型偏好,优先将该类型的接口排在结果前面,可选值:IPv4、IPv6、自动、auto | | ipv4_num | 5 | 结果中偏好的 IPv4 接口数量 | | ipv6_num | 5 | 结果中偏好的 IPv6 接口数量 | -| domain_blacklist | epg.pw | 接口域名黑名单,用于过滤低质量含广告类域名的接口 | | url_keywords_blacklist | | 接口关键字黑名单,用于过滤含特定字符的接口 | | open_subscribe | False | 开启订阅源功能 | | subscribe_urls | | 订阅源,请输入订阅链接(支持 txt 与 m3u 链接),多个链接以逗号分隔 | diff --git a/docs/config_en.md b/docs/config_en.md index 5da6e322612..d0dd43b71e3 100644 --- a/docs/config_en.md +++ b/docs/config_en.md @@ -24,7 +24,6 @@ | ipv_type_prefer | auto | Interface protocol type preference, prioritize interfaces of this type in the results, optional values: IPv4, IPv6, auto | | ipv4_num | 5 | The preferred number of IPv4 interfaces in the result | | ipv6_num | 5 | The preferred number of IPv6 interfaces in the result | -| domain_blacklist | | Interface domain blacklist, used to filter out interfaces with low-quality, ad-inclusive domains | | url_keywords_blacklist | | Interface keyword blacklist, used to filter out interfaces containing specific characters | | open_subscribe | True | Enable subscription source feature | | subscribe_urls | | Subscription source, please enter the subscription link (supports txt and m3u links), multiple links should be separated by commas | diff --git a/tkinter_ui/default.py b/tkinter_ui/default.py index f527ce73a10..e2323f58cf9 100644 --- a/tkinter_ui/default.py +++ b/tkinter_ui/default.py @@ -372,22 +372,6 @@ def init_ui(self, root): ) self.open_empty_category_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) - frame_default_domain_blacklist = tk.Frame(root) - frame_default_domain_blacklist.pack(fill=tk.X) - - self.domain_blacklist_label = tk.Label( - frame_default_domain_blacklist, text="域名黑名单:", width=12 - ) - self.domain_blacklist_label.pack(side=tk.LEFT, padx=4, pady=8) - self.domain_blacklist_text = scrolledtext.ScrolledText( - frame_default_domain_blacklist, height=2 - ) - self.domain_blacklist_text.pack( - side=tk.LEFT, padx=4, pady=8, expand=True, fill=tk.BOTH - ) - self.domain_blacklist_text.insert(tk.END, ",".join(config.domain_blacklist)) - self.domain_blacklist_text.bind("", self.update_domain_blacklist) - frame_default_url_keywords_blacklist = tk.Frame(root) frame_default_url_keywords_blacklist.pack(fill=tk.X) @@ -503,13 +487,6 @@ def update_url_keywords_blacklist(self, event): self.url_keywords_blacklist_text.get(1.0, tk.END), ) - def update_domain_blacklist(self, event): - config.set( - "Settings", - "domain_blacklist", - self.domain_blacklist_text.get(1.0, tk.END), - ) - def update_url_keywords_blacklist(self, event): config.set( "Settings", @@ -541,7 +518,6 @@ def change_entry_state(self, state): "open_url_info_checkbutton", "open_empty_category_checkbutton", "ipv_type_combo", - "domain_blacklist_text", "url_keywords_blacklist_text", ]: getattr(self, entry).config(state=state) diff --git a/tkinter_ui/tkinter_ui.py b/tkinter_ui/tkinter_ui.py index b5905282a0a..f4c80ae8693 100644 --- a/tkinter_ui/tkinter_ui.py +++ b/tkinter_ui/tkinter_ui.py @@ -58,7 +58,6 @@ def save_config(self): "response_time_weight": self.default_ui.response_time_weight_scale.get(), "resolution_weight": self.default_ui.resolution_weight_scale.get(), "ipv_type": self.default_ui.ipv_type_combo.get(), - "domain_blacklist": self.default_ui.domain_blacklist_text.get(1.0, tk.END), "url_keywords_blacklist": self.default_ui.url_keywords_blacklist_text.get( 1.0, tk.END ), diff --git a/utils/config.py b/utils/config.py index 512f657322d..ea434b73180 100644 --- a/utils/config.py +++ b/utils/config.py @@ -147,16 +147,6 @@ def open_url_info(self): def recent_days(self): return self.config.getint("Settings", "recent_days", fallback=30) - @property - def domain_blacklist(self): - return [ - domain.strip() - for domain in self.config.get( - "Settings", "domain_blacklist", fallback="" - ).split(",") - if domain.strip() - ] - @property def url_keywords_blacklist(self): return [ diff --git a/utils/tools.py b/utils/tools.py index db93397c85d..8ed74d8f42f 100644 --- a/utils/tools.py +++ b/utils/tools.py @@ -274,17 +274,6 @@ def check_url_ipv_type(url): ) -def check_by_domain_blacklist(url): - """ - Check by domain blacklist - """ - domain_blacklist = { - (urlparse(domain).netloc if urlparse(domain).scheme else domain) - for domain in config.domain_blacklist - } - return urlparse(url).netloc not in domain_blacklist - - def check_by_url_keywords_blacklist(url): """ Check by URL blacklist keywords @@ -296,11 +285,7 @@ def check_url_by_patterns(url): """ Check the url by patterns """ - return ( - check_url_ipv_type(url) - and check_by_domain_blacklist(url) - and check_by_url_keywords_blacklist(url) - ) + return check_url_ipv_type(url) and check_by_url_keywords_blacklist(url) def filter_urls_by_patterns(urls): @@ -308,7 +293,6 @@ def filter_urls_by_patterns(urls): Filter urls by patterns """ urls = [url for url in urls if check_url_ipv_type(url)] - urls = [url for url in urls if check_by_domain_blacklist(url)] urls = [url for url in urls if check_by_url_keywords_blacklist(url)] return urls From 9249970a4ef58341b2d35c11cc70df1d793b3cf5 Mon Sep 17 00:00:00 2001 From: "guorong.zheng" <360996299@qq.com> Date: Fri, 15 Nov 2024 15:52:01 +0800 Subject: [PATCH 3/4] chore:layout --- tkinter_ui/default.py | 52 ++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/tkinter_ui/default.py b/tkinter_ui/default.py index e2323f58cf9..0da7131523f 100644 --- a/tkinter_ui/default.py +++ b/tkinter_ui/default.py @@ -141,7 +141,7 @@ def init_ui(self, root): frame_default_channel_column1, text="频道接口数量:", width=12 ) self.urls_limit_label.pack(side=tk.LEFT, padx=4, pady=8) - self.urls_limit_entry = tk.Entry(frame_default_channel_column1) + self.urls_limit_entry = tk.Entry(frame_default_channel_column1, width=8) self.urls_limit_entry.pack(side=tk.LEFT, padx=4, pady=8) self.urls_limit_entry.insert(0, config.urls_limit) self.urls_limit_entry.bind("", self.update_urls_limit) @@ -150,7 +150,7 @@ def init_ui(self, root): frame_default_channel_column2, text="接口协议类型:", width=12 ) self.ipv_type_label.pack(side=tk.LEFT, padx=4, pady=8) - self.ipv_type_combo = ttk.Combobox(frame_default_channel_column2) + self.ipv_type_combo = ttk.Combobox(frame_default_channel_column2, width=5) self.ipv_type_combo.pack(side=tk.LEFT, padx=4, pady=8) self.ipv_type_combo["values"] = ("IPv4", "IPv6", "全部") if config.ipv_type == "ipv4": @@ -161,22 +161,16 @@ def init_ui(self, root): self.ipv_type_combo.current(2) self.ipv_type_combo.bind("<>", self.update_ipv_type) - frame_default_sort = tk.Frame(root) - frame_default_sort.pack(fill=tk.X) - frame_default_sort_column1 = tk.Frame(frame_default_sort) - frame_default_sort_column1.pack(side=tk.LEFT, fill=tk.Y) - frame_default_sort_column2 = tk.Frame(frame_default_sort) - frame_default_sort_column2.pack(side=tk.LEFT, fill=tk.Y) - frame_default_sort_column3 = tk.Frame(frame_default_sort) - frame_default_sort_column3.pack(side=tk.RIGHT, fill=tk.Y) + frame_default_open_keep_all = tk.Frame(root) + frame_default_open_keep_all.pack(fill=tk.X) self.open_keep_all_label = tk.Label( - frame_default_sort_column1, text="保留模式:", width=12 + frame_default_open_keep_all, text="保留模式:", width=12 ) self.open_keep_all_label.pack(side=tk.LEFT, padx=4, pady=8) self.open_keep_all_var = tk.BooleanVar(value=config.open_keep_all) self.open_keep_all_checkbutton = ttk.Checkbutton( - frame_default_sort_column1, + frame_default_open_keep_all, variable=self.open_keep_all_var, onvalue=True, offvalue=False, @@ -185,13 +179,20 @@ def init_ui(self, root): ) self.open_keep_all_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) + frame_default_sort = tk.Frame(root) + frame_default_sort.pack(fill=tk.X) + frame_default_sort_column1 = tk.Frame(frame_default_sort) + frame_default_sort_column1.pack(side=tk.LEFT, fill=tk.Y) + frame_default_sort_column2 = tk.Frame(frame_default_sort) + frame_default_sort_column2.pack(side=tk.RIGHT, fill=tk.Y) + self.open_sort_label = tk.Label( - frame_default_sort_column2, text="测速排序:", width=12 + frame_default_sort_column1, text="测速排序:", width=12 ) self.open_sort_label.pack(side=tk.LEFT, padx=4, pady=8) self.open_sort_var = tk.BooleanVar(value=config.open_sort) self.open_sort_checkbutton = ttk.Checkbutton( - frame_default_sort_column2, + frame_default_sort_column1, variable=self.open_sort_var, onvalue=True, offvalue=False, @@ -200,10 +201,10 @@ def init_ui(self, root): self.open_sort_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) self.sort_timeout_label = tk.Label( - frame_default_sort_column3, text="测速超时:", width=12 + frame_default_sort_column2, text="测速超时:", width=12 ) self.sort_timeout_label.pack(side=tk.LEFT, padx=4, pady=8) - self.sort_timeout_entry = tk.Entry(frame_default_sort_column3) + self.sort_timeout_entry = tk.Entry(frame_default_sort_column2, width=8) self.sort_timeout_entry.pack(side=tk.LEFT, padx=4, pady=8) self.sort_timeout_entry.insert(0, config.sort_timeout) self.sort_timeout_entry.bind("", self.update_sort_timeout) @@ -241,7 +242,7 @@ def init_ui(self, root): onvalue=True, offvalue=False, command=self.update_open_m3u_result, - text="(支持频道图标)", + text="(开启频道图标)", ) self.open_m3u_result_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) @@ -277,7 +278,9 @@ def init_ui(self, root): frame_default_resolution_params_column2, text="最小分辨率:", width=12 ) self.min_resolution_label.pack(side=tk.LEFT, padx=4, pady=8) - self.min_resolution_entry = tk.Entry(frame_default_resolution_params_column2) + self.min_resolution_entry = tk.Entry( + frame_default_resolution_params_column2, width=10 + ) self.min_resolution_entry.pack(side=tk.LEFT, padx=4, pady=8) self.min_resolution_entry.insert(0, config.min_resolution) self.min_resolution_entry.bind("", self.update_min_resolution) @@ -345,12 +348,12 @@ def init_ui(self, root): self.open_update_time_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) self.open_url_info_label = tk.Label( - frame_default_open_update_info_column1, text="显示接口信息:", width=12 + frame_default_open_update_info_column2, text="显示接口信息:", width=12 ) self.open_url_info_label.pack(side=tk.LEFT, padx=4, pady=8) self.open_url_info_var = tk.BooleanVar(value=config.open_url_info) self.open_url_info_checkbutton = ttk.Checkbutton( - frame_default_open_update_info_column1, + frame_default_open_update_info_column2, variable=self.open_url_info_var, onvalue=True, offvalue=False, @@ -358,13 +361,16 @@ def init_ui(self, root): ) self.open_url_info_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) + frame_default_open_empty_category = tk.Frame(root) + frame_default_open_empty_category.pack(fill=tk.X) + self.open_empty_category_label = tk.Label( - frame_default_open_update_info_column2, text="无结果频道分类:", width=12 + frame_default_open_empty_category, text="显示无结果分类:", width=12 ) self.open_empty_category_label.pack(side=tk.LEFT, padx=4, pady=8) self.open_empty_category_var = tk.BooleanVar(value=config.open_empty_category) self.open_empty_category_checkbutton = ttk.Checkbutton( - frame_default_open_update_info_column2, + frame_default_open_empty_category, variable=self.open_empty_category_var, onvalue=True, offvalue=False, @@ -380,7 +386,7 @@ def init_ui(self, root): ) self.url_keywords_blacklist_label.pack(side=tk.LEFT, padx=4, pady=8) self.url_keywords_blacklist_text = scrolledtext.ScrolledText( - frame_default_url_keywords_blacklist, height=2 + frame_default_url_keywords_blacklist, height=5 ) self.url_keywords_blacklist_text.pack( side=tk.LEFT, padx=4, pady=8, expand=True, fill=tk.BOTH From 288b8d934474317f9d6b9e0dd223b14f44933e32 Mon Sep 17 00:00:00 2001 From: "guorong.zheng" <360996299@qq.com> Date: Fri, 15 Nov 2024 16:27:23 +0800 Subject: [PATCH 4/4] release:v1.5.2 --- CHANGELOG.md | 33 +++++++++++++++++++++++++++++++++ version.json | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98cec04db56..2e12f8f5073 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,38 @@ # 更新日志(Changelog) +## v1.5.2 + +### 2024/11/15 + +- ✨ 新增各省份地方台 +- ✨ 新增控制显示无结果频道分类配置(open_empty_category)(#551) +- ✨ 调整接口源(#526) +- 🪄 优化频道数据插入速度 +- 🪄 优化 IPv6 测速逻辑,解决无结果问题 +- 🪄 优化页面服务启动与 docker 定时任务日志输出 +- 🪄 调整默认配置:接口数量 urls_limit=10 等数量配置,增加订阅源 +- 🐛 修复运行停止问题(#527) +- 🐛 修复 Win7 GUI 启动问题(#536) +- 🗑️ 移除部分无效订阅源 +- 🗑️ 移除域名黑名单配置(domain_blacklist),请使用接口关键字黑名单(url_keywords_blacklist)替代 + +
+ English + +- ✨ Added local channels for each province. +- ✨ Added configuration to control the display of the No Results Channel Category (open_empty_category) (#551). +- ✨ Adjusted interface sources (#526). +- 🪄 Optimized the speed of channel data insertion. +- 🪄 Optimized IPv6 speed test logic to resolve no results issues. +- 🪄 Optimized page service startup and Docker scheduled task log output. +- 🪄 Adjusted default configurations: number of interfaces urls_limit=10, etc., and added subscription sources. +- 🐛 Fixed the issue of the program stopping (#527). +- 🐛 Fixed the issue of Win7 GUI startup (#536). +- 🗑️ Removed some invalid subscription sources. +- 🗑️ Removed the domain blacklist configuration (domain_blacklist). Please use the interface keyword blacklist (url_keywords_blacklist) instead. + +
+ ## v1.5.1 ### 2024/11/5 diff --git a/version.json b/version.json index 89704bb19db..d2d7d6bdc41 100644 --- a/version.json +++ b/version.json @@ -1,4 +1,4 @@ { - "version": "1.5.1", + "version": "1.5.2", "name": "IPTV电视直播源更新工具" } \ No newline at end of file