diff --git a/.gitignore b/.gitignore
index 2cf1da454af..9315b48695d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
dist
-build
\ No newline at end of file
+build
+result_new.log
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 60a4bfcb468..0d9cbc6021f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,16 @@
# 更新日志(Changelog)
+## v1.3.6
+
+### 2024/8/22
+
+- 新增酒店源更新,支持 Tonkiang、FOFA 两种工作模式(Added hotel source updates, supporting Tonkiang and FOFA working modes)
+- 重构 UI 界面软件,新增帮助-关于、获取频道名称编辑、酒店源相关配置、软件图标(Refactored UI interface software, added Help-About, channel name editing, hotel source related configuration, and software icon)
+- 移除关注频道相关配置(Removed configuration related to followed channels)
+- 修复 Docker 定时任务未执行问题(Fixed issue with Docker scheduled tasks not executing)
+- 修复使用历史结果时频道数据异常问题(Fixed issue with channel data anomalies when using historical results)
+- 优化 UI 界面软件运行生成配置目录,方便查看与修改(Optimized UI interface software to generate configuration directory for easier viewing and modification)
+
## v1.3.5
### 2024/8/14
diff --git a/README.md b/README.md
index d0e25541f1e..e565db44fba 100644
--- a/README.md
+++ b/README.md
@@ -112,4 +112,4 @@ Fork 本项目并开启工作流更新
## 赞赏
-![image](./docs/images/appreciate.jpg)
+![image](./static/images/appreciate.jpg)
diff --git a/README_en.md b/README_en.md
index 417e846cfaf..265cf7b7e98 100644
--- a/README_en.md
+++ b/README_en.md
@@ -112,4 +112,4 @@ If you don't want to bother, and my configuration just meets your needs, you can
## Appreciate
-![image](./docs/images/appreciate.jpg)
+![image](./static/images/appreciate.jpg)
diff --git a/config/config.ini b/config/config.ini
index 5fb336959a2..e9189845a86 100644
--- a/config/config.ini
+++ b/config/config.ini
@@ -26,7 +26,7 @@ multicast_region_list = 广东
multicast_page_num = 5
open_proxy = False
open_driver = False
-open_hotel = False
+open_hotel = True
open_hotel_tonkiang = True
open_hotel_fofa = True
hotel_region_list = 广东
diff --git a/main.py b/main.py
index c77e0d7db0b..bc293e06aae 100644
--- a/main.py
+++ b/main.py
@@ -1,5 +1,5 @@
import asyncio
-from utils.config import config
+from utils.config import config, copy_config
from utils.channel import (
get_channel_items,
append_data_to_info_data,
@@ -34,7 +34,23 @@ def show_result():
user_final_file = config.get("Settings", "final_file")
with open(user_final_file, "r", encoding="utf-8") as file:
content = file.read()
- return render_template_string("
{{ content }}
", content=content)
+ return render_template_string(
+ "{{ content }}
",
+ content=content,
+ )
+
+
+@app.route("/log")
+def show_log():
+ user_log_file = "output/" + (
+ "user_result.log" if os.path.exists("config/user_config.ini") else "result.log"
+ )
+ with open(user_log_file, "r", encoding="utf-8") as file:
+ content = file.read()
+ return render_template_string(
+ "{{ content }}
",
+ content=content,
+ )
class UpdateSource:
@@ -94,6 +110,8 @@ def sort_pbar_update(self):
async def main(self):
try:
self.channel_items = get_channel_items()
+ if self.run_ui:
+ copy_config()
channel_names = [
name
for channel_obj in self.channel_items.values()
@@ -171,8 +189,6 @@ async def main(self):
)
update_file(user_log_file, "output/result_new.log")
print(f"Update completed! Please check the {user_final_file} file!")
- if not os.environ.get("GITHUB_ACTIONS"):
- print(f"You can access the result at {get_ip_address()}")
if self.run_ui:
self.update_progress(
f"更新完成, 请检查{user_final_file}文件, 可访问以下链接:",
@@ -191,16 +207,14 @@ def default_callback(self, *args, **kwargs):
self.run_ui = True if callback else False
if config.getboolean("Settings", "open_update"):
await self.main()
- if self.run_ui:
- if not config.getboolean("Settings", "open_update"):
- print(f"You can access the result at {get_ip_address()}")
- self.update_progress(
- f"服务启动成功, 可访问以下链接:",
- 100,
- True,
- url=f"{get_ip_address()}",
- )
- app.run(host="0.0.0.0", port=8000)
+ if self.run_ui and config.getboolean("Settings", "open_update") == False:
+ self.update_progress(
+ f"服务启动成功, 可访问以下链接:",
+ 100,
+ True,
+ url=f"{get_ip_address()}",
+ )
+ run_app()
def stop(self):
for task in self.tasks:
@@ -218,8 +232,13 @@ def scheduled_task():
loop.run_until_complete(update_source.start())
+def run_app():
+ if not os.environ.get("GITHUB_ACTIONS"):
+ print(f"You can access the result at {get_ip_address()}")
+ app.run(host="0.0.0.0", port=8000)
+
+
if __name__ == "__main__":
if len(sys.argv) == 1 or (len(sys.argv) > 1 and sys.argv[1] == "scheduled_task"):
scheduled_task()
- if not os.environ.get("GITHUB_ACTIONS"):
- app.run(host="0.0.0.0", port=8000)
+ run_app()
diff --git a/docs/images/appreciate.jpg b/static/images/appreciate.jpg
similarity index 100%
rename from docs/images/appreciate.jpg
rename to static/images/appreciate.jpg
diff --git a/static/images/favicon.ico b/static/images/favicon.ico
new file mode 100644
index 00000000000..b68c23b6202
Binary files /dev/null and b/static/images/favicon.ico differ
diff --git a/tkinter_ui/about.py b/tkinter_ui/about.py
new file mode 100644
index 00000000000..3e1e0a943e0
--- /dev/null
+++ b/tkinter_ui/about.py
@@ -0,0 +1,87 @@
+import tkinter as tk
+from PIL import Image, ImageTk
+import webbrowser
+from utils.config import resource_path
+
+
+class AboutUI:
+ def init_ui(self, root=None, version=None):
+ about_window = tk.Toplevel(root)
+ about_window.title("关于")
+ about_window_width = 430
+ about_window_height = 430
+
+ version_frame = tk.Frame(about_window)
+ version_frame.pack(side=tk.TOP, fill=tk.X)
+
+ version_label = tk.Label(version_frame, text=f"版本: {version}")
+ version_label.pack()
+
+ author_row = tk.Frame(about_window)
+ author_row.pack()
+ author_row_column1 = tk.Frame(author_row)
+ author_row_column1.pack(side=tk.LEFT, fill=tk.Y)
+ author_row_column2 = tk.Frame(author_row)
+ author_row_column2.pack(side=tk.RIGHT, fill=tk.Y)
+ author_label = tk.Label(author_row_column1, text="作者:")
+ author_label.pack()
+ author_name = tk.Label(
+ author_row_column2, text="Govin", fg="blue", cursor="hand2"
+ )
+ author_name.pack()
+ author_name.bind(
+ "",
+ lambda e: webbrowser.open_new_tab("https://github.com/Guovin"),
+ )
+
+ project_row = tk.Frame(about_window)
+ project_row.pack()
+ project_row_column1 = tk.Frame(project_row)
+ project_row_column1.pack(side=tk.LEFT, fill=tk.Y)
+ project_row_column2 = tk.Frame(project_row)
+ project_row_column2.pack(side=tk.RIGHT, fill=tk.Y)
+ project_label = tk.Label(project_row_column1, text="项目地址:")
+ project_label.pack()
+ project_link = tk.Label(
+ project_row_column2,
+ text="https://github.com/Guovin/TV",
+ fg="blue",
+ cursor="hand2",
+ )
+ project_link.pack()
+ project_link.bind(
+ "",
+ lambda e: webbrowser.open_new_tab("https://github.com/Guovin/TV"),
+ )
+
+ disclaimer_label = tk.Label(
+ version_frame,
+ text="本软件仅供学习交流用途,数据均来源于互联网,禁止商业行为,一切法律责任与作者无关。",
+ wraplength=265,
+ )
+ disclaimer_label.pack()
+
+ image = Image.open(resource_path("static/images/appreciate.jpg"))
+ resized_image = image.resize((250, 250))
+ photo = ImageTk.PhotoImage(resized_image)
+ image_label = tk.Label(about_window, image=photo)
+ image_label.image = photo
+ image_label.pack()
+
+ appreciate_label = tk.Label(about_window, text="您的赞助是我更新的动力")
+ appreciate_label.pack()
+
+ confirm_button = tk.ttk.Button(
+ about_window, text="确定", command=about_window.destroy
+ )
+ confirm_button.pack(side=tk.RIGHT, padx=5)
+
+ main_width = root.winfo_width()
+ main_height = root.winfo_height()
+ main_x = root.winfo_x()
+ main_y = root.winfo_y()
+ pos_x = main_x + (main_width // 2) - (about_window_width // 2)
+ pos_y = main_y + (main_height // 2) - (about_window_height // 2)
+ about_window.geometry(
+ f"{about_window_width}x{about_window_height}+{pos_x}+{pos_y}"
+ )
diff --git a/tkinter_ui/default.py b/tkinter_ui/default.py
index 56324f9898d..473283c550f 100644
--- a/tkinter_ui/default.py
+++ b/tkinter_ui/default.py
@@ -4,6 +4,7 @@
from tkinter import scrolledtext
from tkinter import filedialog
import os
+from utils.channel import get_channel_items
class DefaultUI:
@@ -67,7 +68,7 @@ def init_ui(self, root):
frame_default_source_file_select = tk.Frame(root)
frame_default_source_file_select.pack(fill=tk.X)
- self.source_file_button = tk.Button(
+ self.source_file_button = tk.ttk.Button(
frame_default_source_file_select,
text="选择文件",
command=self.select_source_file,
@@ -106,7 +107,7 @@ def init_ui(self, root):
frame_default_final_file_select = tk.Frame(root)
frame_default_final_file_select.pack(fill=tk.X)
- self.final_file_button = tk.Button(
+ self.final_file_button = tk.ttk.Button(
frame_default_final_file_select,
text="选择文件",
command=self.select_final_file,
@@ -305,6 +306,11 @@ def select_source_file(self):
self.source_file_entry.delete(0, tk.END)
self.source_file_entry.insert(0, filepath)
config.set("Settings", "source_file", filepath)
+ get_channel_items(change_source_path=True)
+ self.source_channels_text.delete(1.0, tk.END)
+ self.source_channels_text.insert(
+ tk.END, config.get("Settings", "source_channels")
+ )
def update_source_channels(self, event):
config.set(
diff --git a/tkinter_ui/tkinter_ui.py b/tkinter_ui/tkinter_ui.py
index 019827e5d61..7abb1190207 100644
--- a/tkinter_ui/tkinter_ui.py
+++ b/tkinter_ui/tkinter_ui.py
@@ -4,12 +4,12 @@
sys.path.append(os.path.dirname(sys.path[0]))
import tkinter as tk
from tkinter import messagebox
-from tkinter import ttk
from utils.config import config, resource_path, save_config
from main import UpdateSource
import asyncio
import threading
import webbrowser
+from about import AboutUI
from default import DefaultUI
from multicast import MulticastUI
from hotel import HotelUI
@@ -25,6 +25,7 @@ def __init__(self, root):
self.root = root
self.root.title(info.get("name", ""))
self.version = info.get("version", "")
+ self.about_ui = AboutUI()
self.default_ui = DefaultUI()
self.multicast_ui = MulticastUI()
self.hotel_ui = HotelUI()
@@ -129,14 +130,23 @@ def update_progress(self, title, progress, finished=False, url=None):
def init_UI(self):
- notebook = ttk.Notebook(self.root)
- notebook.pack(expand=True, fill="both", padx=10, pady=0)
+ menu_bar = tk.Menu(self.root)
+ help_menu = tk.Menu(menu_bar, tearoff=0)
+ help_menu.add_command(
+ label="关于",
+ command=lambda: self.about_ui.init_ui(root=self.root, version=self.version),
+ )
+ menu_bar.add_cascade(label="帮助", menu=help_menu)
+ self.root.config(menu=menu_bar)
+
+ notebook = tk.ttk.Notebook(self.root)
+ notebook.pack(fill="both", padx=10, pady=5)
- frame_default = ttk.Frame(notebook, width=500, height=500)
- frame_multicast = ttk.Frame(notebook, width=500, height=500)
- frame_hotel = ttk.Frame(notebook, width=500, height=500)
- frame_subscribe = ttk.Frame(notebook, width=500, height=500)
- frame_online_search = ttk.Frame(notebook, width=500, height=500)
+ frame_default = tk.ttk.Frame(notebook)
+ frame_multicast = tk.ttk.Frame(notebook)
+ frame_hotel = tk.ttk.Frame(notebook)
+ frame_subscribe = tk.ttk.Frame(notebook)
+ frame_online_search = tk.ttk.Frame(notebook)
notebook.add(frame_default, text="通用设置")
notebook.add(frame_multicast, text="组播源")
@@ -157,45 +167,20 @@ def init_UI(self):
root_operate_column2 = tk.Frame(root_operate)
root_operate_column2.pack(side=tk.RIGHT, fill=tk.Y)
- self.save_button = tk.Button(
+ self.save_button = tk.ttk.Button(
root_operate_column1, text="保存设置", command=self.save_config
)
self.save_button.pack(side=tk.LEFT, padx=4, pady=8)
- self.run_button = tk.Button(
+ self.run_button = tk.ttk.Button(
root_operate_column2, text="开始更新", command=self.on_run_update
)
self.run_button.pack(side=tk.LEFT, padx=4, pady=8)
- version_frame = tk.Frame(self.root)
- version_frame.pack(side=tk.BOTTOM, fill=tk.X)
-
- self.version_label = tk.Label(
- version_frame, text=self.version, fg="gray", anchor="se"
- )
- self.version_label.pack(side=tk.RIGHT, padx=5, pady=5)
-
- self.author_label = tk.Label(
- version_frame,
- text="by Govin",
- fg="gray",
- anchor="se",
- )
- self.author_label.pack(side=tk.LEFT, padx=5, pady=5)
-
- self.project_link = tk.Label(
- version_frame, text="访问项目主页", fg="blue", cursor="hand2"
- )
- self.project_link.pack(side=tk.LEFT, padx=5, pady=5)
- self.project_link.bind(
- "",
- lambda e: webbrowser.open_new_tab("https://github.com/Guovin/TV"),
- )
-
root_progress = tk.Frame(self.root)
root_progress.pack(fill=tk.X)
- self.progress_bar = ttk.Progressbar(
+ self.progress_bar = tk.ttk.Progressbar(
root_progress, length=300, mode="determinate"
)
self.progress_bar.pack_forget()
@@ -211,15 +196,22 @@ def init_UI(self):
self.view_result_link.pack_forget()
-if __name__ == "__main__":
- root = tk.Tk()
- tkinter_ui = TkinterUI(root)
- tkinter_ui.init_UI()
+def get_root_location(root):
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
width = 550
height = 750
x = (screen_width / 2) - (width / 2)
y = (screen_height / 2) - (height / 2)
- root.geometry("%dx%d+%d+%d" % (width, height, x, y))
+ return (width, height, x, y)
+
+
+if __name__ == "__main__":
+ root = tk.Tk()
+ tkinter_ui = TkinterUI(root)
+ tkinter_ui.init_UI()
+ screen_width = root.winfo_screenwidth()
+ screen_height = root.winfo_screenheight()
+ root.geometry("%dx%d+%d+%d" % get_root_location(root))
+ root.iconbitmap(resource_path("static/images/favicon.ico"))
root.mainloop()
diff --git a/tkinter_ui/tkinter_ui.spec b/tkinter_ui/tkinter_ui.spec
index f0ca2a0b4f4..6d5d6bd1f5d 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', 'default.py', 'multicast.py', 'hotel.py', 'subscribe.py', 'online_search.py'],
+ ['tkinter_ui.py', 'about.py', 'default.py', 'multicast.py', 'hotel.py', 'subscribe.py', 'online_search.py'],
pathex=[],
binaries=[],
datas=[
@@ -9,6 +9,9 @@ a = Analysis(
('../config/demo.txt', 'config'),
('../updates/multicast/multicast_map.json', 'updates/multicast'),
('../updates/multicast/multicast_region_result.json', 'updates/multicast'),
+ ('../static/images/favicon.ico', 'static/images'),
+ ('../static/images/appreciate.jpg', 'static/images'),
+ ('about.py', '.'),
('default.py', '.'),
('multicast.py', '.'),
('hotel.py', '.'),
@@ -46,4 +49,5 @@ exe = EXE(
target_arch=None,
codesign_identity=None,
entitlements_file=None,
+ icon='../static/images/favicon.ico'
)
diff --git a/utils/channel.py b/utils/channel.py
index 966ac007758..6182c47ac8a 100644
--- a/utils/channel.py
+++ b/utils/channel.py
@@ -24,7 +24,9 @@
)
-def get_channel_data_from_file(channels=None, file=None, names=None, from_result=False):
+def get_channel_data_from_file(
+ channels=None, file=None, names=None, from_result=False, change_source_path=False
+):
"""
Get the channel data from the file
"""
@@ -43,7 +45,7 @@ def get_channel_data_from_file(channels=None, file=None, names=None, from_result
match = re.search(pattern, line)
if match is not None:
name = match.group(1).strip()
- if name not in names:
+ if not change_source_path and name not in names:
continue
url = match.group(2).strip()
if url and url not in channels[current_category][name]:
@@ -51,7 +53,7 @@ def get_channel_data_from_file(channels=None, file=None, names=None, from_result
return channels
-def get_channel_items():
+def get_channel_items(change_source_path=False):
"""
Get the channel items from the source file
"""
@@ -63,7 +65,10 @@ def get_channel_items():
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=channels, file=file, names=source_channel_names
+ channels=channels,
+ file=file,
+ names=source_channel_names,
+ change_source_path=change_source_path,
)
if config.getboolean("Settings", "open_use_old_result") and os.path.exists(
@@ -75,14 +80,16 @@ def get_channel_items():
file=file,
names=source_channel_names,
from_result=True,
+ change_source_path=change_source_path,
)
channel_names = [
name for channel_obj in channels.values() for name in channel_obj.keys()
]
- for source_name in source_channel_names:
- if source_name not in channel_names:
- channels["自定义频道"][source_name] = []
+ if not change_source_path:
+ for source_name in source_channel_names:
+ if source_name not in channel_names:
+ channels["自定义频道"][source_name] = []
total_channel_names = ",".join(
[name for channel_obj in channels.values() for name in channel_obj.keys()]
)
@@ -514,6 +521,10 @@ def append_all_method_data(
("online_search", online_search_result),
]:
if config.getboolean("Settings", f"open_{method}"):
+ if (
+ method == "hotel_tonkiang" or method == "hotel_fofa"
+ ) and config.getboolean("Settings", f"open_hotel") == False:
+ continue
data = append_data_to_info_data(
data,
cate,
@@ -556,17 +567,21 @@ def append_all_method_data_keep_all(
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 [
+ for method, result in [
("subscribe", subscribe_result),
("multicast", multicast_result),
("hotel_tonkiang", hotel_tonkiang_result),
("hotel_fofa", hotel_fofa_result),
("online_search", online_search_result),
]:
- if result and config.getboolean("Settings", f"open_{result_name}"):
+ if result and config.getboolean("Settings", f"open_{method}"):
+ if (
+ method == "hotel_tonkiang" or method == "hotel_fofa"
+ ) and config.getboolean("Settings", f"open_hotel") == False:
+ continue
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))
+ print(name, f"{method.capitalize()} num:", len(urls))
if config.getboolean("Settings", "open_use_old_result"):
old_urls = channel_obj.get(name, [])
data = append_data_to_info_data(
diff --git a/utils/config.py b/utils/config.py
index 8f9f4bd7d8f..554d31b9466 100644
--- a/utils/config.py
+++ b/utils/config.py
@@ -1,6 +1,7 @@
import os
import sys
import configparser
+import shutil
def resource_path(relative_path, persistent=False):
@@ -50,6 +51,26 @@ def save_config():
else "config.ini"
)
user_config_path = resource_path(user_config_file, persistent=True)
- os.makedirs(os.path.dirname(user_config_path), exist_ok=True)
+ if not os.path.exists(user_config_path):
+ os.makedirs(os.path.dirname(user_config_path), exist_ok=True)
with open(user_config_path, "w", encoding="utf-8") as configfile:
config.write(configfile)
+
+
+def copy_config():
+ user_source_file = resource_path(config.get("Settings", "source_file"))
+ user_config_path = resource_path("config/user_config.ini")
+ default_config_path = resource_path("config/config.ini")
+ user_config_file = (
+ user_config_path if os.path.exists(user_config_path) else default_config_path
+ )
+ dest_folder = os.path.join(os.getcwd(), "config")
+ files_to_copy = [user_source_file, user_config_file]
+ try:
+ for src_file in files_to_copy:
+ dest_path = os.path.join(dest_folder, os.path.basename(src_file))
+ if os.path.abspath(src_file) == os.path.abspath(dest_path):
+ continue
+ shutil.copy(src_file, dest_folder)
+ except Exception as e:
+ print(f"Failed to copy files: {str(e)}")
diff --git a/version.json b/version.json
index 753bcd9ecb0..ef1109dd7a6 100644
--- a/version.json
+++ b/version.json
@@ -1,4 +1,4 @@
{
- "version": "1.3.5",
+ "version": "1.3.6",
"name": "直播源接口更新工具"
}
\ No newline at end of file