tkinter_ui.py 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. import tkinter as tk
  2. from tkinter import messagebox
  3. from tkinter import scrolledtext
  4. from tkinter import ttk
  5. from tkinter import filedialog
  6. from utils.config import resource_path, load_external_config
  7. from main import UpdateSource
  8. import os
  9. import asyncio
  10. import threading
  11. import webbrowser
  12. config_path = resource_path("user_config.py")
  13. default_config_path = resource_path("config.py")
  14. config = (
  15. load_external_config("user_config.py")
  16. if os.path.exists(config_path)
  17. else load_external_config("config.py")
  18. )
  19. class TkinterUI:
  20. def __init__(self, root):
  21. self.root = root
  22. self.root.title("直播源接口更新工具")
  23. self.version = "v1.3.4"
  24. self.update_source = UpdateSource()
  25. self.update_running = False
  26. self.config_entrys = [
  27. "open_update_checkbutton",
  28. "open_use_old_result_checkbutton",
  29. "open_driver_checkbutton",
  30. "open_proxy_checkbutton",
  31. "source_file_entry",
  32. "source_file_button",
  33. "final_file_entry",
  34. "final_file_button",
  35. "open_subscribe_checkbutton",
  36. "open_multicast_checkbutton",
  37. "open_online_search_checkbutton",
  38. "open_keep_all_checkbutton",
  39. "open_sort_checkbutton",
  40. "favorite_list_text",
  41. "favorite_page_num_entry",
  42. "default_page_num_entry",
  43. "urls_limit_entry",
  44. "response_time_weight_entry",
  45. "resolution_weight_entry",
  46. "ipv_type_combo",
  47. "recent_days_entry",
  48. "domain_blacklist_text",
  49. "url_keywords_blacklist_text",
  50. "subscribe_urls_text",
  51. "region_list_text",
  52. ]
  53. self.result_url = None
  54. def format_list(self, text):
  55. return [f"{item.strip()}" for item in text.split(",") if item.strip()]
  56. def update_open_update(self):
  57. config.open_update = self.open_update_var.get()
  58. def update_open_use_old_result(self):
  59. config.open_use_old_result = self.open_use_old_result_var.get()
  60. def select_source_file(self):
  61. filepath = filedialog.askopenfilename(
  62. initialdir=os.getcwd(), title="选择模板文件", filetypes=[("txt", "*.txt")]
  63. )
  64. if filepath:
  65. self.source_file_entry.delete(0, tk.END)
  66. self.source_file_entry.insert(0, filepath)
  67. config.source_file = filepath
  68. def select_final_file(self):
  69. filepath = filedialog.askopenfilename(
  70. initialdir=os.getcwd(), title="选择结果文件", filetypes=[("txt", "*.txt")]
  71. )
  72. if filepath:
  73. self.final_file_entry.delete(0, tk.END)
  74. self.final_file_entry.insert(0, filepath)
  75. config.final_file = filepath
  76. def update_open_subscribe(self):
  77. config.open_subscribe = self.open_subscribe_var.get()
  78. def update_open_multicast(self):
  79. config.open_multicast = self.open_multicast_var.get()
  80. def update_open_online_search(self):
  81. config.open_online_search = self.open_online_search_var.get()
  82. def update_open_driver(self):
  83. config.open_driver = self.open_driver_var.get()
  84. def update_open_proxy(self):
  85. config.open_proxy = self.open_proxy_var.get()
  86. def update_open_keep_all(self):
  87. config.open_keep_all = self.open_keep_all_var.get()
  88. def update_open_sort(self):
  89. config.open_sort = self.open_sort_var.get()
  90. def update_favorite_list(self, event):
  91. config.favorite_list = self.format_list(
  92. self.favorite_list_text.get(1.0, tk.END)
  93. )
  94. def update_favorite_page_num(self, event):
  95. config.favorite_page_num = self.favorite_page_num_entry.get()
  96. def update_default_page_num(self, event):
  97. config.default_page_num = self.default_page_num_entry.get()
  98. def update_urls_limit(self, event):
  99. config.urls_limit = self.urls_limit_entry.get()
  100. def update_response_time_weight(self, event):
  101. config.response_time_weight = self.response_time_weight_entry.get()
  102. def update_resolution_weight(self, event):
  103. config.resolution_weight = self.resolution_weight_entry.get()
  104. def update_ipv_type(self, event):
  105. config.ipv_type = f'"{self.ipv_type_combo.get()}"'
  106. def update_recent_days(self, event):
  107. config.recent_days = self.recent_days_entry.get()
  108. def update_url_keywords_blacklist(self, event):
  109. config.url_keywords_blacklist = self.format_list(
  110. self.url_keywords_blacklist_text.get(1.0, tk.END)
  111. )
  112. def update_domain_blacklist(self, event):
  113. config.domain_blacklist = self.format_list(
  114. self.domain_blacklist_text.get(1.0, tk.END)
  115. )
  116. def update_url_keywords_blacklist(self, event):
  117. config.url_keywords_blacklist = self.format_list(
  118. self.url_keywords_blacklist_text.get(1.0, tk.END)
  119. )
  120. def update_subscribe_urls(self, event):
  121. config.subscribe_urls = self.format_list(
  122. self.subscribe_urls_text.get(1.0, tk.END)
  123. )
  124. def update_region_list(self, event):
  125. config.region_list = self.format_list(self.region_list_text.get(1.0, tk.END))
  126. def view_result_link_callback(self, event):
  127. webbrowser.open_new_tab(self.result_url)
  128. def save_config(self):
  129. config_values = {
  130. "open_update": self.open_update_var.get(),
  131. "open_use_old_result": self.open_use_old_result_var.get(),
  132. "source_file": f'"{self.source_file_entry.get()}"',
  133. "final_file": f'"{self.final_file_entry.get()}"',
  134. "favorite_list": self.format_list(self.favorite_list_text.get(1.0, tk.END)),
  135. "open_online_search": self.open_online_search_var.get(),
  136. "favorite_page_num": self.favorite_page_num_entry.get(),
  137. "default_page_num": self.default_page_num_entry.get(),
  138. "urls_limit": self.urls_limit_entry.get(),
  139. "open_driver": self.open_driver_var.get(),
  140. "open_proxy": self.open_proxy_var.get(),
  141. "open_keep_all": self.open_keep_all_var.get(),
  142. "open_sort": self.open_sort_var.get(),
  143. "response_time_weight": self.response_time_weight_entry.get(),
  144. "resolution_weight": self.resolution_weight_entry.get(),
  145. "recent_days": self.recent_days_entry.get(),
  146. "ipv_type": f'"{self.ipv_type_combo.get()}"',
  147. "domain_blacklist": self.format_list(
  148. self.domain_blacklist_text.get(1.0, tk.END)
  149. ),
  150. "url_keywords_blacklist": self.format_list(
  151. self.url_keywords_blacklist_text.get(1.0, tk.END)
  152. ),
  153. "open_subscribe": self.open_subscribe_var.get(),
  154. "subscribe_urls": self.format_list(
  155. self.subscribe_urls_text.get(1.0, tk.END)
  156. ),
  157. "open_multicast": self.open_multicast_var.get(),
  158. "region_list": self.format_list(self.region_list_text.get(1.0, tk.END)),
  159. }
  160. for key, value in config_values.items():
  161. setattr(config, key, value)
  162. user_config_file = (
  163. "user_config.py" if os.path.exists("user_config.py") else "config.py"
  164. )
  165. with open(
  166. resource_path(user_config_file, persistent=True), "w", encoding="utf-8"
  167. ) as f:
  168. for key, value in config_values.items():
  169. f.write(f"{key} = {value}\n")
  170. messagebox.showinfo("提示", "保存成功")
  171. async def run_update(self):
  172. self.update_running = not self.update_running
  173. if self.update_running:
  174. self.run_button.config(text="取消更新", state="normal")
  175. for entry in self.config_entrys:
  176. getattr(self, entry).config(state="disabled")
  177. self.progress_bar["value"] = 0
  178. self.progress_label.pack()
  179. self.view_result_link.pack()
  180. self.progress_bar.pack()
  181. await self.update_source.start(self.update_progress)
  182. else:
  183. self.stop()
  184. self.update_source.stop()
  185. self.run_button.config(text="开始更新", state="normal")
  186. for entry in self.config_entrys:
  187. getattr(self, entry).config(state="normal")
  188. self.progress_bar.pack_forget()
  189. self.view_result_link.pack_forget()
  190. self.progress_label.pack_forget()
  191. def on_run_update(self):
  192. def run_loop():
  193. loop = asyncio.new_event_loop()
  194. asyncio.set_event_loop(loop)
  195. loop.run_until_complete(self.run_update())
  196. self.thread = threading.Thread(target=run_loop, daemon=True)
  197. self.thread.start()
  198. def stop(self):
  199. asyncio.get_event_loop().stop()
  200. def update_progress(self, title, progress, finished=False, url=None):
  201. self.progress_bar["value"] = progress
  202. progress_text = f"{title}, 进度: {progress}%" if not finished else f"{title}"
  203. self.progress_label["text"] = progress_text
  204. self.root.update()
  205. if finished:
  206. self.run_button.config(text="开始更新", state="normal")
  207. self.update_running = False
  208. for entry in self.config_entrys:
  209. getattr(self, entry).config(state="normal")
  210. if url:
  211. self.view_result_link.config(text=url)
  212. self.result_url = url
  213. def init_UI(self):
  214. notebook = ttk.Notebook(self.root)
  215. notebook.pack(expand=True, fill="both", padx=10, pady=0)
  216. frame1 = ttk.Frame(notebook, width=500, height=500)
  217. frame2 = ttk.Frame(notebook, width=500, height=500)
  218. frame3 = ttk.Frame(notebook, width=500, height=500)
  219. frame4 = ttk.Frame(notebook, width=500, height=500)
  220. notebook.add(frame1, text="通用设置")
  221. notebook.add(frame2, text="在线搜索")
  222. notebook.add(frame3, text="订阅源")
  223. notebook.add(frame4, text="组播源")
  224. frame1_open_update = tk.Frame(frame1)
  225. frame1_open_update.pack(fill=tk.X)
  226. frame1_open_update_column1 = tk.Frame(frame1_open_update)
  227. frame1_open_update_column1.pack(side=tk.LEFT, fill=tk.Y)
  228. frame1_open_update_column2 = tk.Frame(frame1_open_update)
  229. frame1_open_update_column2.pack(side=tk.RIGHT, fill=tk.Y)
  230. self.open_update_label = tk.Label(
  231. frame1_open_update_column1, text="开启更新:", width=8
  232. )
  233. self.open_update_label.pack(side=tk.LEFT, padx=4, pady=8)
  234. self.open_update_var = tk.BooleanVar(value=config.open_update)
  235. self.open_update_checkbutton = ttk.Checkbutton(
  236. frame1_open_update_column1,
  237. variable=self.open_update_var,
  238. onvalue=True,
  239. offvalue=False,
  240. command=self.update_open_update,
  241. text="(关闭则只运行结果页面服务)",
  242. )
  243. self.open_update_checkbutton.pack(side=tk.LEFT, padx=4, pady=8)
  244. self.open_use_old_result_label = tk.Label(
  245. frame1_open_update_column2, text="使用历史结果:", width=12
  246. )
  247. self.open_use_old_result_label.pack(side=tk.LEFT, padx=4, pady=8)
  248. self.open_use_old_result_var = tk.BooleanVar(value=config.open_use_old_result)
  249. self.open_use_old_result_checkbutton = ttk.Checkbutton(
  250. frame1_open_update_column2,
  251. variable=self.open_use_old_result_var,
  252. onvalue=True,
  253. offvalue=False,
  254. command=self.update_open_use_old_result,
  255. text="(保留上次更新可用结果)",
  256. )
  257. self.open_use_old_result_checkbutton.pack(side=tk.LEFT, padx=4, pady=8)
  258. frame1_source_file = tk.Frame(frame1)
  259. frame1_source_file.pack(fill=tk.X)
  260. self.source_file_label = tk.Label(frame1_source_file, text="模板文件:", width=8)
  261. self.source_file_entry = tk.Entry(frame1_source_file)
  262. self.source_file_label.pack(side=tk.LEFT, padx=4, pady=8)
  263. self.source_file_entry.pack(fill=tk.X, padx=4, expand=True)
  264. self.source_file_entry.insert(0, config.source_file)
  265. frame1_source_file_select = tk.Frame(frame1)
  266. frame1_source_file_select.pack(fill=tk.X)
  267. self.source_file_button = tk.Button(
  268. frame1_source_file_select, text="选择文件", command=self.select_source_file
  269. )
  270. self.source_file_button.pack(side=tk.LEFT, padx=4, pady=0)
  271. frame1_final_file = tk.Frame(frame1)
  272. frame1_final_file.pack(fill=tk.X)
  273. self.final_file_label = tk.Label(frame1_final_file, text="结果文件:", width=8)
  274. self.final_file_entry = tk.Entry(frame1_final_file)
  275. self.final_file_label.pack(side=tk.LEFT, padx=4, pady=8)
  276. self.final_file_entry.pack(fill=tk.X, padx=4, expand=True)
  277. self.final_file_entry.insert(0, config.final_file)
  278. frame1_final_file_select = tk.Frame(frame1)
  279. frame1_final_file_select.pack(fill=tk.X)
  280. self.final_file_button = tk.Button(
  281. frame1_final_file_select, text="选择文件", command=self.select_final_file
  282. )
  283. self.final_file_button.pack(side=tk.LEFT, padx=4, pady=0)
  284. frame1_mode = tk.Frame(frame1)
  285. frame1_mode.pack(fill=tk.X)
  286. frame1_mode_params_column1 = tk.Frame(frame1_mode)
  287. frame1_mode_params_column1.pack(side=tk.LEFT, fill=tk.Y)
  288. frame1_mode_params_column2 = tk.Frame(frame1_mode)
  289. frame1_mode_params_column2.pack(side=tk.RIGHT, fill=tk.Y)
  290. self.open_driver_label = tk.Label(
  291. frame1_mode_params_column1, text="浏览器模式:", width=12
  292. )
  293. self.open_driver_label.pack(side=tk.LEFT, padx=4, pady=8)
  294. self.open_driver_var = tk.BooleanVar(value=config.open_driver)
  295. self.open_driver_checkbutton = ttk.Checkbutton(
  296. frame1_mode_params_column1,
  297. variable=self.open_driver_var,
  298. onvalue=True,
  299. offvalue=False,
  300. command=self.update_open_driver,
  301. text="(若获取更新异常请开启)",
  302. )
  303. self.open_driver_checkbutton.pack(side=tk.LEFT, padx=4, pady=8)
  304. self.open_proxy_label = tk.Label(
  305. frame1_mode_params_column2, text="开启代理:", width=12
  306. )
  307. self.open_proxy_label.pack(side=tk.LEFT, padx=4, pady=8)
  308. self.open_proxy_var = tk.BooleanVar(value=config.open_proxy)
  309. self.open_proxy_checkbutton = ttk.Checkbutton(
  310. frame1_mode_params_column2,
  311. variable=self.open_proxy_var,
  312. onvalue=True,
  313. offvalue=False,
  314. command=self.update_open_proxy,
  315. text="(通过代理进行更新)",
  316. )
  317. self.open_proxy_checkbutton.pack(side=tk.LEFT, padx=4, pady=8)
  318. frame1_channel = tk.Frame(frame1)
  319. frame1_channel.pack(fill=tk.X)
  320. frame1_channel_column1 = tk.Frame(frame1_channel)
  321. frame1_channel_column1.pack(side=tk.LEFT, fill=tk.Y)
  322. frame1_channel_column2 = tk.Frame(frame1_channel)
  323. frame1_channel_column2.pack(side=tk.RIGHT, fill=tk.Y)
  324. self.urls_limit_label = tk.Label(
  325. frame1_channel_column1, text="频道接口数量:", width=12
  326. )
  327. self.urls_limit_label.pack(side=tk.LEFT, padx=4, pady=8)
  328. self.urls_limit_entry = tk.Entry(frame1_channel_column1)
  329. self.urls_limit_entry.pack(side=tk.LEFT, padx=4, pady=8)
  330. self.urls_limit_entry.insert(15, config.urls_limit)
  331. self.urls_limit_entry.bind("<KeyRelease>", self.update_urls_limit)
  332. self.ipv_type_label = tk.Label(
  333. frame1_channel_column2, text="接口协议类型:", width=12
  334. )
  335. self.ipv_type_label.pack(side=tk.LEFT, padx=4, pady=8)
  336. self.ipv_type_combo = ttk.Combobox(frame1_channel_column2)
  337. self.ipv_type_combo.pack(side=tk.LEFT, padx=4, pady=8)
  338. self.ipv_type_combo["values"] = ("ipv4", "ipv6", "all")
  339. self.ipv_type_combo.current(0)
  340. self.ipv_type_combo.bind("<<ComboboxSelected>>", self.update_ipv_type)
  341. frame1_sort = tk.Frame(frame1)
  342. frame1_sort.pack(fill=tk.X)
  343. frame1_sort_column1 = tk.Frame(frame1_sort)
  344. frame1_sort_column1.pack(side=tk.LEFT, fill=tk.Y)
  345. frame1_sort_column2 = tk.Frame(frame1_sort)
  346. frame1_sort_column2.pack(side=tk.RIGHT, fill=tk.Y)
  347. self.open_keep_all_label = tk.Label(
  348. frame1_sort_column1, text="保留模式:", width=12
  349. )
  350. self.open_keep_all_label.pack(side=tk.LEFT, padx=4, pady=8)
  351. self.open_keep_all_var = tk.BooleanVar(value=config.open_keep_all)
  352. self.open_keep_all_checkbutton = ttk.Checkbutton(
  353. frame1_sort_column1,
  354. variable=self.open_keep_all_var,
  355. onvalue=True,
  356. offvalue=False,
  357. command=self.update_open_keep_all,
  358. text="(保留所有检索结果,建议手动维护时开启)",
  359. )
  360. self.open_keep_all_checkbutton.pack(side=tk.LEFT, padx=4, pady=8)
  361. self.open_sort_label = tk.Label(
  362. frame1_sort_column2, text="开启测速排序:", width=12
  363. )
  364. self.open_sort_label.pack(side=tk.LEFT, padx=4, pady=8)
  365. self.open_sort_var = tk.BooleanVar(value=config.open_sort)
  366. self.open_sort_checkbutton = ttk.Checkbutton(
  367. frame1_sort_column2,
  368. variable=self.open_sort_var,
  369. onvalue=True,
  370. offvalue=False,
  371. command=self.update_open_sort,
  372. )
  373. self.open_sort_checkbutton.pack(side=tk.LEFT, padx=4, pady=8)
  374. frame1_sort_params = tk.Frame(frame1)
  375. frame1_sort_params.pack(fill=tk.X)
  376. frame1_sort_params_column1 = tk.Frame(frame1_sort_params)
  377. frame1_sort_params_column1.pack(side=tk.LEFT, fill=tk.Y)
  378. frame1_sort_params_column2 = tk.Frame(frame1_sort_params)
  379. frame1_sort_params_column2.pack(side=tk.RIGHT, fill=tk.Y)
  380. self.response_time_weight_label = tk.Label(
  381. frame1_sort_params_column1, text="响应时间权重:", width=12
  382. )
  383. self.response_time_weight_label.pack(side=tk.LEFT, padx=4, pady=8)
  384. self.response_time_weight_entry = tk.Entry(frame1_sort_params_column1)
  385. self.response_time_weight_entry.pack(side=tk.LEFT, padx=4, pady=8)
  386. self.response_time_weight_entry.insert(0, config.response_time_weight)
  387. self.response_time_weight_entry.bind(
  388. "<KeyRelease>", self.update_response_time_weight
  389. )
  390. self.resolution_weight_label = tk.Label(
  391. frame1_sort_params_column2, text="分辨率权重:", width=12
  392. )
  393. self.resolution_weight_label.pack(side=tk.LEFT, padx=4, pady=8)
  394. self.resolution_weight_entry = tk.Entry(frame1_sort_params_column2)
  395. self.resolution_weight_entry.pack(side=tk.LEFT, padx=4, pady=8)
  396. self.resolution_weight_entry.insert(0, config.resolution_weight)
  397. self.resolution_weight_entry.bind("<KeyRelease>", self.update_resolution_weight)
  398. frame1_domain_blacklist = tk.Frame(frame1)
  399. frame1_domain_blacklist.pack(fill=tk.X)
  400. self.domain_blacklist_label = tk.Label(
  401. frame1_domain_blacklist, text="域名黑名单:", width=12
  402. )
  403. self.domain_blacklist_label.pack(side=tk.LEFT, padx=4, pady=8)
  404. self.domain_blacklist_text = scrolledtext.ScrolledText(
  405. frame1_domain_blacklist, height=5
  406. )
  407. self.domain_blacklist_text.pack(
  408. side=tk.LEFT, padx=4, pady=8, expand=True, fill=tk.BOTH
  409. )
  410. self.domain_blacklist_text.insert(tk.END, ",".join(config.domain_blacklist))
  411. self.domain_blacklist_text.bind("<KeyRelease>", self.update_domain_blacklist)
  412. frame1_url_keywords_blacklist = tk.Frame(frame1)
  413. frame1_url_keywords_blacklist.pack(fill=tk.X)
  414. self.url_keywords_blacklist_label = tk.Label(
  415. frame1_url_keywords_blacklist, text="关键字黑名单:", width=12
  416. )
  417. self.url_keywords_blacklist_label.pack(side=tk.LEFT, padx=4, pady=8)
  418. self.url_keywords_blacklist_text = scrolledtext.ScrolledText(
  419. frame1_url_keywords_blacklist, height=5
  420. )
  421. self.url_keywords_blacklist_text.pack(
  422. side=tk.LEFT, padx=4, pady=8, expand=True, fill=tk.BOTH
  423. )
  424. self.url_keywords_blacklist_text.insert(
  425. tk.END, ",".join(config.url_keywords_blacklist)
  426. )
  427. self.url_keywords_blacklist_text.bind(
  428. "<KeyRelease>", self.update_url_keywords_blacklist
  429. )
  430. frame2_open_online_search = tk.Frame(frame2)
  431. frame2_open_online_search.pack(fill=tk.X)
  432. self.open_online_search_label = tk.Label(
  433. frame2_open_online_search, text="开启在线搜索:", width=13
  434. )
  435. self.open_online_search_label.pack(side=tk.LEFT, padx=4, pady=8)
  436. self.open_online_search_var = tk.BooleanVar(value=config.open_online_search)
  437. self.open_online_search_checkbutton = ttk.Checkbutton(
  438. frame2_open_online_search,
  439. variable=self.open_online_search_var,
  440. onvalue=True,
  441. offvalue=False,
  442. command=self.update_open_online_search,
  443. )
  444. self.open_online_search_checkbutton.pack(side=tk.LEFT, padx=4, pady=8)
  445. frame2_favorite_list = tk.Frame(frame2)
  446. frame2_favorite_list.pack(fill=tk.X)
  447. self.favorite_list_label = tk.Label(
  448. frame2_favorite_list, text="关注频道:", width=13
  449. )
  450. self.favorite_list_label.pack(side=tk.LEFT, padx=4, pady=8)
  451. self.favorite_list_text = scrolledtext.ScrolledText(
  452. frame2_favorite_list, height=5
  453. )
  454. self.favorite_list_text.pack(
  455. side=tk.LEFT, padx=4, pady=8, expand=True, fill=tk.BOTH
  456. )
  457. self.favorite_list_text.insert(tk.END, ",".join(config.favorite_list))
  458. self.favorite_list_text.bind("<KeyRelease>", self.update_favorite_list)
  459. frame2_favorite_page_num = tk.Frame(frame2)
  460. frame2_favorite_page_num.pack(fill=tk.X)
  461. self.favorite_page_num_label = tk.Label(
  462. frame2_favorite_page_num, text="关注获取页数:", width=13
  463. )
  464. self.favorite_page_num_label.pack(side=tk.LEFT, padx=4, pady=8)
  465. self.favorite_page_num_entry = tk.Entry(frame2_favorite_page_num)
  466. self.favorite_page_num_entry.pack(side=tk.LEFT, padx=4, pady=8)
  467. self.favorite_page_num_entry.insert(0, config.favorite_page_num)
  468. self.favorite_page_num_entry.bind("<KeyRelease>", self.update_favorite_page_num)
  469. frame2_default_page_num = tk.Frame(frame2)
  470. frame2_default_page_num.pack(fill=tk.X)
  471. self.default_page_num_label = tk.Label(
  472. frame2_default_page_num, text="默认获取页数:", width=13
  473. )
  474. self.default_page_num_label.pack(side=tk.LEFT, padx=4, pady=8)
  475. self.default_page_num_entry = tk.Entry(frame2_default_page_num)
  476. self.default_page_num_entry.pack(side=tk.LEFT, padx=4, pady=8)
  477. self.default_page_num_entry.insert(0, config.default_page_num)
  478. self.default_page_num_entry.bind("<KeyRelease>", self.update_default_page_num)
  479. frame2_recent_days = tk.Frame(frame2)
  480. frame2_recent_days.pack(fill=tk.X)
  481. self.recent_days_label = tk.Label(
  482. frame2_recent_days, text="获取时间范围(天):", width=13
  483. )
  484. self.recent_days_label.pack(side=tk.LEFT, padx=4, pady=8)
  485. self.recent_days_entry = tk.Entry(frame2_recent_days)
  486. self.recent_days_entry.pack(side=tk.LEFT, padx=4, pady=8)
  487. self.recent_days_entry.insert(30, config.recent_days)
  488. self.recent_days_entry.bind("<KeyRelease>", self.update_recent_days)
  489. frame3_open_subscribe = tk.Frame(frame3)
  490. frame3_open_subscribe.pack(fill=tk.X)
  491. self.open_subscribe_label = tk.Label(
  492. frame3_open_subscribe, text="开启订阅源:", width=9
  493. )
  494. self.open_subscribe_label.pack(side=tk.LEFT, padx=4, pady=8)
  495. self.open_subscribe_var = tk.BooleanVar(value=config.open_subscribe)
  496. self.open_subscribe_checkbutton = ttk.Checkbutton(
  497. frame3_open_subscribe,
  498. variable=self.open_subscribe_var,
  499. onvalue=True,
  500. offvalue=False,
  501. command=self.update_open_subscribe,
  502. )
  503. self.open_subscribe_checkbutton.pack(side=tk.LEFT, padx=4, pady=8)
  504. frame3_subscribe_urls = tk.Frame(frame3)
  505. frame3_subscribe_urls.pack(fill=tk.X)
  506. self.subscribe_urls_label = tk.Label(
  507. frame3_subscribe_urls, text="订阅源:", width=9
  508. )
  509. self.subscribe_urls_label.pack(side=tk.LEFT, padx=4, pady=8)
  510. self.subscribe_urls_text = scrolledtext.ScrolledText(
  511. frame3_subscribe_urls, height=5
  512. )
  513. self.subscribe_urls_text.pack(
  514. side=tk.LEFT, padx=4, pady=8, expand=True, fill=tk.BOTH
  515. )
  516. self.subscribe_urls_text.insert(tk.END, ",".join(config.subscribe_urls))
  517. self.subscribe_urls_text.bind("<KeyRelease>", self.update_subscribe_urls)
  518. frame4_multicast = tk.Frame(frame4)
  519. frame4_multicast.pack(fill=tk.X)
  520. self.open_multicast_label = tk.Label(
  521. frame4_multicast, text="开启组播源:", width=9
  522. )
  523. self.open_multicast_label.pack(side=tk.LEFT, padx=4, pady=8)
  524. self.open_multicast_var = tk.BooleanVar(value=config.open_multicast)
  525. self.open_multicast_checkbutton = ttk.Checkbutton(
  526. frame4_multicast,
  527. variable=self.open_multicast_var,
  528. onvalue=True,
  529. offvalue=False,
  530. command=self.update_open_multicast,
  531. )
  532. self.open_multicast_checkbutton.pack(side=tk.LEFT, padx=4, pady=8)
  533. frame4_region_list = tk.Frame(frame4)
  534. frame4_region_list.pack(fill=tk.X)
  535. self.region_list_label = tk.Label(frame4_region_list, text="组播地区:", width=9)
  536. self.region_list_label.pack(side=tk.LEFT, padx=4, pady=8)
  537. self.region_list_text = scrolledtext.ScrolledText(frame4_region_list, height=5)
  538. self.region_list_text.pack(
  539. side=tk.LEFT, padx=4, pady=8, expand=True, fill=tk.BOTH
  540. )
  541. self.region_list_text.insert(tk.END, ",".join(config.region_list))
  542. self.region_list_text.bind("<KeyRelease>", self.update_region_list)
  543. root_operate = tk.Frame(self.root)
  544. root_operate.pack(fill=tk.X, pady=8, padx=120)
  545. root_operate_column1 = tk.Frame(root_operate)
  546. root_operate_column1.pack(side=tk.LEFT, fill=tk.Y)
  547. root_operate_column2 = tk.Frame(root_operate)
  548. root_operate_column2.pack(side=tk.RIGHT, fill=tk.Y)
  549. self.save_button = tk.Button(
  550. root_operate_column1, text="保存设置", command=self.save_config
  551. )
  552. self.save_button.pack(side=tk.LEFT, padx=4, pady=8)
  553. self.run_button = tk.Button(
  554. root_operate_column2, text="开始更新", command=self.on_run_update
  555. )
  556. self.run_button.pack(side=tk.LEFT, padx=4, pady=8)
  557. version_frame = tk.Frame(self.root)
  558. version_frame.pack(side=tk.BOTTOM, fill=tk.X)
  559. self.version_label = tk.Label(
  560. version_frame, text=self.version, fg="gray", anchor="se"
  561. )
  562. self.version_label.pack(side=tk.RIGHT, padx=5, pady=5)
  563. self.author_label = tk.Label(
  564. version_frame,
  565. text="by Govin",
  566. fg="gray",
  567. anchor="se",
  568. )
  569. self.author_label.pack(side=tk.LEFT, padx=5, pady=5)
  570. self.project_link = tk.Label(
  571. version_frame, text="访问项目主页", fg="blue", cursor="hand2"
  572. )
  573. self.project_link.pack(side=tk.LEFT, padx=5, pady=5)
  574. self.project_link.bind(
  575. "<Button-1>",
  576. lambda e: webbrowser.open_new_tab("https://github.com/Guovin/TV"),
  577. )
  578. root_progress = tk.Frame(self.root)
  579. root_progress.pack(fill=tk.X)
  580. self.progress_bar = ttk.Progressbar(
  581. root_progress, length=300, mode="determinate"
  582. )
  583. self.progress_bar.pack_forget()
  584. self.progress_label = tk.Label(root_progress, text="进度: 0%")
  585. self.progress_label.pack_forget()
  586. self.view_result_link = tk.Label(
  587. root_progress, text="", fg="blue", cursor="hand2"
  588. )
  589. self.view_result_link.bind(
  590. "<Button-1>",
  591. self.view_result_link_callback,
  592. )
  593. self.view_result_link.pack_forget()
  594. if __name__ == "__main__":
  595. root = tk.Tk()
  596. tkinter_ui = TkinterUI(root)
  597. tkinter_ui.init_UI()
  598. screen_width = root.winfo_screenwidth()
  599. screen_height = root.winfo_screenheight()
  600. width = 550
  601. height = 700
  602. x = (screen_width / 2) - (width / 2)
  603. y = (screen_height / 2) - (height / 2)
  604. root.geometry("%dx%d+%d+%d" % (width, height, x, y))
  605. root.mainloop()