Skip to content
This repository has been archived by the owner on May 28, 2024. It is now read-only.

Commit

Permalink
version 6.1.0
Browse files Browse the repository at this point in the history
支持第三方登录
模版字段检查修复
  • Loading branch information
megachweng committed Sep 12, 2019
1 parent 677c152 commit 2d56310
Show file tree
Hide file tree
Showing 11 changed files with 212 additions and 116 deletions.
37 changes: 37 additions & 0 deletions addon/UIForm/loginDialog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'designer/loginDialog.ui'
#
# Created by: PyQt5 UI code generator 5.12.1
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_LoginDialog(object):
def setupUi(self, LoginDialog):
LoginDialog.setObjectName("LoginDialog")
LoginDialog.resize(505, 480)
self.gridLayout = QtWidgets.QGridLayout(LoginDialog)
self.gridLayout.setObjectName("gridLayout")
self.reloadBtn = QtWidgets.QPushButton(LoginDialog)
self.reloadBtn.setObjectName("reloadBtn")
self.gridLayout.addWidget(self.reloadBtn, 0, 1, 1, 1)
self.pageContainer = QtWidgets.QVBoxLayout()
self.pageContainer.setObjectName("pageContainer")
self.gridLayout.addLayout(self.pageContainer, 1, 0, 1, 2)
self.address = QtWidgets.QLineEdit(LoginDialog)
self.address.setClearButtonEnabled(True)
self.address.setObjectName("address")
self.gridLayout.addWidget(self.address, 0, 0, 1, 1)

self.retranslateUi(LoginDialog)
QtCore.QMetaObject.connectSlotsByName(LoginDialog)

def retranslateUi(self, LoginDialog):
_translate = QtCore.QCoreApplication.translate
LoginDialog.setWindowTitle(_translate("LoginDialog", "Login"))
self.reloadBtn.setText(_translate("LoginDialog", "reload"))


38 changes: 38 additions & 0 deletions addon/UIForm/loginDialog.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LoginDialog</class>
<widget class="QDialog" name="LoginDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>505</width>
<height>480</height>
</rect>
</property>
<property name="windowTitle">
<string>Login</string>
</property>
<layout class="QGridLayout" name="gridLayout" rowstretch="0,0">
<item row="0" column="1">
<widget class="QPushButton" name="reloadBtn">
<property name="text">
<string>reload</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<layout class="QVBoxLayout" name="pageContainer"/>
</item>
<item row="0" column="0">
<widget class="QLineEdit" name="address">
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
27 changes: 18 additions & 9 deletions addon/addonWindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@

from .queryApi import apis
from .UIForm import wordGroup, mainUI, icons_rc
from .workers import LoginWorker, VersionCheckWorker, RemoteWordFetchingWorker, QueryWorker, AudioDownloadWorker
from .workers import LoginStateCheckWorker, VersionCheckWorker, RemoteWordFetchingWorker, QueryWorker, AudioDownloadWorker
from .dictionary import dictionaries
from .logger import Handler
from .loginDialog import LoginDialog
from .misc import Mask
from .constants import BASIC_OPTION, EXTRA_OPTION, MODEL_NAME, RELEASE_URL

Expand Down Expand Up @@ -130,6 +131,10 @@ def setupGUIByConfig(self):
self.selectedGroups = config['selectedGroup']

def initCore(self):
self.usernameLineEdit.hide()
self.usernameLabel.hide()
self.passwordLabel.hide()
self.passwordLineEdit.hide()
self.dictionaryComboBox.addItems([d.name for d in dictionaries])
self.apiComboBox.addItems([d.name for d in apis])
self.deckComboBox.addItems(getDeckList())
Expand Down Expand Up @@ -198,8 +203,6 @@ def on_dictionaryComboBox_currentIndexChanged(self, index):
"""词典候选框改变事件"""
self.currentDictionaryLabel.setText(f'当前选择词典: {self.dictionaryComboBox.currentText()}')
config = mw.addonManager.getConfig(__name__)
self.usernameLineEdit.setText(config['credential'][index]['username'])
self.passwordLineEdit.setText(config['credential'][index]['password'])
self.cookieLineEdit.setText(config['credential'][index]['cookie'])

@pyqtSlot()
Expand All @@ -217,25 +220,33 @@ def on_pullRemoteWordsBtn_clicked(self):
self.selectedDict = dictionaries[currentConfig['selectedDict']]()

# 登陆线程
self.loginWorker = LoginWorker(self.selectedDict.login, str(currentConfig['username']), str(currentConfig['password']), json.loads(str(currentConfig['cookie']) or '{}'))
self.loginWorker = LoginStateCheckWorker(self.selectedDict.checkCookie, json.loads(self.cookieLineEdit.text() or '{}'))
self.loginWorker.moveToThread(self.workerThread)
self.loginWorker.logSuccess.connect(self.onLogSuccess)
self.loginWorker.start.connect(self.loginWorker.run)
self.loginWorker.logSuccess.connect(self.onLogSuccess)
self.loginWorker.logFailed.connect(self.onLoginFailed)
self.loginWorker.start.emit()

@pyqtSlot()
def onLoginFailed(self):
showCritical('登录失败!')
self.tabWidget.setCurrentIndex(1)
showCritical('第一次登录或cookie失效!请重新登录')
self.progressBar.setValue(0)
self.progressBar.setMaximum(1)
self.mainTab.setEnabled(True)
self.cookieLineEdit.clear()
self.loginDialog = LoginDialog(
loginUrl=self.selectedDict.loginUrl,
loginCheckCallbackFn=self.selectedDict.loginCheckCallbackFn,
parent=self
)
self.loginDialog.loginSucceed.connect(self.onLogSuccess)
self.loginDialog.show()

@pyqtSlot(str)
def onLogSuccess(self, cookie):
self.cookieLineEdit.setText(cookie)
self.getAndSaveCurrentConfig()
self.selectedDict.checkCookie(json.loads(cookie))
self.selectedDict.getGroups()

container = QDialog(self)
Expand Down Expand Up @@ -501,5 +512,3 @@ def on_syncBtn_clicked(self):

if not audiosDownloadTasks:
tooltip(f'添加{added}个笔记\n删除{deleted}个笔记')


2 changes: 1 addition & 1 deletion addon/constants.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION = 'v6.0.2'
VERSION = 'v6.1.0'
RELEASE_URL = 'https://github.com/megachweng/Dict2Anki'
VERSION_CHECK_API = 'https://api.github.com/repos/megachweng/Dict2Anki/releases/latest'
MODEL_NAME = f'Dict2Anki-{VERSION}'
Expand Down
49 changes: 8 additions & 41 deletions addon/dictionary/eudict.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

class Eudict(AbstractDictionary):
name = '欧陆词典'
loginUrl = 'https://dict.eudic.net/account/login'
timeout = 10
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
Expand All @@ -23,22 +24,9 @@ class Eudict(AbstractDictionary):

def __init__(self):
self.groups = []
self.indexSoup = None

def login(self, username: str, password: str, cookie: dict = None) -> dict:
"""
登陆
:param username: 用户名
:param password: 密码
:param cookie: cookie
:return: 登陆成功的cookie
"""
self.session.cookies.clear()
if cookie and self._checkCookie(cookie):
return cookie
else:
return self._login(username, password)

def _checkCookie(self, cookie: dict) -> bool:
def checkCookie(self, cookie: dict) -> bool:
"""
cookie有效性检验
:param cookie:
Expand All @@ -54,32 +42,11 @@ def _checkCookie(self, cookie: dict) -> bool:
logger.info('Cookie失效')
return False

def _login(self, username: str, password: str) -> dict:
"""账号和密码登陆"""
data = {
"UserName": username,
"Password": password,
"returnUrl": "http://my.eudic.net/studylist",
"RememberMe": 'true'
}
try:
rsp = self.session.post(
url='https://dict.eudic.net/Account/Login?returnUrl=https://my.eudic.net/studylist',
timeout=self.timeout,
headers=self.headers,
data=data
)
cookie = requests.utils.dict_from_cookiejar(self.session.cookies)
if 'EudicWeb' in cookie.keys():
self.indexSoup = BeautifulSoup(rsp.text, features="html.parser")
logger.info(f'登陆成功')
return cookie
else:
logger.error(f'登陆失败')
return {}
except Exception as error:
logger.exception(f'网络异常:{error}')
return {}
@staticmethod
def loginCheckCallbackFn(cookie, content):
if 'EudicWeb' in cookie:
return True
return False

def getGroups(self) -> [(str, int)]:
"""
Expand Down
55 changes: 9 additions & 46 deletions addon/dictionary/youdao.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
from urllib3.util.retry import Retry
from requests.adapters import HTTPAdapter
from ..misc import AbstractDictionary

logger = logging.getLogger('dict2Anki.dictionary.youdao')


class Youdao(AbstractDictionary):
name = '有道词典'
loginUrl = 'http://account.youdao.com/login?service=dict&back_url=http://dict.youdao.com/wordbook/wordlist%3Fkeyfrom%3Dnull'
timeout = 10
headers = {
'Host': 'dict.youdao.com',
Expand All @@ -22,23 +24,10 @@ class Youdao(AbstractDictionary):
session.mount('https://', HTTPAdapter(max_retries=retries))

def __init__(self):
self.indexSoup = None
self.groups = []

def login(self, username: str, password: str, cookie: dict = None) -> dict:
"""
登陆
:param username: 用户名
:param password: 密码
:param cookie: cookie
:return: cookie dict
"""
self.session.cookies.clear()
if cookie and self._checkCookie(cookie):
return cookie
else:
return self._login(username, password)

def _checkCookie(self, cookie) -> bool:
def checkCookie(self, cookie: dict) -> bool:
"""
cookie有效性检验
:param cookie:
Expand All @@ -54,37 +43,11 @@ def _checkCookie(self, cookie) -> bool:
logger.info('Cookie失效')
return False

def _login(self, username: str, password: str) -> dict:
"""账号和密码登陆"""
data = (('app', 'mobile'),
('product', 'DICT'),
('tp', 'urstoken'),
('cf', '7'),
('show', 'true'),
('format', 'json'),
('username', username),
('password', hashlib.md5(password.encode('utf-8')).hexdigest()),
('um', 'true'),)
try:
self.session.post(
url='https://dict.youdao.com/login/acc/login',
timeout=self.timeout,
headers=self.headers,
data=data
)
cookie = requests.utils.dict_from_cookiejar(self.session.cookies)
if username and username.lower() in cookie.get('DICT_SESS', ''):
# 登陆后获取单词本首页的soup对象
rsp = self.session.get('http://dict.youdao.com/wordbook/wordlist', timeout=self.timeout)
self.indexSoup = BeautifulSoup(rsp.text, features="html.parser")
logger.info('登陆成功')
return cookie
else:
logger.error('登陆失败')
return {}
except Exception as error:
logger.exception(f'网络异常:{error}')
return {}
@staticmethod
def loginCheckCallbackFn(cookie, content):
if 'DICT_SESS' in cookie:
return True
return False

def getGroups(self) -> [(str, int)]:
"""
Expand Down
2 changes: 1 addition & 1 deletion addon/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def __init__(self, parent):

formatter = Formatter('[%(asctime)s][%(levelname)8s] -- %(message)s - (%(name)s)', '%d/%m/%Y %H:%M:%S')
self.setFormatter(formatter)
self.setLevel(logging.INFO)
self.setLevel(logging.DEBUG)

def emit(self, record):
msg = self.format(record)
Expand Down
73 changes: 73 additions & 0 deletions addon/loginDialog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import json
import sys
import logging
from PyQt5.QtCore import QUrl, pyqtSignal
from .UIForm import loginDialog
from PyQt5.QtWidgets import QDialog
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEngineProfile

logger = logging.getLogger('dict2Anki')


class LoginDialog(QDialog, loginDialog.Ui_LoginDialog):
loginSucceed = pyqtSignal(str)

def __init__(self, loginUrl, loginCheckCallbackFn, parent=None):
super().__init__(parent)
self.url = QUrl(loginUrl)
self.loginCheckCallbackFn = loginCheckCallbackFn
self.setupUi(self)
self.page = LoginWebEngineView(self)
self.pageContainer.addWidget(self.page)
self.page.load(self.url)
self.makeConnection()

def makeConnection(self):
self.reloadBtn.clicked.connect(self._reload)
self.page.loadFinished.connect(self.checkLoginState)

def _reload(self):
logger.debug('Reload page')
self.page.cookieStore.deleteAllCookies()
self.page.load(QUrl(self.address.text()))

def checkLoginState(self):
def contentLoaded(content):
logger.debug(f'Cookie:{self.page.cookie}')
logger.debug(f'Content{content}')
if self.loginCheckCallbackFn(cookie=self.page.cookie, content=content):
logger.info(f'Login Success!')
self.onLoginSucceed()
logger.info(f'Login Fail!')

self.page.page().toHtml(contentLoaded)

def onLoginSucceed(self):
logger.info('Destruct login dialog')
self.close()
logger.debug('emit cookie')
self.loginSucceed.emit(json.dumps(self.page.cookie))


class LoginWebEngineView(QWebEngineView):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 绑定cookie被添加的信号槽
self.profile = QWebEngineProfile.defaultProfile()
self.profile.setHttpUserAgent(
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko)'
' Chrome/69.0.3497.100 Safari/537.36'
)
self.cookieStore = self.profile.cookieStore()
self.cookieStore.cookieAdded.connect(self.onCookieAdd)
self._cookies = {}
self.show()

def onCookieAdd(self, cookie):
name = cookie.name().data().decode('utf-8')
value = cookie.value().data().decode('utf-8')
self._cookies[name] = value

@property
def cookie(self) -> dict:
return self._cookies
Loading

0 comments on commit 2d56310

Please sign in to comment.