From a70fcdfe20e0b22b2ad990da76cb5d82ed489141 Mon Sep 17 00:00:00 2001 From: "guorong.zheng" <360996299@qq.com> Date: Fri, 13 Dec 2024 18:09:09 +0800 Subject: [PATCH 1/6] feat:tkinter --- tkinter_ui/default.py | 171 +++++++++++++++++++++++++++++++------ tkinter_ui/tkinter_ui.py | 2 +- tkinter_ui/tkinter_ui.spec | 1 + 3 files changed, 148 insertions(+), 26 deletions(-) diff --git a/tkinter_ui/default.py b/tkinter_ui/default.py index 768463b222..c6ad348267 100644 --- a/tkinter_ui/default.py +++ b/tkinter_ui/default.py @@ -46,10 +46,23 @@ def init_ui(self, root): onvalue=True, offvalue=False, command=self.update_open_use_old_result, - text="(保留上次更新可用结果)", ) self.open_use_old_result_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) + self.open_use_cache_label = tk.Label( + frame_default_open_update_column2, text="使用离线数据:", width=12 + ) + self.open_use_cache_label.pack(side=tk.LEFT, padx=4, pady=8) + self.open_use_cache_var = tk.BooleanVar(value=config.open_use_cache) + self.open_use_cache_checkbutton = ttk.Checkbutton( + frame_default_open_update_column2, + variable=self.open_use_cache_var, + onvalue=True, + offvalue=False, + command=self.update_open_use_cache, + ) + self.open_use_cache_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) + frame_default_source_file = tk.Frame(root) frame_default_source_file.pack(fill=tk.X) frame_default_source_file_column1 = tk.Frame(frame_default_source_file) @@ -101,13 +114,27 @@ def init_ui(self, root): frame_default_mode_params_column2 = tk.Frame(frame_default_mode) frame_default_mode_params_column2.pack(side=tk.RIGHT, fill=tk.Y) + self.open_request_label = tk.Label( + frame_default_mode_params_column1, text="开启网络请求:", width=12 + ) + self.open_request_label.pack(side=tk.LEFT, padx=4, pady=8) + self.open_request_var = tk.BooleanVar(value=config.open_request) + self.open_request_checkbutton = ttk.Checkbutton( + frame_default_mode_params_column1, + variable=self.open_request_var, + onvalue=True, + offvalue=False, + command=self.update_open_request + ) + self.open_request_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) + self.open_driver_label = tk.Label( - frame_default_mode_params_column1, text="浏览器模式:", width=12 + frame_default_mode_params_column2, text="浏览器模式:", width=12 ) self.open_driver_label.pack(side=tk.LEFT, padx=4, pady=8) self.open_driver_var = tk.BooleanVar(value=config.open_driver) self.open_driver_checkbutton = ttk.Checkbutton( - frame_default_mode_params_column1, + frame_default_mode_params_column2, variable=self.open_driver_var, onvalue=True, offvalue=False, @@ -116,21 +143,6 @@ def init_ui(self, root): ) self.open_driver_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) - self.open_proxy_label = tk.Label( - frame_default_mode_params_column2, text="开启代理:", width=12 - ) - self.open_proxy_label.pack(side=tk.LEFT, padx=4, pady=8) - self.open_proxy_var = tk.BooleanVar(value=config.open_proxy) - self.open_proxy_checkbutton = ttk.Checkbutton( - frame_default_mode_params_column2, - variable=self.open_proxy_var, - onvalue=True, - offvalue=False, - command=self.update_open_proxy, - text="(通过代理进行更新)", - ) - self.open_proxy_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) - frame_default_channel = tk.Frame(root) frame_default_channel.pack(fill=tk.X) frame_default_channel_column1 = tk.Frame(frame_default_channel) @@ -162,16 +174,35 @@ def init_ui(self, root): self.ipv_type_combo.current(2) self.ipv_type_combo.bind("<>", self.update_ipv_type) - frame_default_open_keep_all = tk.Frame(root) - frame_default_open_keep_all.pack(fill=tk.X) + frame_proxy_mode = tk.Frame(root) + frame_proxy_mode.pack(fill=tk.X) + frame_proxy_mode_params_column1 = tk.Frame(frame_proxy_mode) + frame_proxy_mode_params_column1.pack(side=tk.LEFT, fill=tk.Y) + frame_proxy_mode_params_column2 = tk.Frame(frame_proxy_mode) + frame_proxy_mode_params_column2.pack(side=tk.RIGHT, fill=tk.Y) + + self.open_proxy_label = tk.Label( + frame_proxy_mode_params_column1, text="开启代理:", width=12 + ) + self.open_proxy_label.pack(side=tk.LEFT, padx=4, pady=8) + self.open_proxy_var = tk.BooleanVar(value=config.open_proxy) + self.open_proxy_checkbutton = ttk.Checkbutton( + frame_proxy_mode_params_column1, + variable=self.open_proxy_var, + onvalue=True, + offvalue=False, + command=self.update_open_proxy, + text="(通过代理进行更新)", + ) + self.open_proxy_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) self.open_keep_all_label = tk.Label( - frame_default_open_keep_all, text="保留模式:", width=12 + frame_proxy_mode_params_column2, 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_open_keep_all, + frame_proxy_mode_params_column2, variable=self.open_keep_all_var, onvalue=True, offvalue=False, @@ -247,6 +278,45 @@ def init_ui(self, root): ) self.open_m3u_result_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) + frame_default_speed_params = tk.Frame(root) + frame_default_speed_params.pack(fill=tk.X) + frame_default_speed_params_column1 = tk.Frame( + frame_default_speed_params + ) + frame_default_speed_params_column1.pack(side=tk.LEFT, fill=tk.Y) + frame_default_speed_params_column2 = tk.Frame( + frame_default_speed_params + ) + frame_default_speed_params_column2.pack(side=tk.RIGHT, fill=tk.Y) + + self.open_filter_speed_label = tk.Label( + frame_default_speed_params_column1, text="速率过滤:", width=12 + ) + self.open_filter_speed_label.pack(side=tk.LEFT, padx=4, pady=8) + self.open_filter_speed_var = tk.BooleanVar( + value=config.open_filter_speed + ) + self.open_filter_speed_checkbutton = ttk.Checkbutton( + frame_default_speed_params_column1, + variable=self.open_filter_speed_var, + onvalue=True, + offvalue=False, + command=self.update_open_filter_speed, + text="(低于最小速率将被过滤)", + ) + self.open_filter_speed_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) + + self.min_speed_label = tk.Label( + frame_default_speed_params_column2, text="最小速率:", width=12 + ) + self.min_speed_label.pack(side=tk.LEFT, padx=4, pady=8) + self.min_speed_entry = tk.Entry( + frame_default_speed_params_column2, width=10 + ) + self.min_speed_entry.pack(side=tk.LEFT, padx=4, pady=8) + self.min_speed_entry.insert(0, config.min_speed) + self.min_speed_entry.bind("", self.update_min_speed) + frame_default_resolution_params = tk.Frame(root) frame_default_resolution_params.pack(fill=tk.X) frame_default_resolution_params_column1 = tk.Frame( @@ -293,6 +363,21 @@ def init_ui(self, root): frame_default_sort_params_column2 = tk.Frame(frame_default_sort_params) frame_default_sort_params_column2.pack(side=tk.RIGHT, fill=tk.Y) + self.speed_weight_label = tk.Label( + frame_default_sort_params_column1, text="速率权重:", width=12 + ) + self.speed_weight_label.pack(side=tk.LEFT, padx=4, pady=8) + self.speed_weight_scale = tk.Scale( + frame_default_sort_params_column1, + from_=0, + to=1, + orient=tk.HORIZONTAL, + resolution=0.1, + command=self.update_speed_weight, + ) + self.speed_weight_scale.pack(side=tk.LEFT, padx=4, pady=8) + self.speed_weight_scale.set(config.speed_weight) + self.delay_weight_label = tk.Label( frame_default_sort_params_column1, text="响应时间权重:", width=12 ) @@ -407,6 +492,11 @@ def update_open_use_old_result(self): "Settings", "open_use_old_result", str(self.open_use_old_result_var.get()) ) + def update_open_use_cache(self): + config.set( + "Settings", "open_use_cache", str(self.open_use_cache_var.get()) + ) + def select_source_file(self): filepath = filedialog.askopenfilename( initialdir=os.getcwd(), title="选择模板文件", filetypes=[("txt", "*.txt")] @@ -425,6 +515,9 @@ def select_final_file(self): self.final_file_entry.insert(0, filepath) config.set("Settings", "final_file", filepath) + def update_open_request(self): + config.set("Settings", "open_requests", str(self.open_request_var.get())) + def update_open_driver(self): config.set("Settings", "open_driver", str(self.open_driver_var.get())) @@ -446,6 +539,16 @@ def update_open_ffmpeg(self): def update_open_m3u_result(self): config.set("Settings", "open_m3u_result", str(self.open_m3u_result_var.get())) + def update_open_filter_speed(self): + config.set( + "Settings", + "open_filter_speed", + str(self.open_filter_speed_var.get()), + ) + + def update_min_speed(self, event): + config.set("Settings", "min_speed", self.min_speed_entry.get()) + def update_open_filter_resolution(self): config.set( "Settings", @@ -459,19 +562,32 @@ def update_min_resolution(self, event): def update_urls_limit(self, event): config.set("Settings", "urls_limit", self.urls_limit_entry.get()) + def update_speed_weight(self, event): + weight1 = self.speed_weight_scale.get() + weight2 = 1 - weight1 + self.delay_weight_scale.set(weight2 / 2) + self.resolution_weight_scale.set(weight2 / 2) + config.set("Settings", "speed_weight", str(weight1)) + config.set("Settings", "delay_weight", str(weight2 / 2)) + config.set("Settings", "resolution_weight", str(weight2 / 2)) + def update_delay_weight(self, event): weight1 = self.delay_weight_scale.get() weight2 = 1 - weight1 - self.resolution_weight_scale.set(weight2) + self.speed_weight_scale.set(weight2 / 2) + self.resolution_weight_scale.set(weight2 / 2) config.set("Settings", "delay_weight", str(weight1)) - config.set("Settings", "resolution_weight", str(weight2)) + config.set("Settings", "speed_weight", str(weight2 / 2)) + config.set("Settings", "resolution_weight", str(weight2 / 2)) def update_resolution_weight(self, event): weight1 = self.resolution_weight_scale.get() weight2 = 1 - weight1 + self.speed_weight_scale.set(weight2 / 2) self.delay_weight_scale.set(weight2) config.set("Settings", "resolution_weight", str(weight1)) - config.set("Settings", "delay_weight", str(weight2)) + config.set("Settings", "speed_weight", str(weight2 / 2)) + config.set("Settings", "delay_weight", str(weight2 / 2)) def update_open_update_time(self): config.set("Settings", "open_update_time", str(self.open_update_time_var.get())) @@ -505,6 +621,8 @@ def change_entry_state(self, state): for entry in [ "open_update_checkbutton", "open_use_old_result_checkbutton", + "open_use_cache_checkbutton", + "open_request_checkbutton", "open_driver_checkbutton", "open_proxy_checkbutton", "source_file_entry", @@ -516,9 +634,12 @@ def change_entry_state(self, state): "sort_timeout_entry", "open_ffmpeg_checkbutton", "open_m3u_result_checkbutton", + "open_filter_speed_checkbutton", + "min_speed_entry", "open_filter_resolution_checkbutton", "min_resolution_entry", "urls_limit_entry", + "speed_weight_scale", "delay_weight_scale", "resolution_weight_scale", "open_update_time_checkbutton", diff --git a/tkinter_ui/tkinter_ui.py b/tkinter_ui/tkinter_ui.py index 013ed82f78..22ec51b6d5 100644 --- a/tkinter_ui/tkinter_ui.py +++ b/tkinter_ui/tkinter_ui.py @@ -254,7 +254,7 @@ def init_UI(self): def get_root_location(root): screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() - width = 550 + width = 650 height = 750 x = (screen_width / 2) - (width / 2) y = (screen_height / 2) - (height / 2) diff --git a/tkinter_ui/tkinter_ui.spec b/tkinter_ui/tkinter_ui.spec index 29d406c943..7c8ceeb12d 100644 --- a/tkinter_ui/tkinter_ui.spec +++ b/tkinter_ui/tkinter_ui.spec @@ -8,6 +8,7 @@ a = Analysis( ('../config/config.ini', 'config'), ('../config/demo.txt', 'config'), ('../config/whitelist.txt', 'config'), + ('../config/subscribe.txt', 'config'), ('../config/rtp', 'config/rtp'), ('../updates/hotel/cache.pkl', 'updates/hotel'), ('../updates/multicast/multicast_map.json', 'updates/multicast'), From b9b9e78cd86dcd731451a6fcd715c15f20bde0a5 Mon Sep 17 00:00:00 2001 From: "guorong.zheng" <360996299@qq.com> Date: Mon, 16 Dec 2024 16:55:37 +0800 Subject: [PATCH 2/6] feat:blacklist and ui --- README.md | 5 - README_en.md | 5 - config/blacklist.txt | 11 + config/config.ini | 75 +++-- config/subscribe.txt | 1 - docs/config.md | 5 - docs/config_en.md | 5 - tkinter_ui/default.py | 479 +++++++++---------------------- tkinter_ui/speed.py | 167 +++++++++++ tkinter_ui/subscribe.py | 33 ++- tkinter_ui/tkinter_ui.py | 63 ++-- tkinter_ui/tkinter_ui.spec | 4 +- updates/online_search/request.py | 34 ++- utils/channel.py | 36 ++- utils/config.py | 26 -- utils/constants.py | 2 + utils/speed.py | 14 +- utils/tools.py | 31 +- 18 files changed, 465 insertions(+), 531 deletions(-) create mode 100644 config/blacklist.txt create mode 100644 tkinter_ui/speed.py diff --git a/README.md b/README.md index c3b1ce625a..11cf7d08d4 100644 --- a/README.md +++ b/README.md @@ -146,7 +146,6 @@ https://cdn.jsdelivr.net/gh/Guovin/iptv-api@gd/source.json |:-----------------------|:------------------------------------------------------------------------------------------|:----------------------------------------| | open_driver | 开启浏览器运行,若更新无数据可开启此模式,较消耗性能 | True | | open_empty_category | 开启无结果频道分类,自动归类至底部 | False | -| open_ffmpeg | 开启使用 FFmpeg 进行测速,获取更准确的速度与分辨率信息,需要提前手动安装 | True | | open_filter_resolution | 开启分辨率过滤,低于最小分辨率(min_resolution)的接口将会被过滤 | True | | open_filter_speed | 开启速率过滤,低于最小速率(min_speed)的接口将会被过滤 | True | | open_hotel | 开启酒店源功能,关闭后所有酒店源工作模式都将关闭 | True | @@ -168,7 +167,6 @@ https://cdn.jsdelivr.net/gh/Guovin/iptv-api@gd/source.json | open_url_info | 开启显示接口说明信息,用于控制是否显示分辨率、接口协议类型等信息,为$符号后的内容,播放软件使用该信息对接口进行描述 | True | | open_use_cache | 开启使用本地缓存数据,适用于查询请求失败场景 | True | | open_use_old_result | 开启使用历史更新结果(包含模板与结果文件的接口),合并至本次更新中 | True | -| delay_weight | 响应时间权重值(所有权重值总和应为 1) | 0.25 | | final_file | 生成结果文件路径 | output/result.txt | | hotel_num | 结果中偏好的酒店源接口数量 | 4 | | hotel_page_num | 酒店地区获取分页数量 | 1 | @@ -187,12 +185,9 @@ https://cdn.jsdelivr.net/gh/Guovin/iptv-api@gd/source.json | origin_type_prefer | 结果偏好的接口来源,结果优先按该顺序进行排序,hotel:酒店源,multicast:组播源,subscribe:订阅源,online_search:关键字搜索 | hotel,multicast,subscribe,online_search | | recent_days | 获取最近时间范围内更新的接口(单位天),适当减小可避免出现匹配问题 | 30 | | request_timeout | 查询请求超时时长,单位秒(s),用于控制查询接口文本链接的超时时长以及重试时长,调整此值能优化更新时间 | 10 | -| resolution_weight | 分辨率权重值 (所有权重值总和应为 1) | 0.25 | | sort_timeout | 单个接口测速超时时长,单位秒(s);数值越大测速所属时间越长,能提高获取接口数量,但质量会有所下降;数值越小测速所需时间越短,能获取低延时的接口,质量较好;调整此值能优化更新时间 | 10 | | source_file | 模板文件路径 | config/demo.txt | -| speed_weight | 速率权重值(所有权重值总和应为 1) | 0.5 | | subscribe_num | 结果中偏好的订阅源接口数量 | 3 | -| url_keywords_blacklist | 接口关键字黑名单,用于过滤含特定字符的接口 | | | urls_limit | 单个频道接口数量 | 10 | ## 快速上手 diff --git a/README_en.md b/README_en.md index 8cc38408d8..7822ef01f2 100644 --- a/README_en.md +++ b/README_en.md @@ -146,7 +146,6 @@ https://cdn.jsdelivr.net/gh/Guovin/iptv-api@gd/source.json |:-----------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------| | open_driver | Enable browser execution, If there are no updates, this mode can be enabled, which consumes more performance | True | | open_empty_category | Enable the No Results Channel Category, which will automatically categorize channels without results to the bottom | False | -| open_ffmpeg | Enable speed testing using FFmpeg to obtain more accurate speed and resolution information. Manual installation is required in advance. | True | | open_filter_resolution | Enable resolution filtering, interfaces with resolution lower than the minimum resolution (min_resolution) will be filtered | True | | open_filter_speed | Enable speed filtering, interfaces with speed lower than the minimum speed (min_speed) will be filtered | True | | open_hotel | Enable the hotel source function, after closing it all hotel source working modes will be disabled | True | @@ -168,7 +167,6 @@ https://cdn.jsdelivr.net/gh/Guovin/iptv-api@gd/source.json | open_url_info | Enable display of API description information, used to control whether to show resolution, API protocol type, etc., the content after the $ symbol, playback software uses this information to describe the API | True | | open_use_cache | Enable the use of local cache data, applicable to the query request failure scenario | True | | open_use_old_result | Enable the use of historical update results (including the interface for template and result files) and merge them into the current update | True | -| delay_weight | Response time weight value (the sum of all weight values should be 1) | 0.25 | | final_file | Generated result file path | output/result.txt | | hotel_num | The number of preferred hotel source interfaces in the results | 4 | | hotel_page_num | Number of pages to retrieve for hotel regions | 1 | @@ -187,12 +185,9 @@ https://cdn.jsdelivr.net/gh/Guovin/iptv-api@gd/source.json | origin_type_prefer | Result preference for the source of the interface, results are prioritized in this order: hotel: hotel source, multicast: multicast source, subscribe: subscription source, online_search: keyword search | hotel, multicast, subscribe, online_search | | recent_days | Retrieve interfaces updated within a recent time range (in days), reducing appropriately can avoid matching issues | 30 | | request_timeout | Query request timeout duration, in seconds (s), used to control the timeout and retry duration for querying interface text links. Adjusting this value can optimize update time. | 10 | -| resolution_weight | Resolution weight value (the sum of all weight values should be 1) | 0.25 | | sort_timeout | The timeout duration for speed testing of a single interface, in seconds (s). A larger value means a longer testing period, which can increase the number of interfaces obtained but may decrease their quality. A smaller value means a shorter testing time, which can obtain low-latency interfaces with better quality. Adjusting this value can optimize the update time. | 10 | | source_file | Template file path | config/demo.txt | -| speed_weight | Speed weight value (the sum of all weight values should be 1) | 0.5 | | subscribe_num | The number of preferred subscribe source interfaces in the results | 3 | -| url_keywords_blacklist | Interface keyword blacklist, used to filter out interfaces containing specific characters | | | urls_limit | Number of interfaces per channel | 10 | ## Quick Start diff --git a/config/blacklist.txt b/config/blacklist.txt new file mode 100644 index 0000000000..d5e79b2441 --- /dev/null +++ b/config/blacklist.txt @@ -0,0 +1,11 @@ +# 这是接口黑名单列表,符合关键字的接口将被拦截,一个关键字一行 +# This is the interface blacklist list, the interface matching the keyword will be blocked, one keyword line +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 +zsntlqj.xicp.net diff --git a/config/config.ini b/config/config.ini index 6be19b1807..f677f9cdbb 100644 --- a/config/config.ini +++ b/config/config.ini @@ -1,51 +1,46 @@ [Settings] -open_service = True -open_update = True -open_use_old_result = True -open_use_cache = True -open_request = False -source_file = config/demo.txt -final_file = output/result.txt -open_online_search = False -online_search_page_num = 1 -urls_limit = 10 -open_keep_all = False -open_sort = True -sort_timeout = 10 -open_ffmpeg = True -open_filter_speed = True -min_speed = 0.2 +open_driver = False +open_empty_category = False open_filter_resolution = True -min_resolution = 1920x1080 -delay_weight = 0.25 -speed_weight = 0.5 -resolution_weight = 0.25 -recent_days = 30 -ipv_type = 全部 -ipv_type_prefer = 自动 -ipv4_num = 5 -ipv6_num = 5 +open_filter_speed = True +open_hotel = True +open_hotel_foodie = True +open_hotel_fofa = True +open_keep_all = False open_m3u_result = True -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,zsntlqj.xicp.net -open_subscribe = True open_multicast = True open_multicast_foodie = True open_multicast_fofa = True -multicast_region_list = 全部 -multicast_page_num = 1 +open_online_search = False open_proxy = False -open_driver = False -open_hotel = True -open_hotel_foodie = True -open_hotel_fofa = True -hotel_region_list = 全部 -hotel_page_num = 1 +open_request = False +open_service = True +open_sort = True +open_subscribe = True +open_update = True open_update_time = True -request_timeout = 10 -origin_type_prefer = hotel,multicast,subscribe,online_search +open_url_info = True +open_use_cache = True +open_use_old_result = True +final_file = output/result.txt hotel_num = 4 +hotel_page_num = 1 +hotel_region_list = 全部 +ipv4_num = 5 +ipv6_num = 5 +ipv_type = 全部 +ipv_type_prefer = 自动 +min_resolution = 1920x1080 +min_speed = 0.2 multicast_num = 3 -subscribe_num = 3 +multicast_page_num = 1 +multicast_region_list = 全部 online_search_num = 0 -open_url_info = True -open_empty_category = False \ No newline at end of file +online_search_page_num = 1 +origin_type_prefer = hotel,multicast,subscribe,online_search +recent_days = 30 +request_timeout = 10 +sort_timeout = 10 +source_file = config/demo.txt +subscribe_num = 3 +urls_limit = 10 \ No newline at end of file diff --git a/config/subscribe.txt b/config/subscribe.txt index 81ddce1127..7703226a06 100644 --- a/config/subscribe.txt +++ b/config/subscribe.txt @@ -1,6 +1,5 @@ # 这是订阅源列表,每行一个订阅地址 # This is a list of subscription sources, with one subscription address per line - https://iptv.b2og.com/txt/fmml_ipv6.txt https://ghp.ci/raw.githubusercontent.com/suxuang/myIPTV/main/ipv6.m3u https://live.zbds.top/tv/iptv6.txt diff --git a/docs/config.md b/docs/config.md index 7a38a5b6f7..dea3d5fbe6 100644 --- a/docs/config.md +++ b/docs/config.md @@ -2,7 +2,6 @@ |:-----------------------|:------------------------------------------------------------------------------------------|:----------------------------------------| | open_driver | 开启浏览器运行,若更新无数据可开启此模式,较消耗性能 | True | | open_empty_category | 开启无结果频道分类,自动归类至底部 | False | -| open_ffmpeg | 开启使用 FFmpeg 进行测速,获取更准确的速度与分辨率信息,需要提前手动安装 | True | | open_filter_resolution | 开启分辨率过滤,低于最小分辨率(min_resolution)的接口将会被过滤 | True | | open_filter_speed | 开启速率过滤,低于最小速率(min_speed)的接口将会被过滤 | True | | open_hotel | 开启酒店源功能,关闭后所有酒店源工作模式都将关闭 | True | @@ -24,7 +23,6 @@ | open_url_info | 开启显示接口说明信息,用于控制是否显示分辨率、接口协议类型等信息,为$符号后的内容,播放软件使用该信息对接口进行描述 | True | | open_use_cache | 开启使用本地缓存数据,适用于查询请求失败场景 | True | | open_use_old_result | 开启使用历史更新结果(包含模板与结果文件的接口),合并至本次更新中 | True | -| delay_weight | 响应时间权重值(所有权重值总和应为 1) | 0.25 | | final_file | 生成结果文件路径 | output/result.txt | | hotel_num | 结果中偏好的酒店源接口数量 | 4 | | hotel_page_num | 酒店地区获取分页数量 | 1 | @@ -43,10 +41,7 @@ | origin_type_prefer | 结果偏好的接口来源,结果优先按该顺序进行排序,hotel:酒店源,multicast:组播源,subscribe:订阅源,online_search:关键字搜索 | hotel,multicast,subscribe,online_search | | recent_days | 获取最近时间范围内更新的接口(单位天),适当减小可避免出现匹配问题 | 30 | | request_timeout | 查询请求超时时长,单位秒(s),用于控制查询接口文本链接的超时时长以及重试时长,调整此值能优化更新时间 | 10 | -| resolution_weight | 分辨率权重值 (所有权重值总和应为 1) | 0.25 | | sort_timeout | 单个接口测速超时时长,单位秒(s);数值越大测速所属时间越长,能提高获取接口数量,但质量会有所下降;数值越小测速所需时间越短,能获取低延时的接口,质量较好;调整此值能优化更新时间 | 10 | | source_file | 模板文件路径 | config/demo.txt | -| speed_weight | 速率权重值(所有权重值总和应为 1) | 0.5 | | subscribe_num | 结果中偏好的订阅源接口数量 | 3 | -| url_keywords_blacklist | 接口关键字黑名单,用于过滤含特定字符的接口 | | | urls_limit | 单个频道接口数量 | 10 | \ No newline at end of file diff --git a/docs/config_en.md b/docs/config_en.md index dca62473f4..9af3ed04ae 100644 --- a/docs/config_en.md +++ b/docs/config_en.md @@ -2,7 +2,6 @@ |:-----------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------| | open_driver | Enable browser execution, If there are no updates, this mode can be enabled, which consumes more performance | True | | open_empty_category | Enable the No Results Channel Category, which will automatically categorize channels without results to the bottom | False | -| open_ffmpeg | Enable speed testing using FFmpeg to obtain more accurate speed and resolution information. Manual installation is required in advance. | True | | open_filter_resolution | Enable resolution filtering, interfaces with resolution lower than the minimum resolution (min_resolution) will be filtered | True | | open_filter_speed | Enable speed filtering, interfaces with speed lower than the minimum speed (min_speed) will be filtered | True | | open_hotel | Enable the hotel source function, after closing it all hotel source working modes will be disabled | True | @@ -24,7 +23,6 @@ | open_url_info | Enable display of API description information, used to control whether to show resolution, API protocol type, etc., the content after the $ symbol, playback software uses this information to describe the API | True | | open_use_cache | Enable the use of local cache data, applicable to the query request failure scenario | True | | open_use_old_result | Enable the use of historical update results (including the interface for template and result files) and merge them into the current update | True | -| delay_weight | Response time weight value (the sum of all weight values should be 1) | 0.25 | | final_file | Generated result file path | output/result.txt | | hotel_num | The number of preferred hotel source interfaces in the results | 4 | | hotel_page_num | Number of pages to retrieve for hotel regions | 1 | @@ -43,10 +41,7 @@ | origin_type_prefer | Result preference for the source of the interface, results are prioritized in this order: hotel: hotel source, multicast: multicast source, subscribe: subscription source, online_search: keyword search | hotel, multicast, subscribe, online_search | | recent_days | Retrieve interfaces updated within a recent time range (in days), reducing appropriately can avoid matching issues | 30 | | request_timeout | Query request timeout duration, in seconds (s), used to control the timeout and retry duration for querying interface text links. Adjusting this value can optimize update time. | 10 | -| resolution_weight | Resolution weight value (the sum of all weight values should be 1) | 0.25 | | sort_timeout | The timeout duration for speed testing of a single interface, in seconds (s). A larger value means a longer testing period, which can increase the number of interfaces obtained but may decrease their quality. A smaller value means a shorter testing time, which can obtain low-latency interfaces with better quality. Adjusting this value can optimize the update time. | 10 | | source_file | Template file path | config/demo.txt | -| speed_weight | Speed weight value (the sum of all weight values should be 1) | 0.5 | | subscribe_num | The number of preferred subscribe source interfaces in the results | 3 | -| url_keywords_blacklist | Interface keyword blacklist, used to filter out interfaces containing specific characters | | | urls_limit | Number of interfaces per channel | 10 | \ No newline at end of file diff --git a/tkinter_ui/default.py b/tkinter_ui/default.py index c6ad348267..304bb02433 100644 --- a/tkinter_ui/default.py +++ b/tkinter_ui/default.py @@ -1,9 +1,9 @@ import os import tkinter as tk from tkinter import filedialog -from tkinter import scrolledtext from tkinter import ttk +import utils.constants as constants from utils.config import config @@ -13,56 +13,6 @@ def init_ui(self, root): """ Init default UI """ - frame_default_open_update = tk.Frame(root) - frame_default_open_update.pack(fill=tk.X) - frame_default_open_update_column1 = tk.Frame(frame_default_open_update) - frame_default_open_update_column1.pack(side=tk.LEFT, fill=tk.Y) - frame_default_open_update_column2 = tk.Frame(frame_default_open_update) - frame_default_open_update_column2.pack(side=tk.RIGHT, fill=tk.Y) - - self.open_update_label = tk.Label( - frame_default_open_update_column1, text="开启更新:", width=8 - ) - self.open_update_label.pack(side=tk.LEFT, padx=4, pady=8) - self.open_update_var = tk.BooleanVar(value=config.open_update) - self.open_update_checkbutton = ttk.Checkbutton( - frame_default_open_update_column1, - variable=self.open_update_var, - onvalue=True, - offvalue=False, - command=self.update_open_update, - text="(关闭则只运行结果页面服务)", - ) - self.open_update_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) - - self.open_use_old_result_label = tk.Label( - frame_default_open_update_column2, text="使用历史结果:", width=12 - ) - self.open_use_old_result_label.pack(side=tk.LEFT, padx=4, pady=8) - self.open_use_old_result_var = tk.BooleanVar(value=config.open_use_old_result) - self.open_use_old_result_checkbutton = ttk.Checkbutton( - frame_default_open_update_column2, - variable=self.open_use_old_result_var, - onvalue=True, - offvalue=False, - command=self.update_open_use_old_result, - ) - self.open_use_old_result_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) - - self.open_use_cache_label = tk.Label( - frame_default_open_update_column2, text="使用离线数据:", width=12 - ) - self.open_use_cache_label.pack(side=tk.LEFT, padx=4, pady=8) - self.open_use_cache_var = tk.BooleanVar(value=config.open_use_cache) - self.open_use_cache_checkbutton = ttk.Checkbutton( - frame_default_open_update_column2, - variable=self.open_use_cache_var, - onvalue=True, - offvalue=False, - command=self.update_open_use_cache, - ) - self.open_use_cache_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) - frame_default_source_file = tk.Frame(root) frame_default_source_file.pack(fill=tk.X) frame_default_source_file_column1 = tk.Frame(frame_default_source_file) @@ -107,6 +57,76 @@ def init_ui(self, root): ) self.final_file_button.pack(side=tk.LEFT, padx=4, pady=0) + frame_default_open_update = tk.Frame(root) + frame_default_open_update.pack(fill=tk.X) + frame_default_open_update_column1 = tk.Frame(frame_default_open_update) + frame_default_open_update_column1.pack(side=tk.LEFT, fill=tk.Y) + frame_default_open_update_column2 = tk.Frame(frame_default_open_update) + frame_default_open_update_column2.pack(side=tk.RIGHT, fill=tk.Y) + + self.open_update_label = tk.Label( + frame_default_open_update_column1, text="开启更新:", width=12 + ) + self.open_update_label.pack(side=tk.LEFT, padx=4, pady=8) + self.open_update_var = tk.BooleanVar(value=config.open_update) + self.open_update_checkbutton = ttk.Checkbutton( + frame_default_open_update_column1, + variable=self.open_update_var, + onvalue=True, + offvalue=False, + command=self.update_open_update + ) + self.open_update_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) + + self.open_service_label = tk.Label( + frame_default_open_update_column2, text="开启服务:", width=8 + ) + self.open_service_label.pack(side=tk.LEFT, padx=4, pady=8) + self.open_service_var = tk.BooleanVar(value=config.open_service) + self.open_service_checkbutton = ttk.Checkbutton( + frame_default_open_update_column2, + variable=self.open_service_var, + onvalue=True, + offvalue=False, + command=self.update_open_service + ) + self.open_service_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) + + frame_default_open_cache = tk.Frame(root) + frame_default_open_cache.pack(fill=tk.X) + frame_default_open_cache_column1 = tk.Frame(frame_default_open_cache) + frame_default_open_cache_column1.pack(side=tk.LEFT, fill=tk.Y) + frame_default_open_cache_column2 = tk.Frame(frame_default_open_cache) + frame_default_open_cache_column2.pack(side=tk.RIGHT, fill=tk.Y) + + self.open_use_old_result_label = tk.Label( + frame_default_open_cache_column1, text="使用历史结果:", width=12 + ) + self.open_use_old_result_label.pack(side=tk.LEFT, padx=4, pady=8) + self.open_use_old_result_var = tk.BooleanVar(value=config.open_use_old_result) + self.open_use_old_result_checkbutton = ttk.Checkbutton( + frame_default_open_cache_column1, + variable=self.open_use_old_result_var, + onvalue=True, + offvalue=False, + command=self.update_open_use_old_result, + ) + self.open_use_old_result_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) + + self.open_use_cache_label = tk.Label( + frame_default_open_cache_column2, text="使用离线数据:", width=12 + ) + self.open_use_cache_label.pack(side=tk.LEFT, padx=4, pady=8) + self.open_use_cache_var = tk.BooleanVar(value=config.open_use_cache) + self.open_use_cache_checkbutton = ttk.Checkbutton( + frame_default_open_cache_column2, + variable=self.open_use_cache_var, + onvalue=True, + offvalue=False, + command=self.update_open_use_cache, + ) + self.open_use_cache_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) + frame_default_mode = tk.Frame(root) frame_default_mode.pack(fill=tk.X) frame_default_mode_params_column1 = tk.Frame(frame_default_mode) @@ -128,20 +148,14 @@ def init_ui(self, root): ) self.open_request_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) - self.open_driver_label = tk.Label( - frame_default_mode_params_column2, text="浏览器模式:", width=12 - ) - self.open_driver_label.pack(side=tk.LEFT, padx=4, pady=8) - self.open_driver_var = tk.BooleanVar(value=config.open_driver) - self.open_driver_checkbutton = ttk.Checkbutton( - frame_default_mode_params_column2, - variable=self.open_driver_var, - onvalue=True, - offvalue=False, - command=self.update_open_driver, - text="(若获取更新异常请开启)", + self.request_timeout_label = tk.Label( + frame_default_mode_params_column2, text="请求超时(s):", width=12 ) - self.open_driver_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) + self.request_timeout_label.pack(side=tk.LEFT, padx=4, pady=8) + self.request_timeout_entry = tk.Entry(frame_default_mode_params_column2, width=8) + self.request_timeout_entry.pack(side=tk.LEFT, padx=4, pady=8) + self.request_timeout_entry.insert(0, config.request_timeout) + self.request_timeout_entry.bind("", self.update_request_timeout) frame_default_channel = tk.Frame(root) frame_default_channel.pack(fill=tk.X) @@ -182,7 +196,7 @@ def init_ui(self, root): frame_proxy_mode_params_column2.pack(side=tk.RIGHT, fill=tk.Y) self.open_proxy_label = tk.Label( - frame_proxy_mode_params_column1, text="开启代理:", width=12 + frame_proxy_mode_params_column1, text="开启代理查询:", width=12 ) self.open_proxy_label.pack(side=tk.LEFT, padx=4, pady=8) self.open_proxy_var = tk.BooleanVar(value=config.open_proxy) @@ -191,13 +205,12 @@ def init_ui(self, root): variable=self.open_proxy_var, onvalue=True, offvalue=False, - command=self.update_open_proxy, - text="(通过代理进行更新)", + command=self.update_open_proxy ) self.open_proxy_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) self.open_keep_all_label = tk.Label( - frame_proxy_mode_params_column2, text="保留模式:", width=12 + frame_proxy_mode_params_column2, 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) @@ -206,207 +219,43 @@ def init_ui(self, root): variable=self.open_keep_all_var, onvalue=True, offvalue=False, - command=self.update_open_keep_all, - text="(保留所有查询记录)", + command=self.update_open_keep_all ) 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_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_column1, - variable=self.open_sort_var, - onvalue=True, - offvalue=False, - command=self.update_open_sort, - ) - self.open_sort_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) - - self.sort_timeout_label = tk.Label( - 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_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) - - frame_default_sort_mode = tk.Frame(root) - frame_default_sort_mode.pack(fill=tk.X) - frame_default_sort_mode_column1 = tk.Frame(frame_default_sort_mode) - frame_default_sort_mode_column1.pack(side=tk.LEFT, fill=tk.Y) - frame_default_sort_mode_column2 = tk.Frame(frame_default_sort_mode) - frame_default_sort_mode_column2.pack(side=tk.RIGHT, fill=tk.Y) - - self.open_ffmpeg_label = tk.Label( - frame_default_sort_mode_column1, text="FFmpeg测速:", width=12 - ) - self.open_ffmpeg_label.pack(side=tk.LEFT, padx=4, pady=8) - self.open_ffmpeg_var = tk.BooleanVar(value=config.open_ffmpeg) - self.open_ffmpeg_checkbutton = ttk.Checkbutton( - frame_default_sort_mode_column1, - variable=self.open_ffmpeg_var, - onvalue=True, - offvalue=False, - command=self.update_open_ffmpeg, - text="(需要手动安装)", - ) - self.open_ffmpeg_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) - + frame_m3u = tk.Frame(root) + frame_m3u.pack(fill=tk.X) + frame_proxy_m3u_column1 = tk.Frame(frame_m3u) + frame_proxy_m3u_column1.pack(side=tk.LEFT, fill=tk.Y) + frame_proxy_m3u_column2 = tk.Frame(frame_m3u) + frame_proxy_m3u_column2.pack(side=tk.RIGHT, fill=tk.Y) self.open_m3u_result_label = tk.Label( - frame_default_sort_mode_column2, text="M3U转换:", width=12 + frame_proxy_m3u_column1, text="M3U转换:", width=12 ) self.open_m3u_result_label.pack(side=tk.LEFT, padx=4, pady=8) self.open_m3u_result_var = tk.BooleanVar(value=config.open_m3u_result) self.open_m3u_result_checkbutton = ttk.Checkbutton( - frame_default_sort_mode_column2, + frame_proxy_m3u_column1, variable=self.open_m3u_result_var, onvalue=True, offvalue=False, - command=self.update_open_m3u_result, - text="(开启频道图标)", + command=self.update_open_m3u_result ) self.open_m3u_result_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) - frame_default_speed_params = tk.Frame(root) - frame_default_speed_params.pack(fill=tk.X) - frame_default_speed_params_column1 = tk.Frame( - frame_default_speed_params - ) - frame_default_speed_params_column1.pack(side=tk.LEFT, fill=tk.Y) - frame_default_speed_params_column2 = tk.Frame( - frame_default_speed_params - ) - frame_default_speed_params_column2.pack(side=tk.RIGHT, fill=tk.Y) - - self.open_filter_speed_label = tk.Label( - frame_default_speed_params_column1, text="速率过滤:", width=12 - ) - self.open_filter_speed_label.pack(side=tk.LEFT, padx=4, pady=8) - self.open_filter_speed_var = tk.BooleanVar( - value=config.open_filter_speed + self.open_driver_label = tk.Label( + frame_proxy_m3u_column2, text="浏览器模式:", width=12 ) - self.open_filter_speed_checkbutton = ttk.Checkbutton( - frame_default_speed_params_column1, - variable=self.open_filter_speed_var, + self.open_driver_label.pack(side=tk.LEFT, padx=4, pady=8) + self.open_driver_var = tk.BooleanVar(value=config.open_driver) + self.open_driver_checkbutton = ttk.Checkbutton( + frame_proxy_m3u_column2, + variable=self.open_driver_var, onvalue=True, offvalue=False, - command=self.update_open_filter_speed, - text="(低于最小速率将被过滤)", - ) - self.open_filter_speed_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) - - self.min_speed_label = tk.Label( - frame_default_speed_params_column2, text="最小速率:", width=12 - ) - self.min_speed_label.pack(side=tk.LEFT, padx=4, pady=8) - self.min_speed_entry = tk.Entry( - frame_default_speed_params_column2, width=10 - ) - self.min_speed_entry.pack(side=tk.LEFT, padx=4, pady=8) - self.min_speed_entry.insert(0, config.min_speed) - self.min_speed_entry.bind("", self.update_min_speed) - - frame_default_resolution_params = tk.Frame(root) - frame_default_resolution_params.pack(fill=tk.X) - frame_default_resolution_params_column1 = tk.Frame( - frame_default_resolution_params + command=self.update_open_driver ) - frame_default_resolution_params_column1.pack(side=tk.LEFT, fill=tk.Y) - frame_default_resolution_params_column2 = tk.Frame( - frame_default_resolution_params - ) - frame_default_resolution_params_column2.pack(side=tk.RIGHT, fill=tk.Y) - - self.open_filter_resolution_label = tk.Label( - frame_default_resolution_params_column1, text="分辨率过滤:", width=12 - ) - self.open_filter_resolution_label.pack(side=tk.LEFT, padx=4, pady=8) - self.open_filter_resolution_var = tk.BooleanVar( - value=config.open_filter_resolution - ) - self.open_filter_resolution_checkbutton = ttk.Checkbutton( - frame_default_resolution_params_column1, - variable=self.open_filter_resolution_var, - onvalue=True, - offvalue=False, - command=self.update_open_filter_resolution, - text="(低于最小分辨率将被过滤)", - ) - self.open_filter_resolution_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) - - self.min_resolution_label = tk.Label( - 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, 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) - - frame_default_sort_params = tk.Frame(root) - frame_default_sort_params.pack(fill=tk.X) - frame_default_sort_params_column1 = tk.Frame(frame_default_sort_params) - frame_default_sort_params_column1.pack(side=tk.LEFT, fill=tk.Y) - frame_default_sort_params_column2 = tk.Frame(frame_default_sort_params) - frame_default_sort_params_column2.pack(side=tk.RIGHT, fill=tk.Y) - - self.speed_weight_label = tk.Label( - frame_default_sort_params_column1, text="速率权重:", width=12 - ) - self.speed_weight_label.pack(side=tk.LEFT, padx=4, pady=8) - self.speed_weight_scale = tk.Scale( - frame_default_sort_params_column1, - from_=0, - to=1, - orient=tk.HORIZONTAL, - resolution=0.1, - command=self.update_speed_weight, - ) - self.speed_weight_scale.pack(side=tk.LEFT, padx=4, pady=8) - self.speed_weight_scale.set(config.speed_weight) - - self.delay_weight_label = tk.Label( - frame_default_sort_params_column1, text="响应时间权重:", width=12 - ) - self.delay_weight_label.pack(side=tk.LEFT, padx=4, pady=8) - self.delay_weight_scale = tk.Scale( - frame_default_sort_params_column1, - from_=0, - to=1, - orient=tk.HORIZONTAL, - resolution=0.1, - command=self.update_delay_weight, - ) - self.delay_weight_scale.pack(side=tk.LEFT, padx=4, pady=8) - self.delay_weight_scale.set(config.delay_weight) - - self.resolution_weight_label = tk.Label( - frame_default_sort_params_column2, text="分辨率权重:", width=12 - ) - self.resolution_weight_label.pack(side=tk.LEFT, padx=4, pady=8) - self.resolution_weight_scale = tk.Scale( - frame_default_sort_params_column2, - from_=0, - to=1, - orient=tk.HORIZONTAL, - resolution=0.1, - command=self.update_resolution_weight, - ) - self.resolution_weight_scale.pack(side=tk.LEFT, padx=4, pady=8) - self.resolution_weight_scale.set(config.resolution_weight) + self.open_driver_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) frame_default_open_update_info = tk.Frame(root) frame_default_open_update_info.pack(fill=tk.X) @@ -464,29 +313,40 @@ def init_ui(self, root): ) self.open_empty_category_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) - frame_default_url_keywords_blacklist = tk.Frame(root) - frame_default_url_keywords_blacklist.pack(fill=tk.X) + frame_default_url_keywords = tk.Frame(root) + frame_default_url_keywords.pack(fill=tk.X) + frame_default_url_keywords_column1 = tk.Frame(frame_default_url_keywords) + frame_default_url_keywords_column1.pack(side=tk.LEFT, fill=tk.Y) + frame_default_url_keywords_column2 = tk.Frame(frame_default_url_keywords) + frame_default_url_keywords_column2.pack(side=tk.RIGHT, fill=tk.Y) - self.url_keywords_blacklist_label = tk.Label( - frame_default_url_keywords_blacklist, text="关键字黑名单:", width=12 - ) - 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=5 + self.url_keywords_whitelist_label = tk.Label( + frame_default_url_keywords_column1, text="白名单:", width=12 ) - self.url_keywords_blacklist_text.pack( - side=tk.LEFT, padx=4, pady=8, expand=True, fill=tk.BOTH + self.url_keywords_whitelist_label.pack(side=tk.LEFT, padx=4, pady=8) + self.whitelist_file_button = tk.ttk.Button( + frame_default_url_keywords_column1, + text="编辑", + command=self.edit_whitelist_file, ) - self.url_keywords_blacklist_text.insert( - tk.END, ",".join(config.url_keywords_blacklist) + self.whitelist_file_button.pack(side=tk.LEFT, padx=4, pady=0) + self.url_keywords_blacklist_label = tk.Label( + frame_default_url_keywords_column2, text="黑名单:", width=12 ) - self.url_keywords_blacklist_text.bind( - "", self.update_url_keywords_blacklist + self.url_keywords_blacklist_label.pack(side=tk.LEFT, padx=4, pady=8) + self.blacklist_file_button = tk.ttk.Button( + frame_default_url_keywords_column2, + text="编辑", + command=self.edit_blacklist_file, ) + self.blacklist_file_button.pack(side=tk.LEFT, padx=4, pady=0) def update_open_update(self): config.set("Settings", "open_update", str(self.open_update_var.get())) + def update_open_service(self): + config.set("Settings", "open_service", str(self.open_update_var.get())) + def update_open_use_old_result(self): config.set( "Settings", "open_use_old_result", str(self.open_use_old_result_var.get()) @@ -527,68 +387,15 @@ def update_open_proxy(self): def update_open_keep_all(self): config.set("Settings", "open_keep_all", str(self.open_keep_all_var.get())) - def update_open_sort(self): - config.set("Settings", "open_sort", str(self.open_sort_var.get())) - - def update_sort_timeout(self): - config.set("Settings", "sort_timeout", self.sort_timeout_entry.get()) - - def update_open_ffmpeg(self): - config.set("Settings", "open_ffmpeg", str(self.open_ffmpeg_var.get())) - def update_open_m3u_result(self): config.set("Settings", "open_m3u_result", str(self.open_m3u_result_var.get())) - def update_open_filter_speed(self): - config.set( - "Settings", - "open_filter_speed", - str(self.open_filter_speed_var.get()), - ) - - def update_min_speed(self, event): - config.set("Settings", "min_speed", self.min_speed_entry.get()) - - def update_open_filter_resolution(self): - config.set( - "Settings", - "open_filter_resolution", - str(self.open_filter_resolution_var.get()), - ) - - def update_min_resolution(self, event): - config.set("Settings", "min_resolution", self.min_resolution_entry.get()) + def update_request_timeout(self, event): + config.set("Settings", "request_timeout", self.request_timeout_entry.get()) def update_urls_limit(self, event): config.set("Settings", "urls_limit", self.urls_limit_entry.get()) - def update_speed_weight(self, event): - weight1 = self.speed_weight_scale.get() - weight2 = 1 - weight1 - self.delay_weight_scale.set(weight2 / 2) - self.resolution_weight_scale.set(weight2 / 2) - config.set("Settings", "speed_weight", str(weight1)) - config.set("Settings", "delay_weight", str(weight2 / 2)) - config.set("Settings", "resolution_weight", str(weight2 / 2)) - - def update_delay_weight(self, event): - weight1 = self.delay_weight_scale.get() - weight2 = 1 - weight1 - self.speed_weight_scale.set(weight2 / 2) - self.resolution_weight_scale.set(weight2 / 2) - config.set("Settings", "delay_weight", str(weight1)) - config.set("Settings", "speed_weight", str(weight2 / 2)) - config.set("Settings", "resolution_weight", str(weight2 / 2)) - - def update_resolution_weight(self, event): - weight1 = self.resolution_weight_scale.get() - weight2 = 1 - weight1 - self.speed_weight_scale.set(weight2 / 2) - self.delay_weight_scale.set(weight2) - config.set("Settings", "resolution_weight", str(weight1)) - config.set("Settings", "speed_weight", str(weight2 / 2)) - config.set("Settings", "delay_weight", str(weight2 / 2)) - def update_open_update_time(self): config.set("Settings", "open_update_time", str(self.open_update_time_var.get())) @@ -603,23 +410,18 @@ def update_open_empty_category(self): def update_ipv_type(self, event): config.set("Settings", "ipv_type", self.ipv_type_combo.get()) - def update_url_keywords_blacklist(self, event): - config.set( - "Settings", - "url_keywords_blacklist", - self.url_keywords_blacklist_text.get(1.0, tk.END), - ) + def edit_whitelist_file(self): + if os.path.exists(constants.whitelist_path): + os.system(f'notepad.exe {constants.whitelist_path}') - def update_url_keywords_blacklist(self, event): - config.set( - "Settings", - "url_keywords_blacklist", - self.url_keywords_blacklist_text.get(1.0, tk.END), - ) + def edit_blacklist_file(self): + if os.path.exists(constants.blacklist_path): + os.system(f'notepad.exe {constants.blacklist_path}') def change_entry_state(self, state): for entry in [ "open_update_checkbutton", + "open_service_checkbutton", "open_use_old_result_checkbutton", "open_use_cache_checkbutton", "open_request_checkbutton", @@ -630,22 +432,13 @@ def change_entry_state(self, state): "final_file_entry", "final_file_button", "open_keep_all_checkbutton", - "open_sort_checkbutton", - "sort_timeout_entry", - "open_ffmpeg_checkbutton", "open_m3u_result_checkbutton", - "open_filter_speed_checkbutton", - "min_speed_entry", - "open_filter_resolution_checkbutton", - "min_resolution_entry", "urls_limit_entry", - "speed_weight_scale", - "delay_weight_scale", - "resolution_weight_scale", "open_update_time_checkbutton", "open_url_info_checkbutton", "open_empty_category_checkbutton", "ipv_type_combo", - "url_keywords_blacklist_text", + "whitelist_file_button", + "blacklist_file_button", ]: getattr(self, entry).config(state=state) diff --git a/tkinter_ui/speed.py b/tkinter_ui/speed.py new file mode 100644 index 0000000000..d163963469 --- /dev/null +++ b/tkinter_ui/speed.py @@ -0,0 +1,167 @@ +import tkinter as tk +from tkinter import ttk + +from utils.config import config + + +class SpeedUI: + def init_ui(self, root=None): + """ + Init speed UI + """ + 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_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_column1, + variable=self.open_sort_var, + onvalue=True, + offvalue=False, + command=self.update_open_sort, + ) + self.open_sort_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) + + self.sort_timeout_label = tk.Label( + frame_default_sort_column2, text="响应超时(s):", width=12 + ) + self.sort_timeout_label.pack(side=tk.LEFT, padx=4, pady=8) + self.sort_timeout_entry = tk.Entry(frame_default_sort_column2, width=10) + 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) + + frame_default_sort_mode = tk.Frame(root) + frame_default_sort_mode.pack(fill=tk.X) + frame_default_sort_mode_column1 = tk.Frame(frame_default_sort_mode) + frame_default_sort_mode_column1.pack(side=tk.LEFT, fill=tk.Y) + frame_default_sort_mode_column2 = tk.Frame(frame_default_sort_mode) + frame_default_sort_mode_column2.pack(side=tk.RIGHT, fill=tk.Y) + + frame_default_speed_params = tk.Frame(root) + frame_default_speed_params.pack(fill=tk.X) + frame_default_speed_params_column1 = tk.Frame( + frame_default_speed_params + ) + frame_default_speed_params_column1.pack(side=tk.LEFT, fill=tk.Y) + frame_default_speed_params_column2 = tk.Frame( + frame_default_speed_params + ) + frame_default_speed_params_column2.pack(side=tk.RIGHT, fill=tk.Y) + + self.open_filter_speed_label = tk.Label( + frame_default_speed_params_column1, text="速率过滤:", width=12 + ) + self.open_filter_speed_label.pack(side=tk.LEFT, padx=4, pady=8) + self.open_filter_speed_var = tk.BooleanVar( + value=config.open_filter_speed + ) + self.open_filter_speed_checkbutton = ttk.Checkbutton( + frame_default_speed_params_column1, + variable=self.open_filter_speed_var, + onvalue=True, + offvalue=False, + command=self.update_open_filter_speed + ) + self.open_filter_speed_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) + + self.min_speed_label = tk.Label( + frame_default_speed_params_column2, text="最小速率(M/s):", width=12 + ) + self.min_speed_label.pack(side=tk.LEFT, padx=4, pady=8) + self.min_speed_entry = tk.Entry( + frame_default_speed_params_column2, width=10 + ) + self.min_speed_entry.pack(side=tk.LEFT, padx=4, pady=8) + self.min_speed_entry.insert(0, config.min_speed) + self.min_speed_entry.bind("", self.update_min_speed) + + frame_default_resolution_params = tk.Frame(root) + frame_default_resolution_params.pack(fill=tk.X) + frame_default_resolution_params_column1 = tk.Frame( + frame_default_resolution_params + ) + frame_default_resolution_params_column1.pack(side=tk.LEFT, fill=tk.Y) + frame_default_resolution_params_column2 = tk.Frame( + frame_default_resolution_params + ) + frame_default_resolution_params_column2.pack(side=tk.RIGHT, fill=tk.Y) + + self.open_filter_resolution_label = tk.Label( + frame_default_resolution_params_column1, text="分辨率过滤:", width=12 + ) + self.open_filter_resolution_label.pack(side=tk.LEFT, padx=4, pady=8) + self.open_filter_resolution_var = tk.BooleanVar( + value=config.open_filter_resolution + ) + self.open_filter_resolution_checkbutton = ttk.Checkbutton( + frame_default_resolution_params_column1, + variable=self.open_filter_resolution_var, + onvalue=True, + offvalue=False, + command=self.update_open_filter_resolution + ) + self.open_filter_resolution_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) + + self.min_resolution_label = tk.Label( + 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, 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) + + frame_default_sort_params = tk.Frame(root) + frame_default_sort_params.pack(fill=tk.X) + frame_default_sort_params_column1 = tk.Frame(frame_default_sort_params) + frame_default_sort_params_column1.pack(side=tk.LEFT, fill=tk.Y) + frame_default_sort_params_column2 = tk.Frame(frame_default_sort_params) + frame_default_sort_params_column2.pack(side=tk.RIGHT, fill=tk.Y) + + def update_open_sort(self): + config.set("Settings", "open_sort", str(self.open_sort_var.get())) + + def update_sort_timeout(self): + config.set("Settings", "sort_timeout", self.sort_timeout_entry.get()) + + def update_open_filter_speed(self): + config.set( + "Settings", + "open_filter_speed", + str(self.open_filter_speed_var.get()), + ) + + def update_min_speed(self, event): + config.set("Settings", "min_speed", self.min_speed_entry.get()) + + def update_open_filter_resolution(self): + config.set( + "Settings", + "open_filter_resolution", + str(self.open_filter_resolution_var.get()), + ) + + def update_min_resolution(self, event): + config.set("Settings", "min_resolution", self.min_resolution_entry.get()) + + def change_entry_state(self, state): + for entry in [ + "open_sort_checkbutton", + "sort_timeout_entry", + "open_filter_speed_checkbutton", + "min_speed_entry", + "open_filter_resolution_checkbutton", + "min_resolution_entry" + ]: + getattr(self, entry).config(state=state) diff --git a/tkinter_ui/subscribe.py b/tkinter_ui/subscribe.py index 323c857a91..3c2fda914a 100644 --- a/tkinter_ui/subscribe.py +++ b/tkinter_ui/subscribe.py @@ -1,10 +1,10 @@ +import os +import os.path import tkinter as tk -from tkinter import scrolledtext from tkinter import ttk import utils.constants as constants from utils.config import config -from utils.tools import get_urls_from_file class SubscribeUI: @@ -31,33 +31,32 @@ def init_ui(self, root): frame_subscribe_subscribe_urls = tk.Frame(root) frame_subscribe_subscribe_urls.pack(fill=tk.X) + frame_subscribe_urls_column1 = tk.Frame(frame_subscribe_subscribe_urls) + frame_subscribe_urls_column1.pack(side=tk.LEFT, fill=tk.Y) + frame_subscribe_urls_column2 = tk.Frame(frame_subscribe_subscribe_urls) + frame_subscribe_urls_column2.pack(side=tk.LEFT, fill=tk.Y) self.subscribe_urls_label = tk.Label( - frame_subscribe_subscribe_urls, text="订阅源:", width=9 + frame_subscribe_urls_column1, text="订阅源:", width=9 ) self.subscribe_urls_label.pack(side=tk.LEFT, padx=4, pady=8) - self.subscribe_urls_text = scrolledtext.ScrolledText( - frame_subscribe_subscribe_urls, height=40 + self.subscribe_file_button = tk.ttk.Button( + frame_subscribe_urls_column2, + text="编辑", + command=self.edit_subscribe_file, ) - self.subscribe_urls_text.pack( - side=tk.LEFT, padx=4, pady=8, expand=True, fill=tk.BOTH - ) - self.subscribe_urls_text.insert(tk.END, ",".join(get_urls_from_file(constants.subscribe_path))) - self.subscribe_urls_text.bind("", self.update_subscribe_urls) + self.subscribe_file_button.pack(side=tk.LEFT, padx=4, pady=0) def update_open_subscribe(self): config.set("Settings", "open_subscribe", str(self.open_subscribe_var.get())) - def update_subscribe_urls(self, event): - config.set( - "Settings", - "subscribe_urls", - self.subscribe_urls_text.get(1.0, tk.END), - ) + def edit_subscribe_file(self): + if os.path.exists(constants.subscribe_path): + os.system(f'notepad.exe {constants.subscribe_path}') def change_entry_state(self, state): for entry in [ "open_subscribe_checkbutton", - "subscribe_urls_text", + "subscribe_file_button", ]: getattr(self, entry).config(state=state) diff --git a/tkinter_ui/tkinter_ui.py b/tkinter_ui/tkinter_ui.py index 22ec51b6d5..824ec7d2d8 100644 --- a/tkinter_ui/tkinter_ui.py +++ b/tkinter_ui/tkinter_ui.py @@ -13,6 +13,7 @@ import webbrowser from about import AboutUI from default import DefaultUI +from speed import SpeedUI from prefer import PreferUI from multicast import MulticastUI from hotel import HotelUI @@ -30,6 +31,7 @@ def __init__(self, root): self.version = info.get("version", "") self.about_ui = AboutUI() self.default_ui = DefaultUI() + self.speed_ui = SpeedUI() self.prefer_ui = PreferUI() self.multicast_ui = MulticastUI() self.hotel_ui = HotelUI() @@ -44,39 +46,39 @@ def view_result_link_callback(self, event): def save_config(self): config_values = { - "open_update": self.default_ui.open_update_var.get(), - "open_use_old_result": self.default_ui.open_use_old_result_var.get(), - "source_file": self.default_ui.source_file_entry.get(), - "final_file": self.default_ui.final_file_entry.get(), - "urls_limit": self.default_ui.urls_limit_entry.get(), "open_driver": self.default_ui.open_driver_var.get(), - "open_proxy": self.default_ui.open_proxy_var.get(), + "open_filter_resolution": self.speed_ui.open_filter_resolution_var.get(), + "open_hotel": self.hotel_ui.open_hotel_var.get(), + "open_hotel_foodie": self.hotel_ui.open_hotel_foodie_var.get(), + "open_hotel_fofa": self.hotel_ui.open_hotel_fofa_var.get(), "open_keep_all": self.default_ui.open_keep_all_var.get(), - "open_sort": self.default_ui.open_sort_var.get(), - "open_filter_resolution": self.default_ui.open_filter_resolution_var.get(), - "min_resolution": self.default_ui.min_resolution_entry.get(), - "delay_weight": self.default_ui.delay_weight_scale.get(), - "resolution_weight": self.default_ui.resolution_weight_scale.get(), - "ipv_type": self.default_ui.ipv_type_combo.get(), - "url_keywords_blacklist": self.default_ui.url_keywords_blacklist_text.get( - 1.0, tk.END - ), - "open_subscribe": self.subscribe_ui.open_subscribe_var.get(), - "subscribe_urls": self.subscribe_ui.subscribe_urls_text.get(1.0, tk.END), "open_multicast": self.multicast_ui.open_multicast_var.get(), "open_multicast_foodie": self.multicast_ui.open_multicast_foodie_var.get(), "open_multicast_fofa": self.multicast_ui.open_multicast_fofa_var.get(), - "multicast_region_list": self.multicast_ui.region_list_combo.get(), - "multicast_page_num": self.multicast_ui.page_num_entry.get(), - "open_hotel": self.hotel_ui.open_hotel_var.get(), - "open_hotel_foodie": self.hotel_ui.open_hotel_foodie_var.get(), - "open_hotel_fofa": self.hotel_ui.open_hotel_fofa_var.get(), + "open_online_search": self.online_search_ui.open_online_search_var.get(), + "open_proxy": self.default_ui.open_proxy_var.get(), + "open_request": self.default_ui.open_request_var.get(), + "open_service": self.default_ui.open_service_var.get(), + "open_sort": self.speed_ui.open_sort_var.get(), + "open_subscribe": self.subscribe_ui.open_subscribe_var.get(), + "open_update": self.default_ui.open_update_var.get(), + "open_update_time": self.default_ui.open_update_time_var.get(), + "open_url_info": self.default_ui.open_url_info_var.get(), + "open_use_cache": self.default_ui.open_use_cache_var.get(), + "open_use_old_result": self.default_ui.open_use_old_result_var.get(), + "final_file": self.default_ui.final_file_entry.get(), "hotel_region_list": self.hotel_ui.region_list_combo.get(), "hotel_page_num": self.hotel_ui.page_num_entry.get(), - "open_online_search": self.online_search_ui.open_online_search_var.get(), + "ipv_type": self.default_ui.ipv_type_combo.get(), + "min_resolution": self.speed_ui.min_resolution_entry.get(), + "multicast_region_list": self.multicast_ui.region_list_combo.get(), + "multicast_page_num": self.multicast_ui.page_num_entry.get(), "online_search_page_num": self.online_search_ui.page_num_entry.get(), "recent_days": self.online_search_ui.recent_days_entry.get(), - "open_update_time": self.default_ui.open_update_time_var.get(), + "request_timeout": self.default_ui.request_timeout_entry.get(), + "sort_timeout": self.speed_ui.sort_timeout_entry.get(), + "source_file": self.default_ui.source_file_entry.get(), + "urls_limit": self.default_ui.urls_limit_entry.get(), } for key, value in config_values.items(): @@ -86,6 +88,7 @@ def save_config(self): def change_state(self, state): self.default_ui.change_entry_state(state=state) + self.speed_ui.change_entry_state(state=state) self.prefer_ui.change_entry_state(state=state) self.multicast_ui.change_entry_state(state=state) self.hotel_ui.change_entry_state(state=state) @@ -152,6 +155,7 @@ def init_UI(self): notebook.pack(fill="both", padx=10, pady=5) frame_default = tk.ttk.Frame(notebook) + frame_speed = tk.ttk.Frame(notebook) frame_prefer = tk.ttk.Frame(notebook) frame_hotel = tk.ttk.Frame(notebook) frame_multicast = tk.ttk.Frame(notebook) @@ -162,6 +166,10 @@ def init_UI(self): resource_path("static/images/settings_icon.png") ).resize((16, 16)) settings_icon = ImageTk.PhotoImage(settings_icon_source) + speed_icon_source = Image.open( + resource_path("static/images/speed_icon.png") + ).resize((16, 16)) + speed_icon = ImageTk.PhotoImage(speed_icon_source) prefer_icon_source = Image.open( resource_path("static/images/prefer_icon.png") ).resize((16, 16)) @@ -186,6 +194,7 @@ def init_UI(self): notebook.add( frame_default, text="通用设置", image=settings_icon, compound=tk.LEFT ) + notebook.add(frame_speed, text="测速设置", image=speed_icon, compound=tk.LEFT) notebook.add(frame_prefer, text="偏好设置", image=prefer_icon, compound=tk.LEFT) notebook.add(frame_hotel, text="酒店源", image=hotel_icon, compound=tk.LEFT) notebook.add( @@ -202,6 +211,7 @@ def init_UI(self): ) notebook.settings_icon = settings_icon + notebook.speed_icon = speed_icon notebook.prefer_icon = prefer_icon notebook.hotel_icon = hotel_icon notebook.multicast_icon = multicast_icon @@ -209,6 +219,7 @@ def init_UI(self): notebook.online_search_icon = online_search_icon self.default_ui.init_ui(frame_default) + self.speed_ui.init_ui(frame_speed) self.prefer_ui.init_ui(frame_prefer) self.multicast_ui.init_ui(frame_multicast) self.hotel_ui.init_ui(frame_hotel) @@ -254,8 +265,8 @@ def init_UI(self): def get_root_location(root): screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() - width = 650 - height = 750 + width = 500 + height = 600 x = (screen_width / 2) - (width / 2) y = (screen_height / 2) - (height / 2) return (width, height, x, y) diff --git a/tkinter_ui/tkinter_ui.spec b/tkinter_ui/tkinter_ui.spec index 7c8ceeb12d..4afc916e5c 100644 --- a/tkinter_ui/tkinter_ui.spec +++ b/tkinter_ui/tkinter_ui.spec @@ -1,7 +1,7 @@ # -*- mode: python ; coding: utf-8 -*- a = Analysis( - ['tkinter_ui.py', 'about.py', 'default.py', 'prefer.py', 'multicast.py', 'hotel.py', 'subscribe.py', 'online_search.py'], + ['tkinter_ui.py', 'about.py', 'default.py', 'speed.py', 'prefer.py', 'multicast.py', 'hotel.py', 'subscribe.py', 'online_search.py'], pathex=[], binaries=[], datas=[ @@ -18,6 +18,7 @@ a = Analysis( ('../static/images/favicon.ico', 'static/images'), ('../static/images/alipay.jpg', 'static/images'), ('../static/images/settings_icon.png', 'static/images'), + ('../static/images/speed_icon.png', 'static/images'), ('../static/images/prefer_icon.png', 'static/images'), ('../static/images/hotel_icon.png', 'static/images'), ('../static/images/multicast_icon.png', 'static/images'), @@ -25,6 +26,7 @@ a = Analysis( ('../static/images/online_search_icon.png', 'static/images'), ('about.py', '.'), ('default.py', '.'), + ('speed.py', '.'), ('prefer.py', '.'), ('multicast.py', '.'), ('hotel.py', '.'), diff --git a/updates/online_search/request.py b/updates/online_search/request.py index 0992c9e4b6..b971afe549 100644 --- a/updates/online_search/request.py +++ b/updates/online_search/request.py @@ -1,28 +1,30 @@ -from utils.config import config +from concurrent.futures import ThreadPoolExecutor +from time import time + +from tqdm.asyncio import tqdm_asyncio + import utils.constants as constants +from driver.setup import setup_driver +from driver.utils import search_submit +from requests_custom.utils import get_soup_requests, close_session +from updates.proxy import get_proxy, get_proxy_next from utils.channel import ( format_channel_name, get_results_from_soup, get_results_from_soup_requests, ) +from utils.config import config +from utils.retry import ( + retry_func, + find_clickable_element_with_retry, +) from utils.tools import ( - check_url_by_patterns, get_pbar_remaining, get_soup, format_url_with_cache, add_url_info, + get_urls_from_file ) -from updates.proxy import get_proxy, get_proxy_next -from time import time -from driver.setup import setup_driver -from driver.utils import search_submit -from utils.retry import ( - retry_func, - find_clickable_element_with_retry, -) -from tqdm.asyncio import tqdm_asyncio -from concurrent.futures import ThreadPoolExecutor -from requests_custom.utils import get_soup_requests, close_session if config.open_driver: try: @@ -47,6 +49,8 @@ async def get_channels_by_online_search(names, callback=None): proxy = await get_proxy(pageUrl, best=True, with_test=True) start_time = time() online_search_name = constants.origin_map["online_search"] + whitelist = get_urls_from_file(constants.whitelist_path) + blacklist = get_urls_from_file(constants.blacklist_path) def process_channel_by_online_search(name): nonlocal proxy @@ -136,7 +140,7 @@ def process_channel_by_online_search(name): driver, ( By.XPATH, - f'//a[contains(@href, "={page+1}") and contains(@href, "{name}")]', + f'//a[contains(@href, "={page + 1}") and contains(@href, "{name}")]', ), retries=1, ) @@ -151,7 +155,7 @@ def process_channel_by_online_search(name): continue for result in results: url, date, resolution = result - if url and check_url_by_patterns(url): + if url: url = add_url_info(url, online_search_name) url = format_url_with_cache(url) info_list.append((url, date, resolution)) diff --git a/utils/channel.py b/utils/channel.py index 5178fc4caa..76fdbd3673 100644 --- a/utils/channel.py +++ b/utils/channel.py @@ -19,7 +19,8 @@ ) from utils.tools import ( get_name_url, - check_url_by_patterns, + check_url_by_keywords, + check_url_ipv_type, get_total_urls, process_nested_dict, add_url_info, @@ -219,6 +220,8 @@ def get_channel_multicast_result(result, search_result): """ info_result = {} multicast_name = constants.origin_map["multicast"] + whitelist = get_urls_from_file(constants.whitelist_path) + blacklist = get_urls_from_file(constants.blacklist_path) for name, result_obj in result.items(): info_list = [ ( @@ -242,7 +245,10 @@ def get_channel_multicast_result(result, search_result): if result_type in search_result[result_region] for ip in get_multicast_ip_list(result_type_urls) or [] for url, date, resolution in search_result[result_region][result_type] - if check_url_by_patterns(f"http://{url}/rtp/{ip}") + if (whitelist and check_url_by_keywords(f"http://{url}/rtp/{ip}", whitelist)) or + ( + check_url_ipv_type(f"http://{url}/rtp/{ip}") and not check_url_by_keywords( + f"http://{url}/rtp/{ip}", blacklist)) ] info_result[name] = info_list return info_result @@ -430,7 +436,7 @@ def init_info_data(data, cate, name): data[cate][name] = [] -def append_data_to_info_data(info_data, cate, name, data, origin=None, check=True): +def append_data_to_info_data(info_data, cate, name, data, origin=None, check=True, whitelist=None, blacklist=None): """ Append channel data to total info data """ @@ -446,10 +452,13 @@ def append_data_to_info_data(info_data, cate, name, data, origin=None, check=Tru pure_url = url.partition("$")[0] if pure_url in urls: continue + if whitelist and check_url_by_keywords(url, whitelist): + url_origin = "important" if ( url_origin == "important" or (not check) - or (check and check_url_by_patterns(pure_url)) + or ( + check and check_url_ipv_type(pure_url) and not check_url_by_keywords(url, blacklist)) ): info_data[cate][name].append((url, date, resolution, url_origin)) urls.append(pure_url) @@ -464,7 +473,7 @@ def get_origin_method_name(method): return "hotel" if method.startswith("hotel_") else method -def append_old_data_to_info_data(info_data, cate, name, data): +def append_old_data_to_info_data(info_data, cate, name, data, whitelist=None, blacklist=None): """ Append history channel data to total info data """ @@ -473,6 +482,8 @@ def append_old_data_to_info_data(info_data, cate, name, data): cate, name, data, + whitelist=whitelist, + blacklist=blacklist ) print("History:", len(data), end=", ") @@ -497,11 +508,13 @@ def append_total_data( ("subscribe", subscribe_result), ("online_search", online_search_result), ] + whitelist = get_urls_from_file(constants.whitelist_path) + blacklist = get_urls_from_file(constants.blacklist_path) for cate, channel_obj in items: for name, old_info_list in channel_obj.items(): print(f"{name}:", end=" ") if config.open_use_old_result and old_info_list: - append_old_data_to_info_data(data, cate, name, old_info_list) + append_old_data_to_info_data(data, cate, name, old_info_list, whitelist=whitelist, blacklist=blacklist) for method, result in total_result: if config.open_method[method]: origin_method = get_origin_method_name(method) @@ -509,7 +522,7 @@ def append_total_data( continue name_results = get_channel_results_by_name(name, result) append_data_to_info_data( - data, cate, name, name_results, origin=origin_method + data, cate, name, name_results, origin=origin_method, whitelist=whitelist, blacklist=blacklist ) print(f"{method.capitalize()}:", len(name_results), end=", ") print( @@ -534,7 +547,7 @@ def append_total_data( data, extra_cate, name, old_info_list ) append_data_to_info_data( - data, extra_cate, name, urls, origin=origin_method + data, extra_cate, name, urls, origin=origin_method, whitelist=whitelist, blacklist=blacklist ) print(name, f"{method.capitalize()}:", len(urls), end=", ") print( @@ -549,10 +562,7 @@ async def process_sort_channel_list(data, ipv6=False, callback=None): """ ipv6_proxy = None if (not config.open_ipv6 or ipv6) else constants.ipv6_proxy need_sort_data = copy.deepcopy(data) - whitelist_urls = get_urls_from_file(constants.whitelist_path) - if whitelist_urls: - print(f"Found {len(whitelist_urls)} whitelist urls") - process_nested_dict(need_sort_data, seen=set(whitelist_urls), flag=r"cache:(.*)", force_str="!") + process_nested_dict(need_sort_data, seen=set(), flag=r"cache:(.*)", force_str="!") result = {} semaphore = asyncio.Semaphore(5) @@ -576,7 +586,7 @@ async def limited_get_speed(info, ipv6_proxy, callback): logger = get_logger(constants.sort_log_path, level=INFO, init=True) for cate, obj in data.items(): for name, info_list in obj.items(): - info_list = sort_urls(name, info_list, logger=logger, whitelist=whitelist_urls) + info_list = sort_urls(name, info_list, logger=logger) append_data_to_info_data( result, cate, diff --git a/utils/config.py b/utils/config.py index 93c22202b1..0b6ae68977 100644 --- a/utils/config.py +++ b/utils/config.py @@ -166,16 +166,6 @@ def open_url_info(self): def recent_days(self): return self.config.getint("Settings", "recent_days", fallback=30) - @property - def url_keywords_blacklist(self): - return [ - keyword.strip() - for keyword in self.config.get( - "Settings", "url_keywords_blacklist", fallback="" - ).split(",") - if keyword.strip() - ] - @property def source_file(self): return self.config.get("Settings", "source_file", fallback="config/demo.txt") @@ -247,10 +237,6 @@ def open_use_old_result(self): def open_sort(self): return self.config.getboolean("Settings", "open_sort", fallback=True) - @property - def open_ffmpeg(self): - return self.config.getboolean("Settings", "open_ffmpeg", fallback=True) - @property def open_update_time(self): return self.config.getboolean("Settings", "open_update_time", fallback=True) @@ -305,18 +291,6 @@ def multicast_page_num(self): def online_search_page_num(self): return config.getint("Settings", "online_search_page_num", fallback=1) - @property - def delay_weight(self): - return self.config.getfloat("Settings", "delay_weight", fallback=0.5) - - @property - def speed_weight(self): - return self.config.getfloat("Settings", "speed_weight", fallback=0.5) - - @property - def resolution_weight(self): - return self.config.getfloat("Settings", "resolution_weight", fallback=0.5) - @property def open_empty_category(self): return self.config.getboolean("Settings", "open_empty_category", fallback=True) diff --git a/utils/constants.py b/utils/constants.py index bf6463dde6..73df30397d 100644 --- a/utils/constants.py +++ b/utils/constants.py @@ -6,6 +6,8 @@ whitelist_path = os.path.join(config_path, "whitelist.txt") +blacklist_path = os.path.join(config_path, "blacklist.txt") + subscribe_path = os.path.join(config_path, "subscribe.txt") result_path = os.path.join(output_path, "result_new.txt") diff --git a/utils/speed.py b/utils/speed.py index 91a8550bdd..5896735eb4 100644 --- a/utils/speed.py +++ b/utils/speed.py @@ -8,7 +8,7 @@ from aiohttp import ClientSession, TCPConnector from utils.config import config -from utils.tools import is_ipv6, remove_cache_info, get_resolution_value +from utils.tools import is_ipv6, remove_cache_info async def get_speed_with_download(url: str, timeout: int = config.sort_timeout) -> dict[str, float | None]: @@ -207,14 +207,12 @@ async def get_speed(url, ipv6_proxy=None, callback=None): callback() -def sort_urls(name, data, logger=None, whitelist=None): +def sort_urls(name, data, logger=None): """ Sort the urls with info """ filter_data = [] for url, date, resolution, origin in data: - if whitelist and url in whitelist: - origin = "important" result = { "url": remove_cache_info(url), "date": date, @@ -249,15 +247,11 @@ def sort_urls(name, data, logger=None, whitelist=None): filter_data.append(result) def combined_key(item): - speed, delay, resolution, origin = item["speed"], item["delay"], item["resolution"], item["origin"] + speed, origin = item["speed"], item["origin"] if origin == "important": return float("inf") else: - return ( - config.speed_weight * (speed * 1024 if speed is not None else float("-inf")) - - config.delay_weight * (delay if delay is not None else float("inf")) - + config.resolution_weight * (get_resolution_value(resolution) if resolution else 0) - ) + return speed if speed is not None else float("-inf") filter_data.sort(key=combined_key, reverse=True) return [ diff --git a/utils/tools.py b/utils/tools.py index 8b38b4fedc..203876d64d 100644 --- a/utils/tools.py +++ b/utils/tools.py @@ -291,27 +291,14 @@ def check_url_ipv_type(url): ) -def check_by_url_keywords_blacklist(url): +def check_url_by_keywords(url, keywords=None): """ - Check by URL blacklist keywords + Check by URL keywords """ - return not any(keyword in url for keyword in config.url_keywords_blacklist) - - -def check_url_by_patterns(url): - """ - Check the url by patterns - """ - return check_url_ipv_type(url) and check_by_url_keywords_blacklist(url) - - -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_url_keywords_blacklist(url)] - return urls + if not keywords: + return True + else: + return any(keyword in url for keyword in keywords) def merge_objects(*objects): @@ -562,6 +549,9 @@ def get_urls_from_file(path: str) -> list: if os.path.exists(real_path): with open(real_path, "r", encoding="utf-8") as f: for line in f: + line = line.strip() + if line.startswith("#"): + continue match = re.search(url_pattern, line) if match: urls.append(match.group().strip()) @@ -578,6 +568,9 @@ def get_name_urls_from_file(path: str) -> dict[str, list]: if os.path.exists(real_path): with open(real_path, "r", encoding="utf-8") as f: for line in f: + line = line.strip() + if line.startswith("#"): + continue name_url = get_name_url(line, pattern=txt_pattern) if name_url and name_url[0]: name = name_url[0]["name"] From 5ce3c4db8049230852e5489097563040ffa7f093 Mon Sep 17 00:00:00 2001 From: "guorong.zheng" <360996299@qq.com> Date: Mon, 16 Dec 2024 17:13:36 +0800 Subject: [PATCH 3/6] feat:ipv6_support force config --- README.md | 1 + README_en.md | 1 + config/config.ini | 1 + docs/config.md | 1 + docs/config_en.md | 1 + main.py | 2 +- tkinter_ui/default.py | 32 ++++++++++++++++++++++++++++++-- tkinter_ui/tkinter_ui.py | 1 + utils/config.py | 4 ++++ 9 files changed, 41 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 11cf7d08d4..4bb13d9a9a 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,7 @@ https://cdn.jsdelivr.net/gh/Guovin/iptv-api@gd/source.json | hotel_region_list | 酒店源地区列表,"全部"表示所有地区 | 全部 | | ipv4_num | 结果中偏好的 IPv4 接口数量 | 5 | | ipv6_num | 结果中偏好的 IPv6 接口数量 | 5 | +| ipv6_support | 强制认为当前网络支持IPv6,跳过检测 | False | | ipv_type | 生成结果中接口的协议类型,可选值:ipv4、ipv6、全部、all | 全部 | | ipv_type_prefer | 接口协议类型偏好,优先将该类型的接口排在结果前面,可选值:IPv4、IPv6、自动、auto | 自动 | | min_resolution | 接口最小分辨率,需要开启 open_filter_resolution 才能生效 | 1920x1080 | diff --git a/README_en.md b/README_en.md index 7822ef01f2..d57d09c004 100644 --- a/README_en.md +++ b/README_en.md @@ -173,6 +173,7 @@ https://cdn.jsdelivr.net/gh/Guovin/iptv-api@gd/source.json | hotel_region_list | List of hotel source regions, 'all' indicates all regions | all | | ipv4_num | The preferred number of IPv4 interfaces in the result | 5 | | ipv6_num | The preferred number of IPv6 interfaces in the result | 5 | +| ipv6_support | It is forced to consider that the current network supports IPv6 and skip the check | False | | ipv_type | The protocol type of interface in the generated result, optional values: ipv4, ipv6, all | all | | ipv_type_prefer | Interface protocol type preference, prioritize interfaces of this type in the results, optional values: IPv4, IPv6, auto | auto | | min_resolution | Minimum interface resolution, requires enabling open_filter_resolution to take effect | 1920x1080 | diff --git a/config/config.ini b/config/config.ini index f677f9cdbb..b71ba738b4 100644 --- a/config/config.ini +++ b/config/config.ini @@ -28,6 +28,7 @@ hotel_page_num = 1 hotel_region_list = 全部 ipv4_num = 5 ipv6_num = 5 +ipv6_support = False ipv_type = 全部 ipv_type_prefer = 自动 min_resolution = 1920x1080 diff --git a/docs/config.md b/docs/config.md index dea3d5fbe6..6c30ee8dd9 100644 --- a/docs/config.md +++ b/docs/config.md @@ -29,6 +29,7 @@ | hotel_region_list | 酒店源地区列表,"全部"表示所有地区 | 全部 | | ipv4_num | 结果中偏好的 IPv4 接口数量 | 5 | | ipv6_num | 结果中偏好的 IPv6 接口数量 | 5 | +| ipv6_support | 强制认为当前网络支持IPv6,跳过检测 | False | | ipv_type | 生成结果中接口的协议类型,可选值:ipv4、ipv6、全部、all | 全部 | | ipv_type_prefer | 接口协议类型偏好,优先将该类型的接口排在结果前面,可选值:IPv4、IPv6、自动、auto | 自动 | | min_resolution | 接口最小分辨率,需要开启 open_filter_resolution 才能生效 | 1920x1080 | diff --git a/docs/config_en.md b/docs/config_en.md index 9af3ed04ae..98b2973aee 100644 --- a/docs/config_en.md +++ b/docs/config_en.md @@ -29,6 +29,7 @@ | hotel_region_list | List of hotel source regions, 'all' indicates all regions | all | | ipv4_num | The preferred number of IPv4 interfaces in the result | 5 | | ipv6_num | The preferred number of IPv6 interfaces in the result | 5 | +| ipv6_support | It is forced to consider that the current network supports IPv6 and skip the check | False | | ipv_type | The protocol type of interface in the generated result, optional values: ipv4, ipv6, all | all | | ipv_type_prefer | Interface protocol type preference, prioritize interfaces of this type in the results, optional values: IPv4, IPv6, auto | auto | | min_resolution | Minimum interface resolution, requires enabling open_filter_resolution to take effect | 1920x1080 | diff --git a/main.py b/main.py index 477a63a127..cb43e5e4fa 100644 --- a/main.py +++ b/main.py @@ -129,7 +129,7 @@ async def main(self): self.online_search_result, ) channel_data_cache = copy.deepcopy(self.channel_data) - ipv6_support = check_ipv6_support() + ipv6_support = config.ipv6_support or check_ipv6_support() open_sort = config.open_sort if open_sort: urls_total = self.get_urls_len() diff --git a/tkinter_ui/default.py b/tkinter_ui/default.py index 304bb02433..f6c0ed3475 100644 --- a/tkinter_ui/default.py +++ b/tkinter_ui/default.py @@ -298,14 +298,22 @@ def init_ui(self, root): frame_default_open_empty_category = tk.Frame(root) frame_default_open_empty_category.pack(fill=tk.X) + frame_default_open_empty_category_column1 = tk.Frame( + frame_default_open_empty_category + ) + frame_default_open_empty_category_column1.pack(side=tk.LEFT, fill=tk.Y) + frame_default_open_empty_category_column2 = tk.Frame( + frame_default_open_empty_category + ) + frame_default_open_empty_category_column2.pack(side=tk.RIGHT, fill=tk.Y) self.open_empty_category_label = tk.Label( - frame_default_open_empty_category, text="显示无结果分类:", width=12 + frame_default_open_empty_category_column1, 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_empty_category, + frame_default_open_empty_category_column1, variable=self.open_empty_category_var, onvalue=True, offvalue=False, @@ -313,6 +321,20 @@ def init_ui(self, root): ) self.open_empty_category_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) + self.ipv6_support_label = tk.Label( + frame_default_open_empty_category_column2, text="跳过IPv6检测:", width=12 + ) + self.ipv6_support_label.pack(side=tk.LEFT, padx=4, pady=8) + self.ipv6_support_var = tk.BooleanVar(value=config.ipv6_support) + self.ipv6_support_checkbutton = ttk.Checkbutton( + frame_default_open_empty_category_column2, + variable=self.ipv6_support_var, + onvalue=True, + offvalue=False, + command=self.update_ipv6_support, + ) + self.ipv6_support_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) + frame_default_url_keywords = tk.Frame(root) frame_default_url_keywords.pack(fill=tk.X) frame_default_url_keywords_column1 = tk.Frame(frame_default_url_keywords) @@ -407,6 +429,11 @@ def update_open_empty_category(self): "Settings", "open_empty_category", str(self.open_empty_category_var.get()) ) + def update_ipv6_support(self): + config.set( + "Settings", "ipv6_support", str(self.ipv6_support_var.get()) + ) + def update_ipv_type(self, event): config.set("Settings", "ipv_type", self.ipv_type_combo.get()) @@ -438,6 +465,7 @@ def change_entry_state(self, state): "open_url_info_checkbutton", "open_empty_category_checkbutton", "ipv_type_combo", + "ipv6_support_checkbutton", "whitelist_file_button", "blacklist_file_button", ]: diff --git a/tkinter_ui/tkinter_ui.py b/tkinter_ui/tkinter_ui.py index 824ec7d2d8..5c728c0366 100644 --- a/tkinter_ui/tkinter_ui.py +++ b/tkinter_ui/tkinter_ui.py @@ -70,6 +70,7 @@ def save_config(self): "hotel_region_list": self.hotel_ui.region_list_combo.get(), "hotel_page_num": self.hotel_ui.page_num_entry.get(), "ipv_type": self.default_ui.ipv_type_combo.get(), + "ipv6_support": self.default_ui.ipv6_support_var.get(), "min_resolution": self.speed_ui.min_resolution_entry.get(), "multicast_region_list": self.multicast_ui.region_list_combo.get(), "multicast_page_num": self.multicast_ui.page_num_entry.get(), diff --git a/utils/config.py b/utils/config.py index 0b6ae68977..4fb878df66 100644 --- a/utils/config.py +++ b/utils/config.py @@ -98,6 +98,10 @@ def ipv4_num(self): def ipv6_num(self): return self.config.getint("Settings", "ipv6_num", fallback=15) + @property + def ipv6_support(self): + return self.config.getboolean("Settings", "ipv6_support", fallback=False) + @property def ipv_limit(self): return { From bdda9d701e2d21a8e45e7d898126bf0862409289 Mon Sep 17 00:00:00 2001 From: "guorong.zheng" <360996299@qq.com> Date: Mon, 16 Dec 2024 17:25:11 +0800 Subject: [PATCH 4/6] chore:proxy --- README.md | 16 ---------------- README_en.md | 16 ---------------- config/subscribe.txt | 14 +++++++------- docs/tutorial.md | 4 ++-- docs/tutorial_en.md | 8 ++++---- 5 files changed, 13 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 4bb13d9a9a..e9363a96de 100644 --- a/README.md +++ b/README.md @@ -110,16 +110,6 @@ - 接口源: -```bash -https://ghp.ci/raw.githubusercontent.com/Guovin/iptv-api/gd/output/result.m3u -``` - -```bash -https://ghp.ci/raw.githubusercontent.com/Guovin/iptv-api/gd/output/result.txt -``` - -或 - ```bash https://cdn.jsdelivr.net/gh/Guovin/iptv-api@gd/output/result.m3u ``` @@ -130,12 +120,6 @@ https://cdn.jsdelivr.net/gh/Guovin/iptv-api@gd/output/result.txt - 数据源: -```bash -https://ghp.ci/raw.githubusercontent.com/Guovin/iptv-api/gd/source.json -``` - -或 - ```bash https://cdn.jsdelivr.net/gh/Guovin/iptv-api@gd/source.json ``` diff --git a/README_en.md b/README_en.md index d57d09c004..2408d27f8b 100644 --- a/README_en.md +++ b/README_en.md @@ -110,16 +110,6 @@ - Interface source: -```bash -https://ghp.ci/raw.githubusercontent.com/Guovin/iptv-api/gd/output/result.m3u -``` - -```bash -https://ghp.ci/raw.githubusercontent.com/Guovin/iptv-api/gd/output/result.txt -``` - -or - ```bash https://cdn.jsdelivr.net/gh/Guovin/iptv-api@gd/output/result.m3u ``` @@ -130,12 +120,6 @@ https://cdn.jsdelivr.net/gh/Guovin/iptv-api@gd/output/result.txt - Data source: -```bash -https://ghp.ci/raw.githubusercontent.com/Guovin/iptv-api/gd/source.json -``` - -or - ```bash https://cdn.jsdelivr.net/gh/Guovin/iptv-api@gd/source.json ``` diff --git a/config/subscribe.txt b/config/subscribe.txt index 7703226a06..755b6da565 100644 --- a/config/subscribe.txt +++ b/config/subscribe.txt @@ -1,18 +1,18 @@ # 这是订阅源列表,每行一个订阅地址 # This is a list of subscription sources, with one subscription address per line https://iptv.b2og.com/txt/fmml_ipv6.txt -https://ghp.ci/raw.githubusercontent.com/suxuang/myIPTV/main/ipv6.m3u +https://cdn.jsdelivr.net/gh/suxuang/myIPTV@main/ipv6.m3u https://live.zbds.top/tv/iptv6.txt https://live.zbds.top/tv/iptv4.txt https://live.fanmingming.com/tv/m3u/ipv6.m3u -https://ghp.ci/https://raw.githubusercontent.com/joevess/IPTV/main/home.m3u8 +https://cdn.jsdelivr.net/gh/joevess/IPTV@main/home.m3u8 https://aktv.top/live.txt http://175.178.251.183:6689/live.txt -https://ghp.ci/https://raw.githubusercontent.com/kimwang1978/collect-tv-txt/main/merged_output.txt +https://cdn.jsdelivr.net/gh/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://ghp.ci/https://raw.githubusercontent.com/xzw832/cmys/main/S_CCTV.txt -https://ghp.ci/https://raw.githubusercontent.com/xzw832/cmys/main/S_weishi.txt -https://ghp.ci//https://raw.githubusercontent.com/asdjkl6/tv/tv/.m3u/整套直播源/测试/整套直播源/l.txt -https://ghp.ci//https://raw.githubusercontent.com/asdjkl6/tv/tv/.m3u/整套直播源/测试/整套直播源/kk.txt +https://cdn.jsdelivr.net/gh/xzw832/cmys@main/S_CCTV.txt +https://cdn.jsdelivr.net/gh/xzw832/cmys@main/S_weishi.txt +https://cdn.jsdelivr.net/gh/asdjkl6/tv@tv/.m3u/整套直播源/测试/整套直播源/l.txt +https://cdn.jsdelivr.net/gh/asdjkl6/tv@tv/.m3u/整套直播源/测试/整套直播源/kk.txt diff --git a/docs/tutorial.md b/docs/tutorial.md index e8106b96ea..eda1fee020 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -150,7 +150,7 @@ 如果一切正常,稍等片刻后就可以看到该条工作流已经执行成功(绿色勾图标) ![Workflow执行成功](./images/workflow-success.png 'Workflow执行成功') 此时您可以访问代理文件链接,查看最新结果有没有同步即可: -https://ghp.ci/raw.githubusercontent.com/您的github用户名/仓库名称(对应上述Fork创建时的TV)/master/output/user_result.txt +https://cdn.jsdelivr.net/gh/您的github用户名/仓库名称(对应上述Fork创建时的TV)@master/output/user_result.txt ![用户名与仓库名称](./images/rep-info.png '用户名与仓库名称') 如果访问该链接能正常返回更新后的接口内容,说明您的直播源接口链接已经大功告成了!将该链接复制粘贴到 TVBox @@ -282,5 +282,5 @@ docker run -v /etc/docker/config:/iptv-api-lite/config -v /etc/docker/output:/ip ### 上传更新文件至仓库(可选) 如果您没有自己的域名地址,接口更新完成后,将 user_result.txt 上传至个人仓库,即可使用 -https://ghp.ci/raw.githubusercontent.com/您的github用户名/仓库名称(对应上述Fork创建时的TV)/master/output/user_result.txt +https://cdn.jsdelivr.net/gh/您的github用户名/仓库名称(对应上述Fork创建时的TV)@master/output/user_result.txt ![用户名与仓库名称](./images/rep-info.png '用户名与仓库名称') diff --git a/docs/tutorial_en.md b/docs/tutorial_en.md index e96d296d8f..31323d2a89 100644 --- a/docs/tutorial_en.md +++ b/docs/tutorial_en.md @@ -159,8 +159,8 @@ mark). ![Workflow executed successfully](./images/workflow-success.png 'Workflow executed successfully') At this point, you can visit the proxy file link to see if the latest results have been synchronized: -https://ghp.ci/raw.githubusercontent.com/your github username/repository name (corresponding to the TV created when -forking)/master/user_result.txt +https://cdn.jsdelivr.net/gh/your github username/repository name (corresponding to the TV created when +forking)@master/user_result.txt ![Username and Repository Name](./images/rep-info.png 'Username and Repository Name') If you can access this link and it returns the updated interface content, then your live source interface link has been @@ -303,6 +303,6 @@ Port environment variables: If you do not have your own domain address, after the interface update is completed, upload user_result.txt to your personal repository to use it. -https://ghp.ci/raw.githubusercontent.com/your github username/repository name (corresponding to the TV created when -forking)/master/output/user_result.txt +https://cdn.jsdelivr.net/gh/github username/repository name (corresponding to the TV created when +forking)@master/output/user_result.txt ![Username and Repository Name](./images/rep-info.png 'Username and Repository Name') From e5894379134312a198d74e212a39b09bba981c7b Mon Sep 17 00:00:00 2001 From: "guorong.zheng" <360996299@qq.com> Date: Mon, 16 Dec 2024 17:41:34 +0800 Subject: [PATCH 5/6] release:v1.5.6 --- CHANGELOG.md | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++ version.json | 2 +- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9369987e7b..a0a36944a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,60 @@ # 更新日志(Changelog) +## v1.5.6 + +### 2024/12/16 + +- ❤️ 推荐关注微信公众号(Govin),订阅更新通知与使用技巧等文章推送,还可进行答疑和交流讨论 +- ⚠️ 本次更新涉及配置变更,以最新 `config/config.ini` 为准,工作流用户需复制最新配置至`user_config.ini` +- ✨ 新增白名单列表功能,支持自定义接口和订阅源关键字白名单,文件位于`config/whitelist.txt`,工作流用户为了避免冲突覆盖,建议文件重命名添加 + `user_`前缀(#584,#599) +- ✨ 新增黑名单列表功能,支持接口关键字黑名单,文件位于`config/blacklist.txt`,工作流用户为了避免冲突覆盖,建议文件重命名添加 + `user_`前缀 +- ✨ 新增订阅源列表功能,文件位于`config/subscribe.txt`,工作流用户为了避免冲突覆盖,建议文件重命名添加`user_`前缀 +- ✨ 新增支持获取接口速率、最低速率过滤(`open_filter_speed`、`min_speed`) +- ✨ 新增支持修改Docker服务端口环境变量(`APP_PORT`)(#619) +- ✨ 新增jsdelivr代理地址,支持TLSv1.1 和 TLSv1.2 协议(#639) +- ✨ 新增离线数据和网络数据查询开关(`open_use_cache`, `open_request`) +- ✨ 新增控制是否使用离线数据和网络数据查询(`open_use_cache`、`open_request`) +- ✨ 新增支持跳过检查是否支持ipv6(`ipv6_support`) +- ✨ 调整GUI界面布局,新增测速设置页面,跳转编辑白/黑名单、订阅源列表文本 +- 🐛 修复部分m3u8接口测速导致任务超时(#621) +- 🐛 修复GUI日志线程占用问题(#655) +- 🐛 补充显示更新时间配置文档(#622) +- 🪄 优化接口测速方法,移除`yt-dlp`(#621) +- 🗑️ 移除配置:`open_ffmpeg`、`subscribe_urls`、`resolution_weight`、`response_time_weight`、`url_keywords_blacklist` + +
+ English + +- ❤️ Recommend following the WeChat public account (Govin) to subscribe to update notifications and articles on usage + tips, as well as for Q&A and discussion. +- ⚠️ This update involves configuration changes. Refer to the latest `config/config.ini`. Workflow users need to copy + the latest configuration to `user_config.ini`. +- ✨ Added whitelist feature, supporting custom interface and subscription source keyword whitelists. The file is located + at `config/whitelist.txt`. To avoid conflict, workflow users are advised to rename the file with a `user_` prefix ( + #584, #599). +- ✨ Added blacklist feature, supporting interface keyword blacklists. The file is located at `config/blacklist.txt`. To + avoid conflict, workflow users are advised to rename the file with a `user_` prefix. +- ✨ Added subscription source list feature. The file is located at `config/subscribe.txt`. To avoid conflict, workflow + users are advised to rename the file with a `user_` prefix. +- ✨ Added support for fetching interface speed and minimum speed filtering (`open_filter_speed`, `min_speed`). +- ✨ Added support for modifying Docker server port environment variable (`APP_PORT`) (#619). +- ✨ Added jsdelivr proxy address, supporting TLSv1.1 and TLSv1.2 protocols (#639). +- ✨ Added switches for offline data and network data queries (`open_use_cache`, `open_request`). +- ✨ Added control for whether to use offline data and network data queries (`open_use_cache`, `open_request`). +- ✨ Added support for skipping the check for IPv6 support (`ipv6_support`). +- ✨ Adjusted GUI layout, added speed test settings page, and links to edit whitelist/blacklist and subscription source + list text files. +- 🐛 Fixed issue where some m3u8 interface speed tests caused task timeouts (#621). +- 🐛 Fixed GUI log thread occupation issue (#655). +- 🐛 Added display of update time in configuration documentation (#622). +- 🪄 Optimized interface speed test method, removed `yt-dlp` (#621). +- 🗑️ Removed configurations: `open_ffmpeg`, `subscribe_urls`, `resolution_weight`, `response_time_weight`, + `url_keywords_blacklist`. + +
+ ## v1.5.5 ### 2024/12/2 diff --git a/version.json b/version.json index 92f3eb0151..802a1121fb 100644 --- a/version.json +++ b/version.json @@ -1,4 +1,4 @@ { - "version": "1.5.5", + "version": "1.5.6", "name": "IPTV-API" } \ No newline at end of file From d06c24ada49b146aa7983101d46d15dfefa12a52 Mon Sep 17 00:00:00 2001 From: "guorong.zheng" <360996299@qq.com> Date: Mon, 16 Dec 2024 17:56:00 +0800 Subject: [PATCH 6/6] update:README --- README.md | 6 +++--- README_en.md | 6 +++--- docs/config.md | 6 +++--- docs/config_en.md | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index e9363a96de..508ae522ee 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ https://cdn.jsdelivr.net/gh/Guovin/iptv-api@gd/source.json | 配置项 | 描述 | 默认值 | |:-----------------------|:------------------------------------------------------------------------------------------|:----------------------------------------| -| open_driver | 开启浏览器运行,若更新无数据可开启此模式,较消耗性能 | True | +| open_driver | 开启浏览器运行,若更新无数据可开启此模式,较消耗性能 | False | | open_empty_category | 开启无结果频道分类,自动归类至底部 | False | | open_filter_resolution | 开启分辨率过滤,低于最小分辨率(min_resolution)的接口将会被过滤 | True | | open_filter_speed | 开启速率过滤,低于最小速率(min_speed)的接口将会被过滤 | True | @@ -142,14 +142,14 @@ https://cdn.jsdelivr.net/gh/Guovin/iptv-api@gd/source.json | open_multicast_fofa | 开启 FOFA 组播源工作模式 | True | | open_online_search | 开启关键字搜索源功能 | False | | open_proxy | 开启代理,自动获取免费可用代理,若更新无数据可开启此模式 | False | -| open_request | 开启查询请求,数据来源于网络 | False | +| open_request | 开启查询请求,数据来源于网络(仅针对酒店源与组播源) | False | | open_service | 开启页面服务,用于控制是否启动结果页面服务;如果使用青龙等平台部署,有专门设定的定时任务,需要更新完成后停止运行,可以关闭该功能 | True | | open_sort | 开启排序功能(响应速度、日期、分辨率) | True | | open_subscribe | 开启订阅源功能 | False | | open_update | 开启更新,用于控制是否更新接口,若关闭则所有工作模式(获取接口和测速)均停止 | True | | open_update_time | 开启显示更新时间 | True | | open_url_info | 开启显示接口说明信息,用于控制是否显示分辨率、接口协议类型等信息,为$符号后的内容,播放软件使用该信息对接口进行描述 | True | -| open_use_cache | 开启使用本地缓存数据,适用于查询请求失败场景 | True | +| open_use_cache | 开启使用本地缓存数据,适用于查询请求失败场景(仅针对酒店源与组播源) | True | | open_use_old_result | 开启使用历史更新结果(包含模板与结果文件的接口),合并至本次更新中 | True | | final_file | 生成结果文件路径 | output/result.txt | | hotel_num | 结果中偏好的酒店源接口数量 | 4 | diff --git a/README_en.md b/README_en.md index 2408d27f8b..81b0ba6600 100644 --- a/README_en.md +++ b/README_en.md @@ -128,7 +128,7 @@ https://cdn.jsdelivr.net/gh/Guovin/iptv-api@gd/source.json | Configuration Item | Description | Default Value | |:-----------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------| -| open_driver | Enable browser execution, If there are no updates, this mode can be enabled, which consumes more performance | True | +| open_driver | Enable browser execution, If there are no updates, this mode can be enabled, which consumes more performance | False | | open_empty_category | Enable the No Results Channel Category, which will automatically categorize channels without results to the bottom | False | | open_filter_resolution | Enable resolution filtering, interfaces with resolution lower than the minimum resolution (min_resolution) will be filtered | True | | open_filter_speed | Enable speed filtering, interfaces with speed lower than the minimum speed (min_speed) will be filtered | True | @@ -142,14 +142,14 @@ https://cdn.jsdelivr.net/gh/Guovin/iptv-api@gd/source.json | open_multicast_fofa | Enable FOFA multicast source work mode | True | | open_online_search | Enable keyword search source feature | False | | open_proxy | Enable proxy, automatically obtains free available proxies, If there are no updates, this mode can be enabled | False | -| open_request | Enable query request, the data is obtained from the network | False | +| open_request | Enable query request, the data is obtained from the network (only for hotel sources and multicast sources) | False | | open_service | Enable page service, used to control whether to start the result page service; if deployed on platforms like Qinglong with dedicated scheduled tasks, the function can be turned off after updates are completed and the task is stopped | True | | open_sort | Enable the sorting function (response speed, date, resolution) | True | | open_subscribe | Enable subscription source feature | True | | open_update | Enable updates, if disabled then only the result page service is run | True | | open_update_time | Enable show update time | True | | open_url_info | Enable display of API description information, used to control whether to show resolution, API protocol type, etc., the content after the $ symbol, playback software uses this information to describe the API | True | -| open_use_cache | Enable the use of local cache data, applicable to the query request failure scenario | True | +| open_use_cache | Enable the use of local cache data, applicable to the query request failure scenario (only for hotel sources and multicast sources) | True | | open_use_old_result | Enable the use of historical update results (including the interface for template and result files) and merge them into the current update | True | | final_file | Generated result file path | output/result.txt | | hotel_num | The number of preferred hotel source interfaces in the results | 4 | diff --git a/docs/config.md b/docs/config.md index 6c30ee8dd9..fbb3767978 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1,6 +1,6 @@ | 配置项 | 描述 | 默认值 | |:-----------------------|:------------------------------------------------------------------------------------------|:----------------------------------------| -| open_driver | 开启浏览器运行,若更新无数据可开启此模式,较消耗性能 | True | +| open_driver | 开启浏览器运行,若更新无数据可开启此模式,较消耗性能 | False | | open_empty_category | 开启无结果频道分类,自动归类至底部 | False | | open_filter_resolution | 开启分辨率过滤,低于最小分辨率(min_resolution)的接口将会被过滤 | True | | open_filter_speed | 开启速率过滤,低于最小速率(min_speed)的接口将会被过滤 | True | @@ -14,14 +14,14 @@ | open_multicast_fofa | 开启 FOFA 组播源工作模式 | True | | open_online_search | 开启关键字搜索源功能 | False | | open_proxy | 开启代理,自动获取免费可用代理,若更新无数据可开启此模式 | False | -| open_request | 开启查询请求,数据来源于网络 | False | +| open_request | 开启查询请求,数据来源于网络(仅针对酒店源与组播源) | False | | open_service | 开启页面服务,用于控制是否启动结果页面服务;如果使用青龙等平台部署,有专门设定的定时任务,需要更新完成后停止运行,可以关闭该功能 | True | | open_sort | 开启排序功能(响应速度、日期、分辨率) | True | | open_subscribe | 开启订阅源功能 | False | | open_update | 开启更新,用于控制是否更新接口,若关闭则所有工作模式(获取接口和测速)均停止 | True | | open_update_time | 开启显示更新时间 | True | | open_url_info | 开启显示接口说明信息,用于控制是否显示分辨率、接口协议类型等信息,为$符号后的内容,播放软件使用该信息对接口进行描述 | True | -| open_use_cache | 开启使用本地缓存数据,适用于查询请求失败场景 | True | +| open_use_cache | 开启使用本地缓存数据,适用于查询请求失败场景(仅针对酒店源与组播源) | True | | open_use_old_result | 开启使用历史更新结果(包含模板与结果文件的接口),合并至本次更新中 | True | | final_file | 生成结果文件路径 | output/result.txt | | hotel_num | 结果中偏好的酒店源接口数量 | 4 | diff --git a/docs/config_en.md b/docs/config_en.md index 98b2973aee..be2a6c17d7 100644 --- a/docs/config_en.md +++ b/docs/config_en.md @@ -1,6 +1,6 @@ | Configuration Item | Description | Default Value | |:-----------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------| -| open_driver | Enable browser execution, If there are no updates, this mode can be enabled, which consumes more performance | True | +| open_driver | Enable browser execution, If there are no updates, this mode can be enabled, which consumes more performance | False | | open_empty_category | Enable the No Results Channel Category, which will automatically categorize channels without results to the bottom | False | | open_filter_resolution | Enable resolution filtering, interfaces with resolution lower than the minimum resolution (min_resolution) will be filtered | True | | open_filter_speed | Enable speed filtering, interfaces with speed lower than the minimum speed (min_speed) will be filtered | True | @@ -14,14 +14,14 @@ | open_multicast_fofa | Enable FOFA multicast source work mode | True | | open_online_search | Enable keyword search source feature | False | | open_proxy | Enable proxy, automatically obtains free available proxies, If there are no updates, this mode can be enabled | False | -| open_request | Enable query request, the data is obtained from the network | False | +| open_request | Enable query request, the data is obtained from the network (only for hotel sources and multicast sources) | False | | open_service | Enable page service, used to control whether to start the result page service; if deployed on platforms like Qinglong with dedicated scheduled tasks, the function can be turned off after updates are completed and the task is stopped | True | | open_sort | Enable the sorting function (response speed, date, resolution) | True | | open_subscribe | Enable subscription source feature | True | | open_update | Enable updates, if disabled then only the result page service is run | True | | open_update_time | Enable show update time | True | | open_url_info | Enable display of API description information, used to control whether to show resolution, API protocol type, etc., the content after the $ symbol, playback software uses this information to describe the API | True | -| open_use_cache | Enable the use of local cache data, applicable to the query request failure scenario | True | +| open_use_cache | Enable the use of local cache data, applicable to the query request failure scenario (only for hotel sources and multicast sources) | True | | open_use_old_result | Enable the use of historical update results (including the interface for template and result files) and merge them into the current update | True | | final_file | Generated result file path | output/result.txt | | hotel_num | The number of preferred hotel source interfaces in the results | 4 |