From 7de46151811a07bc2eef4631fc2312cb9ab8337b Mon Sep 17 00:00:00 2001 From: "guorong.zheng" <360996299@qq.com> Date: Wed, 31 Jul 2024 17:31:51 +0800 Subject: [PATCH 1/3] feat:open_use_old_result and open_keep_all --- config.py | 2 + docs/config.md | 2 + docs/config_en.md | 48 +++++++++++---------- main.py | 4 +- tkinter_ui.py | 66 ++++++++++++++++++++++++++--- utils/channel.py | 106 ++++++++++++++++++++++++++++------------------ 6 files changed, 155 insertions(+), 73 deletions(-) diff --git a/config.py b/config.py index faf14de26c..51f3b7bdbb 100644 --- a/config.py +++ b/config.py @@ -1,4 +1,5 @@ open_update = True +open_use_old_result = True source_file = "demo.txt" final_file = "result.txt" favorite_list = [ @@ -18,6 +19,7 @@ favorite_page_num = 5 default_page_num = 3 urls_limit = 15 +open_keep_all = False open_sort = True response_time_weight = 0.5 resolution_weight = 0.5 diff --git a/docs/config.md b/docs/config.md index 27277658b5..36d0f470d1 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1,6 +1,7 @@ | 配置项 | 默认值 | 描述 | | ---------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | | open_update | True | 开启更新,若关闭则只运行结果页面服务 | +| open_use_old_result | True | 开启使用历史更新结果,合并至本次更新中 | | open_driver | False | 开启浏览器运行,若更新无数据可开启此模式,较消耗性能 | | open_proxy | True | 开启代理,自动获取免费可用代理,若更新无数据可开启此模式 | | source_file | "demo.txt" | 模板文件名称 | @@ -10,6 +11,7 @@ | favorite_page_num | 5 | 关注频道获取分页数量 | | default_page_num | 3 | 常规频道获取分页数量 | | urls_limit | 10 | 单个频道接口数量 | +| open_keep_all | False | 保留所有检索结果,会保留非模板频道名称的结果,推荐手动维护时开启 | | open_sort | True | 开启排序功能(响应速度、日期、分辨率) | | response_time_weight | 0.5 | 响应时间权重值(所有权重值总和应为 1) | | resolution_weight | 0.5 | 分辨率权重值 (所有权重值总和应为 1) | diff --git a/docs/config_en.md b/docs/config_en.md index fd5c591f54..b1cf8f5d33 100644 --- a/docs/config_en.md +++ b/docs/config_en.md @@ -1,23 +1,25 @@ -| Configuration Item | Default Value | Description | -| ---------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | -| open_update | True | Enable updates, if disabled then only the result page service is run | -| open_driver | False | Enable browser execution, If there are no updates, this mode can be enabled, which consumes more performance | -| open_proxy | True | Enable proxy, automatically obtains free available proxies, If there are no updates, this mode can be enabled | -| source_file | "demo.txt" | Template file name | -| final_file | "result.txt" | Generated file name | -| favorite_list | ["广东珠江","CCTV-1","CCTV-5","CCTV-5+","CCTV-13","广东体育","广东卫视","大湾区卫视","浙江卫视","湖南卫视","翡翠台"] | List of favorite channel names (used only to distinguish from regular channels, custom page retrieval quantity) | -| open_online_search | False | Enable online search source feature | -| favorite_page_num | 5 | Page retrieval quantity for favorite channels | -| default_page_num | 3 | Page retrieval quantity for regular channels | -| urls_limit | 10 | Number of interfaces per channel | -| open_sort | True | Enable the sorting function (response speed, date, resolution) | -| response_time_weight | 0.5 | Response time weight value (the sum of all weight values should be 1) | -| resolution_weight | 0.5 | Resolution weight value (the sum of all weight values should be 1) | -| recent_days | 30 | Retrieve interfaces updated within a recent time range (in days), reducing appropriately can avoid matching issues | -| ipv_type | "ipv4" | The type of interface in the generated result, optional values: "ipv4", "ipv6", "all" | -| domain_blacklist | ["epg.pw"] | Interface domain blacklist, used to filter out interfaces with low-quality, ad-inclusive domains | -| url_keywords_blacklist | [] | Interface keyword blacklist, used to filter out interfaces containing specific characters | -| open_subscribe | True | Enable subscription source feature | -| subscribe_urls | ["https://m3u.ibert.me/txt/fmml_dv6.txt",
"https://m3u.ibert.me/txt/o_cn.txt",
"https://m3u.ibert.me/txt/j_iptv.txt"] | Subscription source list | -| open_multicast | True | Enable multicast source function | -| region_list | ["all"] | Multicast source region list, [more regions](./fofa_map.py, "all" means all regions) | +| Configuration Item | Default Value | Description | +| ---------------------- | --------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | +| open_update | True | Enable updates, if disabled then only the result page service is run | +| open_use_old_result | True | Enable the use of historical update results and merge them into the current update | +| open_driver | False | Enable browser execution, If there are no updates, this mode can be enabled, which consumes more performance | +| open_proxy | True | Enable proxy, automatically obtains free available proxies, If there are no updates, this mode can be enabled | +| source_file | "demo.txt" | Template file name | +| final_file | "result.txt" | Generated file name | +| favorite_list | ["广东珠江","CCTV-1","CCTV-5","CCTV-5+","CCTV-13","广东体育","广东卫视","大湾区卫视","浙江卫视","湖南卫视","翡翠台"] | List of favorite channel names (used only to distinguish from regular channels, custom page retrieval quantity) | +| open_online_search | False | Enable online search source feature | +| favorite_page_num | 5 | Page retrieval quantity for favorite channels | +| default_page_num | 3 | Page retrieval quantity for regular channels | +| urls_limit | 10 | Number of interfaces per channel | +| open_keep_all | False | Retain all search results, retain results with non-template channel names, recommended to be turned on when manually maintaining | +| open_sort | True | Enable the sorting function (response speed, date, resolution) | +| response_time_weight | 0.5 | Response time weight value (the sum of all weight values should be 1) | +| resolution_weight | 0.5 | Resolution weight value (the sum of all weight values should be 1) | +| recent_days | 30 | Retrieve interfaces updated within a recent time range (in days), reducing appropriately can avoid matching issues | +| ipv_type | "ipv4" | The type of interface in the generated result, optional values: "ipv4", "ipv6", "all" | +| domain_blacklist | ["epg.pw"] | Interface domain blacklist, used to filter out interfaces with low-quality, ad-inclusive domains | +| url_keywords_blacklist | [] | Interface keyword blacklist, used to filter out interfaces containing specific characters | +| open_subscribe | True | Enable subscription source feature | +| subscribe_urls | ["https://m3u.ibert.me/txt/fmml_dv6.txt",
"https://m3u.ibert.me/txt/o_cn.txt",
"https://m3u.ibert.me/txt/j_iptv.txt"] | Subscription source list | +| open_multicast | True | Enable multicast source function | +| region_list | ["all"] | Multicast source region list, [more regions](./fofa_map.py, "all" means all regions) | diff --git a/main.py b/main.py index 81e62cf32d..3eeed5ab21 100644 --- a/main.py +++ b/main.py @@ -3,7 +3,7 @@ from utils.channel import ( get_channel_items, append_data_to_info_data, - append_all_method_data, + append_total_data, sort_channel_list, write_channel_to_file, ) @@ -86,7 +86,7 @@ async def main(self): self.total = len(channel_names) await self.visit_page(channel_names) self.tasks = [] - self.channel_data = append_all_method_data( + self.channel_data = append_total_data( self.channel_items.items(), self.channel_data, self.subscribe_result, diff --git a/tkinter_ui.py b/tkinter_ui.py index 91665872bb..f5c206d37b 100644 --- a/tkinter_ui.py +++ b/tkinter_ui.py @@ -24,11 +24,12 @@ class TkinterUI: def __init__(self, root): self.root = root self.root.title("直播源接口更新工具") - self.version = "v1.3.3" + self.version = "v1.3.4" self.update_source = UpdateSource() self.update_running = False self.config_entrys = [ "open_update_checkbutton", + "open_use_old_result_checkbutton", "open_driver_checkbutton", "open_proxy_checkbutton", "source_file_entry", @@ -38,6 +39,7 @@ def __init__(self, root): "open_subscribe_checkbutton", "open_multicast_checkbutton", "open_online_search_checkbutton", + "open_keep_all_checkbutton", "open_sort_checkbutton", "favorite_list_text", "favorite_page_num_entry", @@ -60,6 +62,9 @@ def format_list(self, text): def update_open_update(self): config.open_update = self.open_update_var.get() + def update_open_use_old_result(self): + config.open_use_old_result = self.open_use_old_result_var.get() + def select_source_file(self): filepath = filedialog.askopenfilename( initialdir=os.getcwd(), title="选择模板文件", filetypes=[("txt", "*.txt")] @@ -93,6 +98,9 @@ def update_open_driver(self): def update_open_proxy(self): config.open_proxy = self.open_proxy_var.get() + def update_open_keep_all(self): + config.open_keep_all = self.open_keep_all_var.get() + def update_open_sort(self): config.open_sort = self.open_sort_var.get() @@ -151,6 +159,7 @@ def view_result_link_callback(self, event): def save_config(self): config_values = { "open_update": self.open_update_var.get(), + "open_use_old_result": self.open_use_old_result_var.get(), "source_file": f'"{self.source_file_entry.get()}"', "final_file": f'"{self.final_file_entry.get()}"', "favorite_list": self.format_list(self.favorite_list_text.get(1.0, tk.END)), @@ -160,6 +169,7 @@ def save_config(self): "urls_limit": self.urls_limit_entry.get(), "open_driver": self.open_driver_var.get(), "open_proxy": self.open_proxy_var.get(), + "open_keep_all": self.open_keep_all_var.get(), "open_sort": self.open_sort_var.get(), "response_time_weight": self.response_time_weight_entry.get(), "resolution_weight": self.resolution_weight_entry.get(), @@ -255,12 +265,18 @@ def init_UI(self): frame1_open_update = tk.Frame(frame1) frame1_open_update.pack(fill=tk.X) + frame1_open_update_column1 = tk.Frame(frame1_open_update) + frame1_open_update_column1.pack(side=tk.LEFT, fill=tk.Y) + frame1_open_update_column2 = tk.Frame(frame1_open_update) + frame1_open_update_column2.pack(side=tk.RIGHT, fill=tk.Y) - self.open_update_label = tk.Label(frame1_open_update, text="开启更新:", width=8) + self.open_update_label = tk.Label( + frame1_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( - frame1_open_update, + frame1_open_update_column1, variable=self.open_update_var, onvalue=True, offvalue=False, @@ -269,6 +285,21 @@ def init_UI(self): ) self.open_update_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) + self.open_use_old_result_label = tk.Label( + frame1_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( + frame1_open_update_column2, + variable=self.open_use_old_result_var, + 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) + frame1_source_file = tk.Frame(frame1) frame1_source_file.pack(fill=tk.X) @@ -336,7 +367,7 @@ def init_UI(self): onvalue=True, offvalue=False, command=self.update_open_proxy, - text="(自动获取免费代理)", + text="(通过代理获取更新结果)", ) self.open_proxy_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) @@ -368,12 +399,33 @@ def init_UI(self): frame1_sort = tk.Frame(frame1) frame1_sort.pack(fill=tk.X) + frame1_sort_column1 = tk.Frame(frame1_sort) + frame1_sort_column1.pack(side=tk.LEFT, fill=tk.Y) + frame1_sort_column2 = tk.Frame(frame1_sort) + frame1_sort_column2.pack(side=tk.RIGHT, fill=tk.Y) + + self.open_keep_all_label = tk.Label( + frame1_sort_column1, 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( + frame1_sort_column1, + variable=self.open_keep_all_var, + onvalue=True, + offvalue=False, + command=self.update_open_keep_all, + text="(保留所有检索结果,建议手动维护时开启)", + ) + self.open_keep_all_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) - self.open_sort_label = tk.Label(frame1_sort, text="开启测速排序:", width=12) + self.open_sort_label = tk.Label( + frame1_sort_column2, 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( - frame1_sort, + frame1_sort_column2, variable=self.open_sort_var, onvalue=True, offvalue=False, @@ -642,7 +694,7 @@ def init_UI(self): tkinter_ui.init_UI() screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() - width = 500 + width = 550 height = 700 x = (screen_width / 2) - (width / 2) y = (screen_height / 2) - (height / 2) diff --git a/utils/channel.py b/utils/channel.py index 7f01fc2228..020155c73b 100644 --- a/utils/channel.py +++ b/utils/channel.py @@ -63,12 +63,13 @@ def get_channel_items(): # Create a dictionary to store the channels. channels = defaultdict(lambda: defaultdict(list)) - with open(resource_path(user_source_file), "r", encoding="utf-8") as file: - get_channel_data_from_file(channels, file) + if os.path.exists(resource_path(user_source_file)): + with open(resource_path(user_source_file), "r", encoding="utf-8") as file: + channels = get_channel_data_from_file(channels, file) - if config.open_use_old_result: + if config.open_use_old_result and os.path.exists(resource_path(user_final_file)): with open(resource_path(user_final_file), "r", encoding="utf-8") as file: - get_channel_data_from_file(channels, file) + channels = get_channel_data_from_file(channels, file) return channels @@ -77,6 +78,8 @@ def format_channel_name(name): """ Format the channel name with sub and replace and lower """ + if config.open_keep_all: + return name sub_pattern = ( r"-|_|\((.*?)\)|\[(.*?)\]| |频道|标清|高清|HD|hd|超清|超高|超高清|中央|央视|台" ) @@ -119,6 +122,8 @@ def channel_name_is_equal(name1, name2): """ Check if the channel name is equal """ + if config.open_keep_all: + return True cc = OpenCC("t2s") name1_converted = cc.convert(format_channel_name(name1)) name2_converted = cc.convert(format_channel_name(name2)) @@ -278,6 +283,16 @@ def append_data_to_info_data(info_data, cate, name, data, check=True): return info_data +def append_total_data(*args, **kwargs): + """ + Append total channel data + """ + if config.open_keep_all: + return append_all_method_data_keep_all(*args, **kwargs) + else: + return append_all_method_data(*args, **kwargs) + + def append_all_method_data( items, data, subscribe_result=None, multicast_result=None, online_search_result=None ): @@ -286,44 +301,25 @@ def append_all_method_data( """ for cate, channel_obj in items: for name, old_urls in channel_obj.items(): - if config.open_subscribe: - data = append_data_to_info_data( - data, - cate, - name, - get_channel_results_by_name(name, subscribe_result), - ) - print( - name, - "subscribe num:", - len(get_channel_results_by_name(name, subscribe_result)), - ) - if config.open_multicast: - data = append_data_to_info_data( - data, - cate, - name, - get_channel_results_by_name(name, multicast_result), - ) - print( - name, - "multicast num:", - len(get_channel_results_by_name(name, multicast_result)), - ) - if config.open_online_search: - data = append_data_to_info_data( - data, - cate, - name, - get_channel_results_by_name(name, online_search_result), - ) - print( - name, - "online search num:", - len(get_channel_results_by_name(name, online_search_result)), - ) + for method, result in [ + ("subscribe", subscribe_result), + ("multicast", multicast_result), + ("online_search", online_search_result), + ]: + if getattr(config, f"open_{method}"): + data = append_data_to_info_data( + data, + cate, + name, + get_channel_results_by_name(name, result), + ) + print( + name, + f"{method.capitalize()} num:", + len(get_channel_results_by_name(name, result)), + ) total_channel_data_len = len(data.get(cate, {}).get(name, [])) - if total_channel_data_len == 0: + if total_channel_data_len == 0 or config.open_use_old_result: data = append_data_to_info_data( data, cate, @@ -338,6 +334,34 @@ def append_all_method_data( return data +def append_all_method_data_keep_all( + items, data, subscribe_result=None, multicast_result=None, online_search_result=None +): + """ + Append all method data to total info data, keep all channel name and urls + """ + for cate, channel_obj in items: + for result_name, result in [ + ("subscribe", subscribe_result), + ("multicast", multicast_result), + ("online_search", online_search_result), + ]: + if result and getattr(config, f"open_{result_name}"): + for name, urls in result.items(): + data = append_data_to_info_data(data, cate, name, urls) + print(name, f"{result_name.capitalize()} num:", len(urls)) + if config.open_use_old_result: + old_urls = channel_obj.get(name, []) + data = append_data_to_info_data( + data, + cate, + name, + [(url, None, None) for url in old_urls], + ) + + return data + + async def sort_channel_list(semaphore, cate, name, info_list, callback): """ Sort the channel list From a5d3e5d8dafe2bac4a2f3a6f7dce1ea15c56f417 Mon Sep 17 00:00:00 2001 From: "guorong.zheng" <360996299@qq.com> Date: Wed, 31 Jul 2024 17:32:05 +0800 Subject: [PATCH 2/3] release:v1.3.4 --- CHANGELOG.md | 7 +++++++ version.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ad2a11ea6..3b2bb9d2d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # 更新日志(Changelog) +## v1.3.4 + +### 2024/7/31 + +- 新增配置 open_use_old_result:保留使用历史更新结果,合并至本次更新中(Add configuration open_use_old_result: Keep using the previous update results and merge them into the current update) +- 新增配置 open_keep_all:保留所有检索结果,推荐手动维护时开启(#121)(Add configuration open_keep_all: Keep all search results, recommend enabling it for manual maintenance (#121)) + ## v1.3.3 ### 2024/7/19 diff --git a/version.json b/version.json index 96649c928e..7c32fcf6b2 100644 --- a/version.json +++ b/version.json @@ -1,3 +1,3 @@ { - "version": "1.3.3" + "version": "1.3.4" } \ No newline at end of file From c8dc786e1f6a4533f1c13b6cfc3e9bcbb5537890 Mon Sep 17 00:00:00 2001 From: "guorong.zheng" <360996299@qq.com> Date: Wed, 31 Jul 2024 17:46:22 +0800 Subject: [PATCH 3/3] chore:title --- tkinter_ui.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tkinter_ui.py b/tkinter_ui.py index f5c206d37b..e5f8deae1b 100644 --- a/tkinter_ui.py +++ b/tkinter_ui.py @@ -352,7 +352,7 @@ def init_UI(self): onvalue=True, offvalue=False, command=self.update_open_driver, - text="(较消耗性能)", + text="(若获取更新异常请开启)", ) self.open_driver_checkbutton.pack(side=tk.LEFT, padx=4, pady=8) @@ -367,7 +367,7 @@ def init_UI(self): onvalue=True, offvalue=False, command=self.update_open_proxy, - text="(通过代理获取更新结果)", + text="(通过代理进行更新)", ) self.open_proxy_checkbutton.pack(side=tk.LEFT, padx=4, pady=8)