Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

整理代码风格、添加下载进度条、软件图标 #3

Merged
merged 2 commits into from
Oct 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added releases/v1.2/favicon.ico
Binary file not shown.
120 changes: 85 additions & 35 deletions releases/v1.2/tchMaterial-parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
import os
import json
import pyperclip
import win32print,win32gui,win32con,win32api,ctypes
import win32print, win32gui, win32con, win32api
import ctypes

# 定义解析URL的函数
def analyze(url):
Expand All @@ -19,11 +20,35 @@ def analyze(url):
contentId = q.split('=')[1]
break

response = requests.get(f"https://s-file-1.ykt.cbern.com.cn/zxx/ndrv2/resources/tch_material/details/{contentId}.json")
# 获得该contentId下书本的信息,返回数据示例:
"""
{
"id": "4f64356a-8df7-4579-9400-e32c9a7f6718",
(...)
"ti_items": [
{
(...),
"ti_storages": [
"https://r1-ndr-private.ykt.cbern.com.cn/edu_product/esp/assets/4f64356a-8df7-4579-9400-e32c9a7f6718.pkg/pdf.pdf",
"https://r2-ndr-private.ykt.cbern.com.cn/edu_product/esp/assets/4f64356a-8df7-4579-9400-e32c9a7f6718.pkg/pdf.pdf",
"https://r3-ndr-private.ykt.cbern.com.cn/edu_product/esp/assets/4f64356a-8df7-4579-9400-e32c9a7f6718.pkg/pdf.pdf"
], // 这就是我们要的pdf
(...)
},
{
(...) // 和上一个元素组成一样
}
]
}
"""
# 不难看出,在ti_items列表下,每一项代表一本书。
response = requests.get(
f'https://s-file-1.ykt.cbern.com.cn/zxx/ndrv2/resources/tch_material/details/{contentId}.json'
)
data = json.loads(response.text)
for item in list(data["ti_items"]):
if item["lc_ti_format"] == "pdf": # 找到存有PDF链接列表的项
pdf_url = item["ti_storages"][0].replace("-private","") # 获取并构建PDF的URL
for item in list(data['ti_items']): # item: 每本书
if item['lc_ti_format'] == 'pdf': # 找到存有PDF链接列表的项
pdf_url = item['ti_storages'][0].replace('-private','') # 获取并构建PDF的URL
break

return pdf_url, contentId
Expand All @@ -32,24 +57,36 @@ def analyze(url):

# 获取默认文件名
def get_default_filename(contentId):
response = requests.get(f"https://s-file-1.ykt.cbern.com.cn/zxx/ndrv2/resources/tch_material/details/{contentId}.json")
response = requests.get(
f'https://s-file-1.ykt.cbern.com.cn/zxx/ndrv2/resources/tch_material/details/{contentId}.json'
)
try:
data = json.loads(response.text)
return data["title"] # 返回教材标题
return data['title'] # 返回教材标题
except:
return None

# 下载文件的函数
def download_file(url, save_path):
response = requests.get(url, stream=True)
total_size = int(response.headers.get('Content-Length', 0))
with open(save_path, 'wb') as file:
download_size = 0
for chunk in response.iter_content(chunk_size=8192): # 分块下载
file.write(chunk)
messagebox.showinfo("完成", f"文件已下载到:{save_path}") # 显示完成对话框
download_size += len(chunk)
if total_size > 0: # 规避 ZeroDivisionError
download_progress = (download_size / total_size) * 100

download_progress_bar['value'] = download_progress
root.update_idletasks()

# print(f'total, {total_size}; down, {download_size}; prog, {download_progress}')
messagebox.showinfo('完成', f'文件已下载到:{save_path}') # 显示完成对话框

# 解析并复制链接的函数
def analyze_and_copy():
urls = [line.strip() for line in url_text.get("1.0", tk.END).splitlines() if line.strip()] # 获取所有非空行
urls = [line.strip() for line in url_text.get('1.0', tk.END).splitlines() if line.strip()] # 获取所有非空行
pdf_links = []
failed_links = []

Expand All @@ -61,21 +98,21 @@ def analyze_and_copy():
pdf_links.append(pdf_url)

if failed_links:
failed_msg = "以下链接无法解析:\n" + '\n'.join(failed_links)
messagebox.showwarning("警告", failed_msg) # 显示警告对话框
failed_msg = '以下链接无法解析:\n' + '\n'.join(failed_links)
messagebox.showwarning('警告', failed_msg) # 显示警告对话框

if pdf_links:
pyperclip.copy("\n".join(pdf_links)) # 将链接复制到剪贴板
messagebox.showinfo("提示", "PDF链接已复制到剪贴板")
pyperclip.copy('\n'.join(pdf_links)) # 将链接复制到剪贴板
messagebox.showinfo('提示', 'PDF链接已复制到剪贴板')

# 下载PDF文件的函数
def download():
urls = [line.strip() for line in url_text.get("1.0", tk.END).splitlines() if line.strip()] # 获取所有非空行
urls = [line.strip() for line in url_text.get('1.0', tk.END).splitlines() if line.strip()] # 获取所有非空行
failed_links = []

if len(urls) > 1:
messagebox.showinfo("提示", "您选择了多个链接,将在选定的文件夹中使用教材名称作为文件名进行下载。")
dir_path = filedialog.askdirectory().replace("/","\\") # 选择文件夹
messagebox.showinfo('提示', '您选择了多个链接,将在选定的文件夹中使用教材名称作为文件名进行下载。')
dir_path = filedialog.askdirectory().replace('/','\\') # 选择文件夹
if not dir_path:
return
else:
Expand All @@ -88,19 +125,26 @@ def download():
continue

if dir_path:
default_filename = get_default_filename(contentId) or "download"
save_path = os.path.join(dir_path, f"{default_filename}.pdf") # 构造完整路径
default_filename = get_default_filename(contentId) or 'download'
save_path = os.path.join(dir_path, f'{default_filename}.pdf') # 构造完整路径
else:
default_filename = get_default_filename(contentId) or "download"
save_path = filedialog.asksaveasfilename(defaultextension=".pdf", filetypes=[("PDF files", "*.pdf"), ("All files", "*.*")], initialfile=default_filename).replace("/","\\") # 选择保存路径
default_filename = get_default_filename(contentId) or 'download'
save_path = filedialog.asksaveasfilename(defaultextension='.pdf', filetypes=[('PDF files', '*.pdf'), ('All files', '*.*')], initialfile=default_filename).replace('/','\\') # 选择保存路径
if not save_path:
return

threading.Thread(target=download_file, args=(pdf_url, save_path)).start() # 开始下载
thread_it(download_file, (pdf_url, save_path)) # 开始下载(多线程,防止窗口卡死)
# threading.Thread(target=download_file, args=(pdf_url, save_path)).start() # 开始下载

if failed_links:
failed_msg = "以下链接无法解析:\n" + '\n'.join(failed_links)
messagebox.showwarning("警告", failed_msg) # 显示警告对话框
failed_msg = '以下链接无法解析:\n' + '\n'.join(failed_links)
messagebox.showwarning('警告', failed_msg) # 显示警告对话框

def thread_it(func, args: tuple):
# 打包函数到线程
t = threading.Thread(target=func, args=args)
# t.daemon = True
t.start()

scale = round(win32print.GetDeviceCaps(win32gui.GetDC(0), win32con.DESKTOPHORZRES) / win32api.GetSystemMetrics(0), 2) # 获取屏幕缩放比例

Expand All @@ -109,28 +153,32 @@ def download():

#----------高DPI适配start---------

#获得当前的缩放因子
ScaleFactor=round(win32print.GetDeviceCaps(win32gui.GetDC(0), win32con.DESKTOPHORZRES) / win32api.GetSystemMetrics (0), 2)
# 获得当前的缩放因子
ScaleFactor = round(win32print.GetDeviceCaps(win32gui.GetDC(0), win32con.DESKTOPHORZRES) / win32api.GetSystemMetrics (0), 2)

#调用api设置成由应用程序缩放
# 调用api设置成由应用程序缩放
try: # 系统版本 >= win 8.1
ctypes.windll.shcore.SetProcessDpiAwareness(2)
except: # 系统版本 <= win 8.0
ctypes.windll.user32.SetProcessDPIAware()

#设置缩放因子
# 设置缩放因子
root.tk.call('tk', 'scaling', ScaleFactor/0.75)

#----------高DPI适配end---------

root.title("国家中小学智慧教育平台 电子课本解析") # 设置窗口标题
# root.geometry("900x600") # 设置窗口大小
root.title('国家中小学智慧教育平台 电子课本解析') # 设置窗口标题
# root.geometry('900x600') # 设置窗口大小

# 设置ico文件
if os.path.exists('favicon.ico'):
root.iconbitmap('favicon.ico')

# 创建一个容器框架
container_frame = ttk.Frame(root)
container_frame.pack(anchor='center',expand='yes', padx=int(20*scale), pady=int(20*scale)) # 容器的中心位置放置,允许组件在容器中扩展,水平外边距40,垂直外边距40

title_label = ttk.Label(container_frame, text="国家中小学智慧教育平台 电子课本解析", font=("微软雅黑", 16, "bold")) # 添加标题标签
title_label = ttk.Label(container_frame, text='国家中小学智慧教育平台 电子课本解析', font=('微软雅黑', 16, 'bold')) # 添加标题标签
title_label.pack(pady=int(5*scale)) # 设置垂直外边距(跟随缩放)

description = '''请在下面的文本框中粘贴一个或多个课本原网址(支持批量每个URL一行)。
Expand All @@ -139,16 +187,18 @@ def download():
assets_document&contentId=b8e9a3fe-dae7-49c0-86cb-d146f88
3fd8e&catalogType=tchMaterial&subCatalog=tchMaterial
点击下载按钮后,程序会解析并下载所有PDF文件。'''
description_label = ttk.Label(container_frame, text=description, justify="left") # 添加描述标签
description_label = ttk.Label(container_frame, text=description, justify='left') # 添加描述标签
description_label.pack(pady=int(5*scale)) # 设置垂直外边距(跟随缩放)

url_text = tk.Text(container_frame, width=70, height=12) # 添加URL输入框,长度和宽度不使用缩放!!!
url_text.pack(padx=int(15*scale), pady=int(15*scale)) # 设置水平外边距、垂直外边距(跟随缩放)

download_btn = ttk.Button(container_frame, text="下载", command=download) # 添加下载按钮
download_btn.pack(side="left", padx=int(40*scale), pady=int(5*scale), ipady=int(5*scale)) # 设置水平外边距、垂直外边距(跟随缩放),设置按钮高度(跟随缩放)
download_btn = ttk.Button(container_frame, text='下载', command=download) # 添加下载按钮
download_btn.pack(side='left', padx=int(40*scale), pady=int(5*scale), ipady=int(5*scale)) # 设置水平外边距、垂直外边距(跟随缩放),设置按钮高度(跟随缩放)

copy_btn = ttk.Button(container_frame, text="解析并复制", command=analyze_and_copy) # 添加“解析并复制”按钮
copy_btn.pack(side="right", padx=int(40*scale), pady=int(5*scale), ipady=int(5*scale)) # 设置水平外边距、垂直外边距(跟随缩放),设置按钮高度(跟随缩放)
copy_btn = ttk.Button(container_frame, text='解析并复制', command=analyze_and_copy) # 添加“解析并复制”按钮
copy_btn.pack(side='right', padx=int(40*scale), pady=int(5*scale), ipady=int(5*scale)) # 设置水平外边距、垂直外边距(跟随缩放),设置按钮高度(跟随缩放)

download_progress_bar = ttk.Progressbar(container_frame, length=(125*scale), mode='determinate')
download_progress_bar.pack(side='bottom', padx=int(40*scale), pady=int(10*scale), ipady=int(10*scale))
root.mainloop() # 开始主循环