Skip to content

Commit

Permalink
Merge pull request #72 from Hpero4/main
Browse files Browse the repository at this point in the history
实现战绩搜索历史
  • Loading branch information
Zzaphkiel authored Sep 23, 2023
2 parents e95712c + 5be287e commit 4aa1e10
Show file tree
Hide file tree
Showing 9 changed files with 288 additions and 20 deletions.
12 changes: 11 additions & 1 deletion app/common/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
from PyQt5.QtCore import QLocale

from qfluentwidgets import (qconfig, QConfig, ConfigItem, FolderValidator, BoolValidator,
OptionsConfigItem, OptionsValidator, ConfigSerializer, RangeConfigItem, RangeValidator)
OptionsConfigItem, OptionsValidator, ConfigSerializer, RangeConfigItem, RangeValidator,
EnumSerializer)


class Language(Enum):
Expand Down Expand Up @@ -76,6 +77,15 @@ class Config(QConfig):

enableCloseToTray = ConfigItem(
"General", "EnableCloseToTray", None, OptionsValidator([None, True, False]))

searchHistory = ConfigItem(
"Other", "SearchHistory", ""
)

enableCheckUpdate = ConfigItem("General",
"EnableCheckUpdate", True,
BoolValidator())

# enableCopyPlayersInfo = ConfigItem("Functions", "EnableCopyPlayersInfo",
# False, BoolValidator())

Expand Down
1 change: 1 addition & 0 deletions app/common/icons.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class Icon(FluentIconBase, Enum):
TEAM = 'Team'
SETTING = 'Setting'
FILTER = 'Filter'
UPDATE = 'Update'

def path(self, theme=Theme.AUTO):
return f'./app/resource/icons/{self.value}_{getIconColor(theme)}.svg'
28 changes: 28 additions & 0 deletions app/common/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import requests

from app.common.config import cfg, VERSION


class Github:
def __init__(self, user="Zzaphkiel", repositories="Seraphine"):
self.API = "http://api.github.com"

self.user = user
self.repositories = repositories
self.sess = requests.session()

def getReleasesInfo(self):
url = f"{self.API}/repos/{self.user}/{self.repositories}/releases/latest"
return self.sess.get(url, verify=False).json()

def checkUpdate(self):
"""
检查版本更新
@return: 有更新 -> info, 无更新 -> None
"""
info = self.getReleasesInfo()
if info.get("tag_name")[1:] != VERSION:
return info
return None

github = Github()
91 changes: 91 additions & 0 deletions app/components/search_line_edit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
from PyQt5.QtCore import Qt, QEvent, QAbstractItemModel
from PyQt5.QtWidgets import QCompleter, QAction
from PyQt5.uic.properties import QtCore, QtGui
from qfluentwidgets import SearchLineEdit as QSearchLineEdit
from qfluentwidgets.components.widgets.line_edit import CompleterMenu

from app.common.config import cfg


class MyCompleterMenu(CompleterMenu):

def eventFilter(self, obj, e):
if e.type() != QEvent.KeyPress:
return super().eventFilter(obj, e)

# redirect input to line edit
self.lineEdit.event(e)
self.view.event(e)

if e.key() == Qt.Key_Escape:
self.close()
if e.key() in [Qt.Key_Enter, Qt.Key_Return]:
self.lineEdit.searchButton.click()
self.close()

return True

def setCompletion(self, model: QAbstractItemModel):
""" set the completion model """
items = []
for i in range(model.rowCount()):
for j in range(model.columnCount()):
items.append(model.data(model.index(i, j)))

if self.items == items and self.isVisible():
return False

self.clear()
self.items = items

# add items
for i in items:
self.addAction(QAction(i, triggered=lambda c, x=i: self.__onItemSelected(x)))

return True

def __onItemSelected(self, text):
self.lineEdit.setText(text)
self.activated.emit(text)
self.lineEdit.searchButton.click()


class SearchLineEdit(QSearchLineEdit):
def __init__(self, parent=None):
super().__init__(parent)

completer = QCompleter([], self)
completer.setCaseSensitivity(Qt.CaseInsensitive)
completer.setMaxVisibleItems(10)
completer.setFilterMode(Qt.MatchFlag.MatchFixedString)
completer.setCompletionRole(Qt.DisplayRole)
completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
self.setCompleter(completer)

def _showCompleterMenu(self):
if not self.completer():
return

model = cfg.get(cfg.searchHistory)
if not model:
return

model = model.split(",")
self.completer().model().setStringList(model)

# create menu
if not self._completerMenu:
self._completerMenu = MyCompleterMenu(self)
self._completerMenu.activated.connect(self._completer.activated)

# add menu items
changed = self._completerMenu.setCompletion(self.completer().completionModel())
self._completerMenu.setMaxVisibleItems(self.completer().maxVisibleItems())

# show menu
if changed:
self._completerMenu.popup()

def focusInEvent(self, e):
self._showCompleterMenu()
super().focusInEvent(e)
32 changes: 32 additions & 0 deletions app/components/update_message_box.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from PyQt5.QtWidgets import QLabel
from qfluentwidgets import MessageBox, MessageBoxBase, SmoothScrollArea, SubtitleLabel, BodyLabel, TextEdit, TitleLabel, \
CheckBox

from app.common.config import VERSION, cfg


class UpdateMessageBox(MessageBoxBase):
def __init__(self, info, parent=None):
super().__init__(parent=parent)
self.titleLabel = TitleLabel(self.tr('Update detected'), self)
self.titleLabel.setContentsMargins(5, 0, 5, 0)
self.content = BodyLabel(self.tr(f'{VERSION} -> {info.get("tag_name")[1:]}'), self)
self.content.setContentsMargins(8, 0, 5, 0)

textEdit = TextEdit(self)
textEdit.setFixedWidth(int(self.width() * .6))
textEdit.setMarkdown(self.tr(info.get("body")))
textEdit.setReadOnly(True)

checkBox = CheckBox()
checkBox.setText("Don't remind me again")
checkBox.clicked.connect(lambda: cfg.set(cfg.enableCheckUpdate, not checkBox.isChecked(), True))

self.viewLayout.addWidget(self.titleLabel)
self.viewLayout.addWidget(self.content)
self.viewLayout.addWidget(textEdit)
self.viewLayout.addWidget(checkBox)

self.yesButton.setText("Download")


46 changes: 39 additions & 7 deletions app/lol/connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,50 @@
requests.packages.urllib3.disable_warnings()


def slowly():
def decorator(func):
def wrapper(*args, **kwargs):
while connector.tackleFlag.is_set():
time.sleep(.2)

connector.slowlyFlag.set()
res = func(*args, **kwargs)
connector.slowlyFlag.clear()
return res
return wrapper
return decorator


def tackle():
def decorator(func):
def wrapper(*args, **kwargs):
connector.tackleFlag.set()
res = func(*args, **kwargs)
connector.tackleFlag.clear()
return res
return wrapper
return decorator


def retry(count=5, retry_sep=0.5):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(count):
try:
# 低优先级请求未结束时, 避免server队列过长
# 若负载过高导致请求失败, 则在触发 retry 间隙为高优先级请求让行
while connector.slowlyFlag.is_set():
time.sleep(.2)

res = func(*args, **kwargs)
except:
time.sleep(retry_sep)
continue
else:
break
else:
# FIXME 任何异常都将以 timeout 抛出
connector.timeoutApi = func.__name__
raise Exception("Exceeded maximum retry attempts.")

return res
Expand All @@ -39,9 +71,12 @@ def __init__(self):
self.token = None
self.url = None

self.flag = threading.Event()
self.tackleFlag = threading.Event()
self.slowlyFlag = threading.Event()
self.manager = None

self.timeoutApi = None

def start(self, pid):
process = psutil.Process(pid)
cmdline = process.cmdline()
Expand Down Expand Up @@ -206,11 +241,9 @@ def getSummonerByPuuid(self, puuid):

return res

@retry()
@slowly()
@retry(10, 1)
def getSummonerGamesByPuuidSlowly(self, puuid, begIndex=0, endIndex=4):
while self.flag.is_set():
time.sleep(.2)

params = {"begIndex": begIndex, "endIndex": endIndex}
res = self.__get(
f"/lol-match-history/v1/products/lol/{puuid}/matches", params
Expand All @@ -221,9 +254,9 @@ def getSummonerGamesByPuuidSlowly(self, puuid, begIndex=0, endIndex=4):

return res["games"]

@tackle()
@retry()
def getSummonerGamesByPuuid(self, puuid, begIndex=0, endIndex=4):
self.flag.set()
params = {"begIndex": begIndex, "endIndex": endIndex}
res = self.__get(
f"/lol-match-history/v1/products/lol/{puuid}/matches", params
Expand All @@ -232,7 +265,6 @@ def getSummonerGamesByPuuid(self, puuid, begIndex=0, endIndex=4):
if "games" not in res:
raise SummonerGamesNotFound()

self.flag.clear()
return res["games"]

@retry()
Expand Down
Loading

0 comments on commit 4aa1e10

Please sign in to comment.