This repository has been archived by the owner on Dec 15, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 23
/
app.py
700 lines (607 loc) · 25.5 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
# -*- coding: utf-8 -*-
"""
GUI app
@author: yanyongyu
"""
__author__ = "yanyongyu"
__version__ = "1.5.5"
import asyncio
import logging
import traceback
import threading
import webbrowser
import requests
from lxml import etree
from tkinter import *
from tkinter.ttk import *
from tkinter.messagebox import showinfo, askyesno
import api
class AutoShowScrollbar(Scrollbar):
"会自动隐藏的滚动条"
def set(self, lo, hi):
if float(lo) <= 0.0 and float(hi) >= 1.0:
# grid_remove is currently missing from Tkinter!
self.tk.call("pack", "forget", self)
else:
self.pack(fill=Y, side=RIGHT, expand=False)
Scrollbar.set(self, lo, hi)
class App():
PLUGIN_CX_URL = "https://github.com/CodFrm/cxmooc-tools/releases"
TOOL_URL = "https://github.com/yanyongyu/CXmoocSearchTool/releases"
ISSUE_URL = "https://github.com/yanyongyu/CXmoocSearchTool/issues"
QQ_URL = "https://jq.qq.com/?_wv=1027&k=5FPg14d"
UNFREEZE_JS = r"""
(function() {
var doc = document,
bd = doc.body;
bd.onselectstart = bd.oncopy = bd.onpaste = bd.onkeydown = bd.oncontextmenu = bd.onmousemove = bd.onselectstart = bd.ondragstart = doc.onselectstart = doc.oncopy = doc.onpaste = doc.onkeydown = doc.oncontextmenu = null;
doc.onselectstart = doc.oncontextmenu = doc.onmousedown = doc.onkeydown = function() {
return true;
};
with (doc.wrappedJSObject || doc) {
onmouseup = null;
onmousedown = null;
oncontextmenu = null;
};
var allElements = doc.getElementsByTagName('*');
for (var i = allElements.length; i > 0;) {
var elmOne = allElements[--i];
with (elmOne.wrappedJSObject || elmOne) {
onmouseup = null;
onmousedown = null;
};
};
alert('已解除复制与右键限制!\n欢迎加入群聊:614202391');
bd.style.webkitUserSelect = 'auto!important';
bd.style.MozUserSelect = 'normal!important';
})();
"""
ZHS_JS = """
function speedUp_muted_bq() {
$(".speedTab15")[0].click();
setTimeout(function() {
document.getElementById("vjs_mediaplayer_html5_api").muted = true;
}, 1000);
$(".line1bq")[0].click();
}
function autoChooseTest() {
//check if the test window is open
if (!document.getElementById("tmDialog_iframe")) {
return;
} else {
//choose right answer
var myradio = document.getElementById("tmDialog_iframe").contentWindow.document.getElementsByClassName("answerOption");
for (var i = 0; i < myradio.length; i++) {
if (myradio[i].getElementsByTagName("input")[0].getAttribute("_correctanswer") == "1")
myradio[i].getElementsByTagName("input")[0].click();
//double click checked;
if (myradio[i].getElementsByTagName("input")[0].getAttribute("checked") == "checked")
myradio[i].getElementsByTagName("input")[0].click();
}
}
//close the window of answer
for (var i = 0; i < $(".popbtn_cancel span").length; i++) {
if ($(".popbtn_cancel span")[i].innerHTML == "关闭" || $(".popbtn_cancel span")[i].innerHTML == "Close") {
$(".popbtn_cancel span")[i].click();
//console.log($(".popbtn_cancel span")[i].innerHTML);
}
}
}
function nextVideo() {
var video = document.getElementById("vjs_mediaplayer_html5_api");
//testTest if it has accelerated
if (video.playbackRate != 1.5) {
setTimeout(function() {
speedUp_muted_bq();
}, 1500);
}
if ((video.currentTime / video.duration) >= 1) {
console.log("Finish");
$(".tm_next_lesson")[0].click();
setTimeout(function() {
speedUp_muted_bq();
}, 1500);
}
//If a chapter is finish, test if next video is as same to the current video
}
speedUp_muted_bq();
if (myInterval) {
clearInterval(myInterval);
}
var myInterval = setInterval(function() {
autoChooseTest();
console.log(new Date().getSeconds());
nextVideo();
}, 5000);
"""
def __init__(self):
# 加载api
self.api_list = {}
self.api_on = {}
for attr in dir(api):
if attr.startswith('_'):
continue
fn = getattr(api, attr)
if callable(fn) and getattr(fn, '__annotations__', None):
self.api_list[attr] = fn
# 初始化session
self.sess = requests.Session()
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/72.0.3626.119 Safari/537.36'}
self.sess.headers.update(headers)
# 初始化text列表
self.text = []
self.start_coroutine(self.scan_release(True))
self.show()
def show(self):
"显示主窗口"
self.root = Tk()
self.root.title(
"查题助手v%s -designed by ShowTime-Joker" % __version__)
# 窗口居中坐标
sw = self.root.winfo_screenwidth()
sh = self.root.winfo_screenheight()
x = (sw - 1000) / 2 - 25
y = (sh - 590) / 2 - 25
# 宽、高、相对屏幕坐标
self.root.geometry('%dx%d+%d+%d' % (600, 105, x, y))
# 不允许缩放
self.root.resizable(False, False)
# style初始化
style = Style()
style.configure('White.TFrame', background='white')
style.configure('TMenu', font=('微软雅黑', 12))
style.configure('TLabel', font=('微软雅黑', 12))
style.configure('TButton', font=('微软雅黑', 12))
# 菜单栏
# 顶级菜单
menu = Menu(self.root)
# api子菜单
api_menu = Menu(menu, tearoff=0)
for api in self.api_list.keys():
self.api_on[api] = IntVar()
self.api_on[api].set(1)
api_menu.add_checkbutton(label=api, variable=self.api_on[api])
menu.add_cascade(label="题库来源", menu=api_menu)
# 插件菜单
plugin_menu = Menu(menu, tearoff=0)
plugin_menu.add_cascade(
label="超星",
command=lambda: webbrowser.open(App.PLUGIN_CX_URL)
)
plugin_menu.add_cascade(
label="智慧树脚本",
command=lambda: self.zhs_js()
)
plugin_menu.add_cascade(
label="解除右键锁定",
command=lambda: self.unfreeze_js()
)
menu.add_cascade(label="浏览器插件", menu=plugin_menu)
# 选项菜单
option_menu = Menu(menu, tearoff=0)
self.isTop = IntVar()
self.isTop.set(0)
self.isBreak = IntVar()
self.isBreak.set(0)
option_menu.add_checkbutton(
label="窗口置顶", variable=self.isTop,
command=lambda: self.root_top_show()
)
option_menu.add_checkbutton(
label="中断式查询", variable=self.isBreak
)
menu.add_cascade(label="选项", menu=option_menu)
# 帮助菜单
help_menu = Menu(menu, tearoff=0)
help_menu.add_command(label="使用说明", command=self.usage)
help_menu.add_command(
label="检查更新",
command=lambda: self.start_coroutine(self.scan_release(False))
)
help_menu.add_command(
label="反馈问题",
command=lambda: webbrowser.open(App.ISSUE_URL)
)
help_menu.add_command(
label="加入我们",
command=lambda: webbrowser.open(App.QQ_URL)
)
menu.add_cascade(label="帮助", menu=help_menu)
self.root['menu'] = menu
# 输入框
frame2 = Frame(self.root, style='White.TFrame')
frame2.pack(side=TOP, fill=BOTH, expand=True)
# 显示画布
canvas = Canvas(frame2, height=70)
canvas.pack(side=LEFT, fill=X, expand=True)
# 内容框架
frame_in = Frame(canvas)
frame_id = canvas.create_window(0, 0, window=frame_in, anchor=NW)
# 动态隐藏滚动条
vbar = AutoShowScrollbar(frame2, orient=VERTICAL)
vbar.pack(fill=Y, side=RIGHT, expand=False)
# 互相绑定滚动
vbar.config(command=canvas.yview)
canvas.configure(yscrollcommand=vbar.set)
# 界面鼠标滚动函数
def _scroll_canvas(event):
canvas.yview_scroll(int(-event.delta / 60), 'units')
def _unscroll_canvas(event):
return 'break'
# 内容框架大小适配
def _configure_frame(event):
# 更新画布的滚动范围以适配内部框架
size = (frame_in.winfo_reqwidth(), frame_in.winfo_reqheight())
canvas.config(scrollregion="0 0 %s %s" % size)
if frame_in.winfo_reqwidth() != canvas.winfo_width():
# 更新画布宽度以适配内部框架
canvas.config(width=frame_in.winfo_reqwidth())
if len(self.text) <= 3:
self.root.geometry('%dx%d' % (600, 35 + 70*len(self.text)))
canvas.config(height=frame_in.winfo_reqheight())
elif len(self.text) > 3:
self.root.geometry('%dx%d' % (600, 35 + 70*3))
canvas.config(height=210)
if frame_in.winfo_reqheight() < canvas.winfo_height():
canvas.bind_all('<MouseWheel>', _unscroll_canvas)
else:
canvas.bind_all('<MouseWheel>', _scroll_canvas)
def _configure_canvas(event):
if frame_in.winfo_reqwidth() != canvas.winfo_width():
# 更新内部框架大小以适配画布大小
canvas.itemconfigure(frame_id, width=canvas.winfo_width())
frame_in.bind('<Configure>', _configure_frame)
canvas.bind('<Configure>', _configure_canvas)
canvas.bind_all('<MouseWheel>', _scroll_canvas)
canvas.bind_all("<ButtonRelease-2>", lambda x: self.start_search())
# 删除输入框
def _delete_entry(event):
button = event.widget
frame = button.master
if len(self.text) > 1:
self.text.remove(frame.children['!text'])
frame.forget()
# 增加输入框
def _create_entry():
frame = Frame(frame_in)
frame.pack(side=TOP, expand=True)
text = Text(frame, height=2, width=45,
borderwidth=2, font=('微软雅黑', 15))
text.grid(row=0, column=0, padx=2, pady=5, rowspan=2)
delete_button = Button(frame, text="-", width=2)
delete_button.grid(row=0, column=1, padx=2, pady=2)
delete_button.bind("<Button-1>", _delete_entry)
add_button = Button(frame, text="+", width=2,
command=_create_entry)
add_button.grid(row=1, column=1, padx=2, pady=2)
self.text.append(text)
return text
_create_entry()
# 超星一键粘贴
def _cx_paste():
question = self.scan_cx()
if not question:
showinfo(
title="查题助手",
message="未能检索到题目!\n目前支持html源码粘贴以及【题目类型】特征识别")
return
for each in question:
text = _create_entry()
text.insert(1.0, each)
def _zhs_paste():
question = self.scan_zhs()
if not question:
showinfo(
title="查题助手",
message="未能检索到题目!\n目前支持html源码粘贴以及【题目类型】特征识别")
return
for each in question:
text = _create_entry()
text.insert(1.0, each)
# 查询按钮框
frame3 = Frame(self.root, style='White.TFrame')
frame3.pack(side=BOTTOM, fill=X)
button1 = Button(frame3, text="查询", command=self.start_search)
button1.pack(side=LEFT, expand=True)
button2 = Button(frame3, text="超星粘贴", command=_cx_paste)
button2.pack(side=RIGHT, expand=False)
button3 = Button(frame3, text="智慧树粘贴", command=_zhs_paste)
button3.pack(side=RIGHT, expand=False)
self.root.update()
self.root.mainloop()
def root_top_show(self):
"窗口置顶切换"
if self.isTop.get():
self.root.wm_attributes('-topmost', 1)
else:
self.root.wm_attributes('-topmost', 0)
def usage(self):
"显示使用说明窗口"
top = Toplevel(self.root)
top.geometry('350x250')
top.resizable(False, False)
top.wm_attributes('-topmost', 1)
frame = Frame(top)
frame.pack(fill=BOTH)
Label(frame, text="复制题目到输入框,一个输入框只能输入一题!").pack()
Label(frame, text="如需多题查询点击 + 号增加输入框。").pack()
Label(frame, text="或直接选择一键粘贴(特征检测【】或html源码)").pack()
Label(frame, text="点击查询或使用鼠标中键开始查询").pack()
Label(frame, text="非中断式查询会查询所有api但更慢").pack()
Label(frame, text="本软件自动检测更新").pack()
Label(frame, text="目前题库包含超星尔雅、知到智慧树。").pack()
Label(frame, text="如遇到问题请点击帮助-反馈问题").pack()
Label(frame, text="或点击加入我们加群反馈").pack()
def zhs_js(self):
top = Toplevel(self.root)
top.geometry('350x180')
top.resizable(False, False)
top.wm_attributes('-topmost', 1)
frame = Frame(top)
frame.pack(fill=BOTH)
# 复制到剪切板
def _copy():
self.root.clipboard_clear()
self.root.clipboard_append(App.ZHS_JS)
Label(frame, text="点击复制按钮,到浏览器页面").pack()
Label(frame, text="按F12或者Ctrl+Shift+i打开开发者工具").pack()
Label(frame, text="切换到Console栏粘贴并回车").pack()
Label(frame, text="提示成功即解除成功!部分浏览器可能不支持").pack()
Label(frame, text="原项目地址:https://github.com/tignioj/").pack()
Label(frame, text="test_login/tree/master/zhs/").pack()
Button(frame, text="点我复制", command=_copy).pack()
def unfreeze_js(self):
"显示解除右键限制说明"
top = Toplevel(self.root)
top.geometry('350x150')
top.resizable(False, False)
top.wm_attributes('-topmost', 1)
frame = Frame(top)
frame.pack(fill=BOTH)
# 复制到剪切板
def _copy():
self.root.clipboard_clear()
self.root.clipboard_append(App.UNFREEZE_JS)
Label(frame, text="点击复制按钮,到浏览器页面").pack()
Label(frame, text="按F12或者Ctrl+Shift+i打开开发者工具").pack()
Label(frame, text="切换到Console栏粘贴并回车").pack()
Label(frame, text="提示成功即解除成功!部分浏览器可能不支持").pack()
Button(frame, text="点我复制", command=_copy).pack()
def scan_cx(self):
clipboard_text = self.root.clipboard_get().strip()
selector = etree.HTML(clipboard_text)
cx_html = selector.xpath('//div[@class="clearfix"]')
html = list(map(lambda x: x.xpath("string(.)").strip(), cx_html))
cx_text = clipboard_text.split("\n")
question = html or cx_text
print(question)
raw_question = [each[each.index("】") + 1:]
for each in question if each.find("】") != -1]
return raw_question
def scan_zhs(self):
clipboard_text = self.root.clipboard_get().strip()
selector = etree.HTML(clipboard_text)
zhs_html = selector.xpath('//div[@class="subject_describe"]')
html = list(map(lambda x: x.xpath("string(.)").strip(), zhs_html))
zhs_text = clipboard_text.split("\n")
question = html or zhs_text
raw_question = [question[i + 1]
for i in range(len(question) - 1)
if question[i].find("】") != -1
if question[i].find(r")") != -1]
return raw_question
def start_search(self):
"开始搜索,显示答案窗口"
text = [each.get(1.0, END).strip(' \n\r') for each in self.text]
text_out_of_order = list(set(text))
text = sorted(text_out_of_order, key=text.index)
try:
text.remove('')
except ValueError:
pass
logging.info("Text get: %s" % text)
index = 0
if text:
# 显示toplevel
top = Toplevel(self.root)
top.geometry('400x300')
top.resizable(False, False)
top.wm_attributes('-topmost', 1)
# 根框架
frame_root = Frame(top, style="White.TFrame")
frame_root.pack(fill=BOTH)
# 上/下一题按钮
frame_button = Frame(top)
frame_button.pack(side=BOTTOM, fill=X)
previous_button = Button(frame_button, text="上一题")
previous_button.pack(side=LEFT, expand=True)
next_button = Button(frame_button, text="下一题")
next_button.pack(side=RIGHT, expand=True)
frame_list = [self.show_frame(frame_root) for i in range(len(text))]
frame_list[index].pack(side=TOP, fill=BOTH, expand=True)
# 上一题
def _previous(event):
nonlocal index, frame_list
if index > 0:
frame_list[index].pack_forget()
index -= 1
frame_list[index].pack(side=TOP, fill=BOTH, expand=True)
# 下一题
def _next(event):
nonlocal index, frame_list
if index < len(frame_list) - 1:
frame_list[index].pack_forget()
index += 1
frame_list[index].pack(side=TOP, fill=BOTH, expand=True)
previous_button.bind('<ButtonRelease-1>', _previous)
next_button.bind('<ButtonRelease-1>', _next)
# 开始搜索线程
logging.info("Start search.")
self.start_coroutine(self.search(frame_list))
async def search(self, frame_list):
text = [each.get(1.0, END).strip(' \n\r') for each in self.text]
text_out_of_order = list(set(text))
text = sorted(text_out_of_order, key=text.index)
try:
text.remove('')
except ValueError:
pass
# 初始化async迭代器
generator_list = {}
for api in self.api_list.keys():
if self.api_on[api].get():
generator_list[api] = self.api_list[api](self.sess, *text)
# 启动迭代器
logging.info("Active generator %s" % api)
await generator_list[api].asend(None)
# 查询答案
for i in range(len(text)):
label = frame_list[i].children['!text']
label.configure(state="normal")
for generator in generator_list.keys():
label.insert(END, f"查询中。。。使用源{generator}\n")
label.configure(state="disable")
try:
result = await generator_list[generator].asend(i)
except Exception as e:
logging.error(repr(e))
label.configure(state="normal")
if result and result[0]['correct']:
for answer in result:
label.insert(END, f"{answer['topic'].strip()}\n")
label.insert(END, f"答案:{answer['correct'].strip()}\n")
if self.isBreak.get():
break
label.insert(END, "查询完毕!")
label.configure(state="disable")
# 关闭event loop
loop = asyncio.get_event_loop()
loop.call_soon_threadsafe(loop.stop)
def show_frame(self, frame_root):
# 总体框架
frame_out = Frame(frame_root)
text = Text(frame_out, width=30, height=12, font=('微软雅黑', 12))
text.pack(fill=BOTH, side=LEFT, expand=True)
text.insert(END, "正在等待查询。。。\n")
text.configure(state="disable")
vbar = AutoShowScrollbar(frame_out, orient=VERTICAL)
vbar.pack(fill=Y, side=RIGHT, expand=False)
vbar.configure(command=text.yview)
text.configure(yscrollcommand=vbar.set)
# 界面鼠标滚动函数
def _scroll_text(event):
text.yview_scroll(int(-event.delta / 60), 'units')
# # 内容框架大小适配
# def _configure_frame(event):
# if frame_root.winfo_width() != frame_out.winfo_reqwidth():
# print(frame_out.winfo_reqwidth(), frame_out.winfo_width())
# print(text.winfo_reqwidth(), text.winfo_width())
# frame_out.configure(width=frame_root.winfo_width())
# print(frame_out.winfo_reqwidth(), frame_out.winfo_width())
# print(text.winfo_reqwidth(), text.winfo_width())
#
# frame_out.bind_all("<Configure>", _configure_frame)
frame_out.bind_all("<MouseWheel>", _scroll_text)
# =============================================================================
# # 显示画布
# canvas = Canvas(frame_out)
# canvas.pack(side=LEFT, fill=BOTH, expand=True)
# # 内容框架
# frame = Frame(canvas)
# frame_id = canvas.create_window(0, 0, window=frame, anchor=NW)
# # 内容标签
# label1 = Label(frame, text="", wraplength=380)
# label1.pack(side=TOP, fill=BOTH)
#
# # 动态隐藏滚动条
# vbar = AutoShowScrollbar(frame_out, orient=VERTICAL)
# vbar.pack(fill=Y, side=RIGHT, expand=False)
#
# # 互相绑定滚动
# vbar.config(command=canvas.yview)
# canvas.configure(yscrollcommand=vbar.set)
#
# # 界面鼠标滚动函数
# def _scroll_canvas(event):
# canvas.yview_scroll(int(-event.delta / 60), 'units')
#
# def _unscroll_canvas(event):
# return 'break'
#
# # 内容框架大小适配
# def _configure_frame(event):
# # 更新画布的滚动范围以适配内部框架
# size = (frame.winfo_reqwidth(), frame.winfo_reqheight())
# canvas.config(scrollregion="0 0 %s %s" % size)
# if frame.winfo_reqwidth() != canvas.winfo_width():
# # 更新画布大小以适配内部框架
# canvas.config(width=frame.winfo_reqwidth())
# if frame.winfo_reqheight() < canvas.winfo_height():
# canvas.bind_all('<MouseWheel>', _unscroll_canvas)
# else:
# canvas.bind_all('<MouseWheel>', _scroll_canvas)
#
# def _configure_canvas(event):
# if frame.winfo_reqwidth() != canvas.winfo_width():
# # 更新内部框架大小以适配画布大小
# canvas.itemconfigure(frame_id, width=canvas.winfo_width())
#
# frame.bind('<Configure>', _configure_frame)
# canvas.bind('<Configure>', _configure_canvas)
# canvas.bind_all('<MouseWheel>', _scroll_canvas)
# =============================================================================
return frame_out
def _start_loop(self, loop):
asyncio.set_event_loop(self.loop)
self.loop.run_forever()
def start_coroutine(self, coroutine):
new_loop = asyncio.new_event_loop()
self.loop = new_loop
t = threading.Thread(target=self._start_loop, args=(new_loop,))
t.start()
asyncio.run_coroutine_threadsafe(coroutine, self.loop)
async def scan_release(self, silence):
"检查更新"
URL = "https://api.github.com/repos/"\
"yanyongyu/CXmoocSearchTool/releases/latest"
try:
res = self.sess.get(URL)
res.raise_for_status()
except requests.exceptions.RequestException as e:
logging.info("Request Exception appeared: %s" % e)
showinfo(title="查题助手",
message="检查更新失败了!")
else:
info = res.json()
latest = info['tag_name'].strip("v").split('.')
now = __version__.split('.')
if latest == now:
if not silence:
showinfo(title="查题助手",
message="已是最新版本!无需更新。")
return
if len(latest) < len(now):
latest.append('0')
elif len(latest) > len(now):
now.append('0')
for i in range(len(now)):
if latest[i] > now[i]:
if askyesno(title="查题助手",
message="发现新版本%s!是否前去更新?"
% info['tag_name']):
webbrowser.open(info['html_url'])
if info['assets'][0]['name'].endswith('.exe'):
webbrowser.open(
info['assets'][0]['browser_download_url'])
break
finally:
loop = asyncio.get_event_loop()
loop.call_soon_threadsafe(loop.stop)
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
try:
app = App()
except Exception:
traceback.print_exc()