Merge pull request #1 from sth2018/master

更新
This commit is contained in:
WorkTimer 2019-02-27 16:10:48 +08:00 committed by GitHub
commit 4007dbbb28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 492 additions and 3378 deletions

View File

@ -1,4 +1,4 @@
#-*- coding:utf-8 -*-
# -*- coding:utf-8 -*-
#
# Copyright (C) 2018 sthoo <sth201807@gmail.com>
#
@ -19,6 +19,7 @@
import ssl
import sys
from anki.hooks import addHook
from anki.utils import isMac
@ -28,6 +29,7 @@ if isMac:
############## other config here ##################
shortcut = ('Ctrl+Alt' if isMac else 'Ctrl') + '+Q'
###################################################
@ -42,7 +44,6 @@ def start_here():
fastwq.browser_menu()
fastwq.context_menu()
fastwq.customize_addcards()
# if fastwq.config.auto_update:
# fastwq.check_updates(True)
addHook("profileLoaded", start_here)
addHook("profileLoaded", start_here)

View File

@ -1,4 +1,4 @@
#-*- coding:utf-8 -*-
# -*- coding:utf-8 -*-
#
# Copyright (C) 2018 sthoo <sth201807@gmail.com>
#
@ -18,24 +18,23 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from operator import itemgetter
from anki.hooks import addHook, remHook, wrap
from aqt import mw
from aqt.qt import *
from anki.hooks import addHook, wrap, remHook
from aqt.addcards import AddCards
from aqt.utils import showInfo, shortcut, downArrow
from .gui import show_options, show_about_dialog #, check_updates
from .query import query_from_browser, query_from_editor_fields
from .context import config, APP_ICON, Config
from aqt.qt import *
from aqt.utils import downArrow, shortcut, showInfo
from .context import APP_ICON, Config, config
from .gui import show_about_dialog, show_options # , check_updates
from .lang import _
from .query import query_from_browser, query_from_editor_fields
from .service import service_pool
from .utils import get_icon
__all__ = [
'browser_menu', 'customize_addcards',
'config_menu', 'context_menu'
] # 'check_updates',
'browser_menu', 'customize_addcards', 'config_menu', 'context_menu'
] # 'check_updates',
have_setup = False
my_shortcut = ''
@ -52,18 +51,23 @@ def set_options_def(mid, i):
data = dict()
data[mid] = conf
config.update(data)
# end set_options_def
def browser_menu():
"""
add add-on's menu to browser window
"""
def on_setup_menus(browser):
"""
on browser setupMenus was called
"""
# main menu
menu = browser.form.menubar.addMenu("FastWQ")
# menu gen
def init_fastwq_menu():
try:
@ -78,6 +82,7 @@ def browser_menu():
menu.addAction(action)
# Options
action = QAction(_('OPTIONS'), browser)
def _show_options():
model_id = -1
for note_id in browser.selectedNotes():
@ -85,26 +90,31 @@ def browser_menu():
model_id = note.model()['id']
break
show_options(browser, model_id)
action.triggered.connect(_show_options)
menu.addAction(action)
# Default configs
menu.addSeparator()
b = False
for m in sorted(browser.mw.col.models.all(), key=itemgetter("name")):
for m in sorted(
browser.mw.col.models.all(), key=itemgetter("name")):
conf = config.get_maps(m['id'])
conf = {'list': [conf], 'def': 0} if isinstance(conf, list) else conf
conf = {
'list': [conf],
'def': 0
} if isinstance(conf, list) else conf
maps_list = conf['list']
if len(maps_list) > 1:
submenu = menu.addMenu(m['name'])
for i, maps in enumerate(maps_list):
submenu.addAction(
_OK_ICON if i==conf['def'] else _NULL_ICON,
_('CONFIG_INDEX') % (i+1) if isinstance(maps, list) else maps['name'],
lambda mid=m['id'], i=i: set_options_def(mid, i)
)
_OK_ICON if i == conf['def'] else _NULL_ICON,
_('CONFIG_INDEX') % (i + 1) if isinstance(
maps, list) else maps['name'],
lambda mid=m['id'], i=i: set_options_def(mid, i))
b = True
if b:
if b:
menu.addSeparator()
# # check update
@ -120,6 +130,7 @@ def browser_menu():
# end init_fastwq_menu
init_fastwq_menu()
addHook('config.update', init_fastwq_menu)
addHook('browser.setupMenus', on_setup_menus)
@ -127,6 +138,7 @@ def customize_addcards():
"""
add button to addcards window
"""
def add_query_button(self):
'''
add a button in add card window
@ -136,44 +148,47 @@ def customize_addcards():
# button
fastwqBtn = QPushButton(_("QUERY") + u" " + downArrow())
fastwqBtn.setShortcut(QKeySequence(my_shortcut))
fastwqBtn.setToolTip(
_(u"Shortcut: %s") % shortcut(my_shortcut)
)
fastwqBtn.setToolTip(_(u"Shortcut: %s") % shortcut(my_shortcut))
bb.addButton(fastwqBtn, ar)
# signal
def onQuery(e):
if isinstance(e, QMouseEvent):
if e.buttons() & Qt.LeftButton:
menu = QMenu(self)
menu.addAction(_("ALL_FIELDS"), lambda: query_from_editor_fields(self.editor), QKeySequence(my_shortcut))
menu.addAction(
_("ALL_FIELDS"),
lambda: query_from_editor_fields(self.editor),
QKeySequence(my_shortcut))
# default options
mid = self.editor.note.model()['id']
conf = config.get_maps(mid)
conf = {'list': [conf], 'def': 0} if isinstance(conf, list) else conf
conf = {
'list': [conf],
'def': 0
} if isinstance(conf, list) else conf
maps_list = conf['list']
if len(maps_list) > 1:
menu.addSeparator()
for i, maps in enumerate(maps_list):
menu.addAction(
_OK_ICON if i==conf['def'] else _NULL_ICON,
_('CONFIG_INDEX') % (i+1) if isinstance(maps, list) else maps['name'],
lambda mid=mid, i=i: set_options_def(mid, i)
)
_OK_ICON if i == conf['def'] else _NULL_ICON,
_('CONFIG_INDEX') % (i + 1) if isinstance(
maps, list) else maps['name'],
lambda mid=mid, i=i: set_options_def(mid, i))
menu.addSeparator()
# end default options
menu.addAction(_("OPTIONS"), lambda: show_options(self, self.editor.note.model()['id']))
menu.exec_(fastwqBtn.mapToGlobal(QPoint(0, fastwqBtn.height())))
menu.exec_(
fastwqBtn.mapToGlobal(QPoint(0, fastwqBtn.height())))
else:
query_from_editor_fields(self.editor)
fastwqBtn.mousePressEvent = onQuery
fastwqBtn.clicked.connect(onQuery)
AddCards.setupButtons = wrap(
AddCards.setupButtons,
add_query_button,
"after"
)
AddCards.setupButtons = wrap(AddCards.setupButtons, add_query_button,
"after")
def config_menu():
@ -187,6 +202,7 @@ def config_menu():
def context_menu():
'''mouse right click menu'''
def on_setup_menus(web_view, menu):
"""
add context menu to webview
@ -217,32 +233,30 @@ def context_menu():
name = s.title + ' :-> ' + s.fields[dict_fld_ord]
if name not in names:
names.append(name)
curr_flds.append({
'name': name,
'def': i
})
curr_flds.append({'name': name, 'def': i})
service_pool.put(s)
submenu = menu.addMenu(_('QUERY'))
submenu.addAction(_('ALL_FIELDS'), lambda: query_from_editor_fields(web_view.editor), QKeySequence(my_shortcut))
submenu.addAction(
_('ALL_FIELDS'), lambda: query_from_editor_fields(web_view.editor),
QKeySequence(my_shortcut))
if len(curr_flds) > 0:
# quer hook method
def query_from_editor_hook(i):
conf = config.get_maps(current_model_id)
maps_old_def = 0 if isinstance(conf, list) else conf.get('def', 0)
maps_old_def = 0 if isinstance(conf, list) else conf.get(
'def', 0)
set_options_def(current_model_id, i)
query_from_editor_fields(
web_view.editor,
fields=[web_view.editor.currentField]
)
web_view.editor, fields=[web_view.editor.currentField])
set_options_def(current_model_id, maps_old_def)
# sub menu
#flds_menu = submenu.addMenu(_('CURRENT_FIELDS'))
# flds_menu = submenu.addMenu(_('CURRENT_FIELDS'))
submenu.addSeparator()
for c in curr_flds:
submenu.addAction(c['name'],
lambda i=c['def']: query_from_editor_hook(i)
)
submenu.addAction(
c['name'], lambda i=c['def']: query_from_editor_hook(i))
submenu.addSeparator()
submenu.addAction(_("OPTIONS"), lambda: show_options(web_view, web_view.editor.note.model()['id']))

View File

@ -1,4 +1,4 @@
#-*- coding:utf-8 -*-
# -*- coding:utf-8 -*-
#
# Copyright (C) 2018 sthoo <sth201807@gmail.com>
#
@ -17,13 +17,12 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .lang import _
__all__ = ['VERSION', 'Endpoint', 'Template']
VERSION = 'v1.3.5'
VERSION = 'v2.0.0b'
class Endpoint:
repository = u'https://github.com/sth2018/FastWordQuery'
@ -36,10 +35,13 @@ class Endpoint:
class Template:
tmpl_about = u'''<b>{t0}</b><br/>{version}<br/><b>{t1}</b><br/>
<a href="{url}">{url}</a><br/><b>{t2}</b><br/>
<a href="{feedback0}">{feedback0}</a><br/>
<a href="mailto:{feedback1}">{feedback1}</a>'''.format(
t0=_('VERSION'), version=VERSION,
t1=_('REPOSITORY'), url=Endpoint.repository,
t2=_('FEEDBACK'), feedback0=Endpoint.feedback_issue, feedback1=Endpoint.feedback_mail)
miss_css = u'MDX dictonary <b>{dict}</b> misses css file <b>{css}</b>. <br/>Please choose the file.'
<a href="{url}">{url}</a><br/><b>{t2}</b><br/>
<a href="{feedback0}">{feedback0}</a><br/>
<a href="mailto:{feedback1}">{feedback1}</a>'''.format(
t0=_('VERSION'),
version=VERSION,
t1=_('REPOSITORY'),
url=Endpoint.repository,
t2=_('FEEDBACK'),
feedback0=Endpoint.feedback_issue,
feedback1=Endpoint.feedback_mail)

View File

@ -1,4 +1,4 @@
#-*- coding:utf-8 -*-
# -*- coding:utf-8 -*-
#
# Copyright (C) 2018 sthoo <sth201807@gmail.com>
#
@ -19,25 +19,24 @@
import json
import os
from aqt import mw
from anki.hooks import runHook
from aqt import mw
from .constants import VERSION
from .utils import get_icon
__all__ = ['APP_ICON', 'config']
APP_ICON = get_icon('wqicon.png') #Addon Icon
APP_ICON = get_icon('wqicon.png') # Addon Icon
class Config(object):
"""
Addon Config
"""
_CONFIG_FILENAME = 'fastwqcfg.json' #Config File Path
_CONFIG_FILENAME = 'fastwqcfg.json' # Config File Path
def __init__(self, window):
self.path = u'_' + self._CONFIG_FILENAME
@ -55,10 +54,12 @@ class Config(object):
Update && Save
"""
data['version'] = VERSION
data['%s_last' % self.pmname] = data.get('last_model', self.last_model_id)
data['%s_last' % self.pmname] = data.get('last_model',
self.last_model_id)
self.data.update(data)
with open(self.path, 'w', encoding='utf-8') as f:
json.dump(self.data, f, indent=4, sort_keys=True, ensure_ascii=False)
json.dump(
self.data, f, indent=4, sort_keys=True, ensure_ascii=False)
f.close()
runHook('config.update')
@ -69,13 +70,15 @@ class Config(object):
if self.data:
return self.data
try:
path = self.path if os.path.exists(self.path) else u'.' + self._CONFIG_FILENAME
path = self.path if os.path.exists(
self.path) else u'.' + self._CONFIG_FILENAME
with open(path, 'r', encoding="utf-8") as f:
self.data = json.load(f)
f.close()
if not os.path.exists(self.path):
self.update(self.data)
except:
except Exception as e:
print('can not find config file', e)
self.data = dict()
def get_maps(self, model_id):
@ -107,7 +110,7 @@ class Config(object):
@property
def force_update(self):
return self.data.get('force_update', False)
@property
def ignore_mdx_wordcase(self):
return self.data.get('ignore_mdx_wordcase', False)
@ -122,7 +125,7 @@ class Config(object):
@property
def last_folder(self):
"""
last file dialog open path
last file dialog open path
"""
return self.data.get('last_folder', '')
@ -131,15 +134,13 @@ class Config(object):
'''ignore accents of field in querying'''
return self.data.get('ignore_accents', False)
@property
def auto_update(self):
'''auto check new version'''
return self.data.get('auto_update', True)
@property
def cloze_str(self):
'''cloze formater string'''
return self.data.get('cloze_str', '{{c1::%s}}')
tmpstr = self.data.get('cloze_str', '{{c1::%s}}')
if len(tmpstr.split('%s')) != 2:
tmpstr = '{{c1::%s}}'
return tmpstr
config = Config(mw)

View File

@ -1,4 +1,4 @@
#-*- coding:utf-8 -*-
# -*- coding:utf-8 -*-
from .common import *
from .progress import *

View File

@ -1,4 +1,4 @@
#-*- coding:utf-8 -*-
# -*- coding:utf-8 -*-
#
# Copyright (C) 2018 sthoo <sth201807@gmail.com>
#
@ -18,10 +18,11 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
from anki.utils import isMac
from aqt.qt import *
from ..context import APP_ICON
from ..context import APP_ICON
__all__ = ['Dialog', 'WIDGET_SIZE']
@ -37,20 +38,15 @@ class Dialog(QDialog):
return value of the _ui() method, and sets a default title.
'''
self._title = title
self._title = title if "FastWQ" in title else "FastWQ - " + title
self._parent = parent
super(Dialog, self).__init__(parent)
self.setModal(True)
self.setWindowFlags(
self.windowFlags() &
~Qt.WindowContextHelpButtonHint
)
self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
self.setWindowIcon(APP_ICON)
self.setWindowTitle(
title if "FastWQ" in title
else "FastWQ - " + title
)
self.setWindowTitle(self._title)
# 2 & 3 & mac compatible
if isMac and sys.hexversion >= 0x03000000:
QApplication.setStyle('Fusion')

View File

@ -1,4 +1,4 @@
#-*- coding:utf-8 -*-
# -*- coding:utf-8 -*-
#
# Copyright (C) 2018 sthoo <sth201807@gmail.com>
#
@ -18,38 +18,22 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import types
from aqt import mw
from aqt.qt import *
from aqt.utils import showInfo
from .options import OptionsDialog
from .foldermanager import FoldersManageDialog
from .dictmanager import DictManageDialog
from ..libs import ankihub
from ..constants import Template
from ..context import config
from ..lang import _
from ..constants import Endpoint, Template
from ..service import service_manager, service_pool
from .dictmanager import DictManageDialog
from .foldermanager import FoldersManageDialog
from .options import OptionsDialog
__all__ = ['show_options', 'show_fm_dialog', 'show_about_dialog']
__all__ = ['show_options', 'show_fm_dialog', 'show_about_dialog'] #'check_updates',
# def check_updates(background=False, parent=None):
# '''check add-on last version'''
# try:
# parent = mw if parent is None else parent
# state = ankihub.update([Endpoint.check_version], Endpoint.version, background, parent)
# if not background:
# if state == 0:
# showInfo(_('LATEST_VERSION'))
# elif state == -1:
# showInfo(_('CHECK_FAILURE'))
# except:
# if not background:
# showInfo(_('CHECK_FAILURE'))
def show_fm_dialog(browser = None):
def show_fm_dialog(browser=None):
'''open dictionary folder manager window'''
parent = mw if browser is None else browser
fm_dialog = FoldersManageDialog(parent, u'Dictionary Folder Manager')
@ -64,7 +48,7 @@ def show_fm_dialog(browser = None):
show_options(browser)
def show_dm_dialog(browser = None):
def show_dm_dialog(browser=None):
parent = mw if browser is None else browser
dm_dialog = DictManageDialog(parent, u'Dictionary Manager')
dm_dialog.activateWindow()
@ -78,7 +62,7 @@ def show_dm_dialog(browser = None):
show_options(browser)
def show_options(browser = None, model_id = -1, callback = None, *args, **kwargs):
def show_options(browser=None, model_id=-1, callback=None, *args, **kwargs):
'''open options window'''
parent = mw if browser is None else browser
config.read()

View File

@ -1,4 +1,4 @@
#-*- coding:utf-8 -*-
# -*- coding:utf-8 -*-
#
# Copyright (C) 2018 sthoo <sth201807@gmail.com>
#
@ -19,19 +19,20 @@
import os
import sys
from aqt.qt import *
from aqt.forms.editaddon import Ui_Dialog
from .base import Dialog, WIDGET_SIZE
from ..service import service_manager, service_pool
from aqt.qt import *
from ..context import config
from ..lang import _, _sl
from ..service import service_manager, service_pool
from ..utils import get_icon
from .base import WIDGET_SIZE, Dialog
# 2x3 compatible
if sys.hexversion >= 0x03000000:
unicode = str
__all__ = ['DictManageDialog']
@ -45,14 +46,14 @@ class DictManageDialog(Dialog):
self.main_layout = QVBoxLayout()
self.setLayout(self.main_layout)
self._options = list()
btnbox = QDialogButtonBox(QDialogButtonBox.Ok, Qt.Horizontal , self)
btnbox = QDialogButtonBox(QDialogButtonBox.Ok, Qt.Horizontal, self)
btnbox.accepted.connect(self.accept)
# add dicts mapping
self.dicts_layout = QGridLayout()
self.main_layout.addLayout(self.dicts_layout)
self.main_layout.addWidget(btnbox)
self.build()
def build(self):
''' '''
# labels
@ -80,10 +81,14 @@ class DictManageDialog(Dialog):
services = service_manager.local_custom_services + service_manager.web_services
for clazz in services:
dicts.append({
'title': clazz.__title__,
'unique': clazz.__unique__,
'path': clazz.__path__,
'enabled': confs.get(clazz.__unique__, dict()).get('enabled', True)
'title':
clazz.__title__,
'unique':
clazz.__unique__,
'path':
clazz.__path__,
'enabled':
confs.get(clazz.__unique__, dict()).get('enabled', True)
})
# add dict
for i, d in enumerate(dicts):
@ -102,7 +107,7 @@ class DictManageDialog(Dialog):
)
# button
check_btn = QCheckBox(title)
check_btn.setMinimumSize(WIDGET_SIZE.map_dict_width*1.5, 0)
check_btn.setMinimumSize(WIDGET_SIZE.map_dict_width * 1.5, 0)
check_btn.setEnabled(True)
check_btn.setChecked(enabled)
edit_btn = QToolButton(self)
@ -114,9 +119,9 @@ class DictManageDialog(Dialog):
self.dicts_layout.addWidget(check_btn, i + 1, 0)
self.dicts_layout.addWidget(edit_btn, i + 1, 1)
self._options.append({
'unique': unique,
'check_btn': check_btn,
'edit_btn': edit_btn,
'unique': unique,
'check_btn': check_btn,
'edit_btn': edit_btn,
})
def enabled_all_update(self):
@ -126,7 +131,7 @@ class DictManageDialog(Dialog):
b = False
break
self.enabled_all_check_btn.setChecked(b)
def enabled_all_changed(self):
b = self.enabled_all_check_btn.isChecked()
for row in self._options:

View File

@ -1,4 +1,4 @@
#-*- coding:utf-8 -*-
# -*- coding:utf-8 -*-
#
# Copyright (C) 2018 sthoo <sth201807@gmail.com>
#
@ -18,10 +18,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from aqt.qt import *
from .base import Dialog, WIDGET_SIZE
from ..context import config
from ..lang import _, _sl
from .base import WIDGET_SIZE, Dialog
__all__ = ['FoldersManageDialog']
@ -33,7 +33,7 @@ class FoldersManageDialog(Dialog):
def __init__(self, parent, title=u'Dictionary Folder Manager'):
super(FoldersManageDialog, self).__init__(parent, title)
#self._dict_paths = []
# self._dict_paths = []
self.build()
def build(self):
@ -65,10 +65,9 @@ class FoldersManageDialog(Dialog):
def add_folder(self):
dir_ = QFileDialog.getExistingDirectory(
self,
caption=u"Select Folder",
directory=config.last_folder,
options=QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks
)
caption=u"Select Folder",
directory=config.last_folder,
options=QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks)
if dir_:
self.folders_lst.addItem(dir_)
config.update({'last_folder': dir_})
@ -80,8 +79,10 @@ class FoldersManageDialog(Dialog):
@property
def dirs(self):
'''dictionary folders list'''
return [self.folders_lst.item(i).text()
for i in range(self.folders_lst.count())]
return [
self.folders_lst.item(i).text()
for i in range(self.folders_lst.count())
]
def accept(self):
'''ok button clicked'''

View File

@ -1,4 +1,4 @@
#-*- coding:utf-8 -*-
# -*- coding:utf-8 -*-
#
# Copyright (C) 2018 sthoo <sth201807@gmail.com>
#
@ -18,22 +18,23 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import anki
import aqt
import aqt.models
import sip
from anki.utils import isMac
from aqt import mw
from aqt.qt import *
from aqt.studydeck import StudyDeck
from anki.utils import isMac
from .base import Dialog, WIDGET_SIZE
from .setting import SettingDialog
from ..constants import Endpoint
from ..context import config
from ..lang import _, _sl
from ..service import service_manager, service_pool
from ..utils import get_model_byId, get_icon
from ..constants import Endpoint
from ..utils import get_icon, get_model_byId
from .base import WIDGET_SIZE, Dialog
from .setting import SettingDialog
__all__ = ['OptionsDialog']
@ -44,16 +45,13 @@ class OptionsDialog(Dialog):
setting query dictionary and fileds
'''
__slot__ = [
'begore_build',
'after_build'
]
__slot__ = ['begore_build', 'after_build']
_signal = pyqtSignal(str)
_NULL_ICON = get_icon('null.png')
_OK_ICON = get_icon('ok.png')
def __init__(self, parent, title=u'Options', model_id = -1):
def __init__(self, parent, title=u'Options', model_id=-1):
super(OptionsDialog, self).__init__(parent, title)
self._signal.connect(self._before_build)
self._signal.connect(self._after_build)
@ -61,32 +59,34 @@ class OptionsDialog(Dialog):
self.main_layout = QVBoxLayout()
self.loading_label = QLabel(_('INITLIZING_DICT'))
self.main_layout.addWidget(self.loading_label, 0, Qt.AlignCenter)
#self.loading_layout.addLayout(models_layout)
# self.loading_layout.addLayout(models_layout)
self.setLayout(self.main_layout)
#initlize properties
# initlize properties
self.model_id = model_id if model_id != -1 else config.last_model_id
self.current_model = None
self.tabs = []
self.dict_services = None
# size and signal
self.resize(WIDGET_SIZE.dialog_width, 4 * WIDGET_SIZE.map_max_height + WIDGET_SIZE.dialog_height_margin)
self.resize(
WIDGET_SIZE.dialog_width,
4 * WIDGET_SIZE.map_max_height + WIDGET_SIZE.dialog_height_margin)
self._signal.emit('before_build')
def _before_build(self, s):
if s != 'before_build':
return
# dict service list
dicts = config.dicts
self.dict_services = {
'local': [], #本地词典
'web': [] #网络词典
'local': [], # 本地词典
'web': [] # 网络词典
}
for clazz in service_manager.local_services:
if dicts.get(clazz.__unique__, dict()).get('enabled', True):
service = service_pool.get(clazz.__unique__)
if service and service.support:
self.dict_services['local'].append({
'title': service.title,
'title': service.title,
'unique': service.unique
})
service_pool.put(service)
@ -95,7 +95,7 @@ class OptionsDialog(Dialog):
service = service_pool.get(clazz.__unique__)
if service and service.support:
self.dict_services['web'].append({
'title': service.title,
'title': service.title,
'unique': service.unique
})
service_pool.put(service)
@ -121,13 +121,11 @@ class OptionsDialog(Dialog):
# tabs
self.tab_widget = QTabWidget()
self.tab_widget.setTabBar(CTabBar())
self.tab_widget.setStyleSheet(
"""
self.tab_widget.setStyleSheet("""
QTabWidget::pane { /* The tab widget frame */
border: 1px solid #c3c3c3;
}
"""
)
""")
tab_corner = QWidget()
tab_corner_layout = QHBoxLayout()
tab_corner_layout.setSpacing(1)
@ -160,8 +158,7 @@ class OptionsDialog(Dialog):
# chk_update_btn = QPushButton(_('UPDATE'))
# chk_update_btn.clicked.connect(self.check_updates)
home_label = QLabel(
'<a href="{url}">User Guide</a>'.format(url=Endpoint.user_guide)
)
'<a href="{url}">User Guide</a>'.format(url=Endpoint.user_guide))
home_label.setOpenExternalLinks(True)
# buttons
btnbox = QDialogButtonBox(QDialogButtonBox.Ok, Qt.Horizontal, self)
@ -171,7 +168,7 @@ class OptionsDialog(Dialog):
bottom_layout.addWidget(about_btn)
bottom_layout.addWidget(home_label)
bottom_layout.addWidget(btnbox)
#self.setLayout(self.main_layout)
# self.setLayout(self.main_layout)
self.main_layout.addLayout(bottom_layout)
# init from saved data
self.current_model = None
@ -179,7 +176,8 @@ class OptionsDialog(Dialog):
self.current_model = get_model_byId(mw.col.models, self.model_id)
if self.current_model:
self.models_button.setText(
u'%s [%s]' % (_('CHOOSE_NOTE_TYPES'), self.current_model['name']))
u'%s [%s]' % (_('CHOOSE_NOTE_TYPES'),
self.current_model['name']))
# build fields -- dicts layout
self.build_tabs_layout()
@ -198,7 +196,7 @@ class OptionsDialog(Dialog):
'''open folder manager dialog'''
self.accept()
self.setResult(1001)
def show_dm_dialog(self):
'''open dictionary manager dialog'''
self.accept()
@ -225,13 +223,18 @@ class OptionsDialog(Dialog):
'''
build dictionaryfields etc
'''
try: self.tab_widget.currentChanged.disconnect()
except Exception: pass
try:
self.tab_widget.currentChanged.disconnect()
except Exception:
pass
while len(self.tabs) > 0:
self.removeTab(0, True)
# tabs
conf = config.get_maps(self.current_model['id'])
maps_list = {'list': [conf], 'def': 0} if isinstance(conf, list) else conf
maps_list = {
'list': [conf],
'def': 0
} if isinstance(conf, list) else conf
for maps in maps_list['list']:
self.addTab(maps, False)
self.tab_widget.currentChanged.connect(self.changedTab)
@ -240,28 +243,21 @@ class OptionsDialog(Dialog):
self.tab_widget.setCurrentIndex(maps_list['def'])
# size
self.resize(
WIDGET_SIZE.dialog_width,
min(max(3, len(self.current_model['flds'])+1), 14) * WIDGET_SIZE.map_max_height + WIDGET_SIZE.dialog_height_margin
)
WIDGET_SIZE.dialog_width,
min(max(3,
len(self.current_model['flds']) + 1), 14) *
WIDGET_SIZE.map_max_height + WIDGET_SIZE.dialog_height_margin)
self.save()
def addTab(self, maps=None, forcus=True):
i = len(self.tabs)
if isinstance(maps, list):
maps = {
'fields': maps,
'name': _('CONFIG_INDEX') % (i+1)
}
tab = TabContent(
self.current_model,
maps['fields'] if maps else None,
self.dict_services
)
maps = {'fields': maps, 'name': _('CONFIG_INDEX') % (i + 1)}
tab = TabContent(self.current_model, maps['fields'] if maps else None,
self.dict_services)
self.tabs.append(tab)
self.tab_widget.addTab(
tab,
maps['name'] if maps else _('CONFIG_INDEX') % (i+1)
)
tab, maps['name'] if maps else _('CONFIG_INDEX') % (i + 1))
if forcus:
self.tab_widget.setCurrentIndex(i)
@ -273,7 +269,7 @@ class OptionsDialog(Dialog):
del self.tabs[i]
self.tab_widget.removeTab(i)
tab.destroy()
#for k in range(0, len(self.tabs)):
# for k in range(0, len(self.tabs)):
# self.tab_widget.setTabText(k, _('CONFIG_INDEX') % (k+1))
def changedTab(self, i):
@ -289,12 +285,18 @@ class OptionsDialog(Dialog):
'''
show choose note type window
'''
edit = QPushButton(anki.lang._("Manage"),
clicked=lambda: aqt.models.Models(mw, self))
ret = StudyDeck(mw, names=lambda: sorted(mw.col.models.allNames()),
accept=anki.lang._("Choose"), title=anki.lang._("Choose Note Type"),
help="_notes", parent=self, buttons=[edit],
cancel=True, geomKey="selectModel")
edit = QPushButton(
anki.lang._("Manage"), clicked=lambda: aqt.models.Models(mw, self))
ret = StudyDeck(
mw,
names=lambda: sorted(mw.col.models.allNames()),
accept=anki.lang._("Choose"),
title=anki.lang._("Choose Note Type"),
help="_notes",
parent=self,
buttons=[edit],
cancel=True,
geomKey="selectModel")
if ret.name:
model = mw.col.models.byName(ret.name)
self.models_button.setText(
@ -306,18 +308,17 @@ class OptionsDialog(Dialog):
if not self.current_model:
return
data = dict()
maps_list = {
'list': [],
'def': self.tab_widget.currentIndex()
}
maps_list = {'list': [], 'def': self.tab_widget.currentIndex()}
for i, tab in enumerate(self.tabs):
maps_list['list'].append({
'fields': tab.data,
'name': self.tab_widget.tabBar().tabText(i)
'fields':
tab.data,
'name':
self.tab_widget.tabBar().tabText(i)
})
current_model_id = str(self.current_model['id'])
data[current_model_id] = maps_list
data['last_model'] = self.current_model['id']
data['last_model'] = self.current_model['id']
config.update(data)
@ -339,7 +340,7 @@ class TabContent(QScrollArea):
self.setWidgetResizable(True)
self.setWidget(dicts)
self.dicts_layout = dicts.layout()
#self.dicts_layout.setSizeConstraint(QLayout.SetFixedSize)
# self.dicts_layout.setSizeConstraint(QLayout.SetFixedSize)
def build_layout(self):
'''
@ -352,7 +353,7 @@ class TabContent(QScrollArea):
self._last_checkeds = None
self._was_built = True
model = self._model
model = self._model
maps = self._conf
# labels
@ -372,7 +373,8 @@ class TabContent(QScrollArea):
self.ignore_all_check_btn.setEnabled(True)
self.ignore_all_check_btn.setChecked(True)
self.dicts_layout.addWidget(self.ignore_all_check_btn, 0, 1)
self.ignore_all_check_btn.clicked.connect(self.ignore_all_check_changed)
self.ignore_all_check_btn.clicked.connect(
self.ignore_all_check_changed)
# Skip valued all
self.skip_all_check_btn = QCheckBox(_('SELECT_ALL'))
@ -381,7 +383,7 @@ class TabContent(QScrollArea):
self.skip_all_check_btn.setChecked(True)
self.dicts_layout.addWidget(self.skip_all_check_btn, 0, 4)
self.skip_all_check_btn.clicked.connect(self.skip_all_check_changed)
# dict & fields
self.radio_group = QButtonGroup()
for i, fld in enumerate(model['flds']):
@ -389,16 +391,19 @@ class TabContent(QScrollArea):
name = fld['name']
if maps:
for j, each in enumerate(maps):
if each.get('fld_ord', -1) == ord or each.get('fld_name', '') == name:
if each.get('fld_ord', -1) == ord or each.get(
'fld_name', '') == name:
each['fld_name'] = name
each['fld_ord'] = ord
self.add_dict_layout(j, **each)
break
else:
self.add_dict_layout(i, fld_name=name, fld_ord=ord, word_checked=i==0)
self.add_dict_layout(
i, fld_name=name, fld_ord=ord, word_checked=i == 0)
else:
self.add_dict_layout(i, fld_name=name, fld_ord=ord, word_checked=i==0)
self.add_dict_layout(
i, fld_name=name, fld_ord=ord, word_checked=i == 0)
# update
self.ignore_all_update()
self.skip_all_update()
@ -410,21 +415,21 @@ class TabContent(QScrollArea):
word_checked = kwargs.get('word_checked', False)
fld_name, fld_ord = (
kwargs.get('fld_name', ''), #笔记类型的字段名
kwargs.get('fld_ord', ''), #笔记类型的字段编号
kwargs.get('fld_name', ''), # 笔记类型的字段名
kwargs.get('fld_ord', ''), # 笔记类型的字段编号
)
dict_name, dict_unique, dict_fld_name, dict_fld_ord = (
kwargs.get('dict_name', ''), #字典名
kwargs.get('dict_unique', ''), #字典ID
kwargs.get('dict_fld_name', ''), #对应字典的字段名
kwargs.get('dcit_fld_ord', 0) #对应字典的字段编号
kwargs.get('dict_name', ''), # 字典名
kwargs.get('dict_unique', ''), # 字典ID
kwargs.get('dict_fld_name', ''), # 对应字典的字段名
kwargs.get('dcit_fld_ord', 0) # 对应字典的字段编号
)
ignore, skip, cloze = (
kwargs.get('ignore', True), #忽略标志
kwargs.get('skip_valued', True), #略过有值项标志
kwargs.get('cloze_word', False), #单词填空
kwargs.get('ignore', True), # 忽略标志
kwargs.get('skip_valued', True), # 略过有值项标志
kwargs.get('cloze_word', False), # 单词填空
)
# check
@ -436,26 +441,23 @@ class TabContent(QScrollArea):
# dict combox
dict_combo = QComboBox()
dict_combo.setMinimumSize(WIDGET_SIZE.map_dict_width, 0)
dict_combo.setMaximumSize(
WIDGET_SIZE.map_dict_width,
WIDGET_SIZE.map_max_height
)
dict_combo.setFocusPolicy(
Qt.TabFocus | Qt.ClickFocus | Qt.StrongFocus | Qt.WheelFocus
)
ignore = not self.fill_dict_combo_options(dict_combo, dict_unique, self._services) or ignore
dict_combo.setMaximumSize(WIDGET_SIZE.map_dict_width,
WIDGET_SIZE.map_max_height)
dict_combo.setFocusPolicy(Qt.TabFocus | Qt.ClickFocus | Qt.StrongFocus
| Qt.WheelFocus)
ignore = not self.fill_dict_combo_options(dict_combo, dict_unique,
self._services) or ignore
dict_unique = dict_combo.itemData(dict_combo.currentIndex())
dict_combo.setEnabled(not word_checked and not ignore)
# field combox
field_combo = QComboBox()
field_combo.setMinimumSize(WIDGET_SIZE.map_field_width, 0)
field_combo.setMaximumSize(
WIDGET_SIZE.map_field_width,
WIDGET_SIZE.map_max_height
)
field_combo.setMaximumSize(WIDGET_SIZE.map_field_width,
WIDGET_SIZE.map_max_height)
field_combo.setEnabled(not word_checked and not ignore)
self.fill_field_combo_options(field_combo, dict_name, dict_unique, dict_fld_name, dict_fld_ord)
self.fill_field_combo_options(field_combo, dict_name, dict_unique,
dict_fld_name, dict_fld_ord)
# ignore
ignore_check_btn = QCheckBox(_("NOT_DICT_FIELD"))
ignore_check_btn.setEnabled(not word_checked)
@ -489,13 +491,14 @@ class TabContent(QScrollArea):
cloze_check_btn.setEnabled(not word_checked and not ignore)
if word_checked:
self._last_checkeds = [
ignore_check_btn, dict_combo,
field_combo, skip_check_btn
ignore_check_btn, dict_combo, field_combo, skip_check_btn
]
word_check_btn.clicked.connect(radio_btn_checked)
if word_checked:
if word_checked:
self._last_checkeds = None
radio_btn_checked()
# ignor
def ignore_check_changed():
word_checked = word_check_btn.isChecked()
@ -504,35 +507,38 @@ class TabContent(QScrollArea):
field_combo.setEnabled(not word_checked and not ignore)
skip_check_btn.setEnabled(not word_checked and not ignore)
cloze_check_btn.setEnabled(not word_checked and not ignore)
ignore_check_btn.stateChanged.connect(ignore_check_changed)
ignore_check_btn.clicked.connect(self.ignore_all_update)
# skip
skip_check_btn.clicked.connect(self.skip_all_update)
# dict
def dict_combo_changed(index):
'''dict combo box index changed'''
self.fill_field_combo_options(
field_combo,
dict_combo.currentText(),
dict_combo.itemData(index),
field_combo.currentText(),
field_combo.itemData(field_combo.currentIndex())
)
field_combo, dict_combo.currentText(),
dict_combo.itemData(index), field_combo.currentText(),
field_combo.itemData(field_combo.currentIndex()))
dict_combo.currentIndexChanged.connect(dict_combo_changed)
self.dicts_layout.addWidget(word_check_btn, i + 1, 0)
self.dicts_layout.addWidget(ignore_check_btn, i + 1, 1)
self.dicts_layout.addWidget(dict_combo, i + 1, 2)
self.dicts_layout.addWidget(field_combo, i + 1, 3)
self.dicts_layout.addWidget(skip_check_btn, i + 1, 4)
self.dicts_layout.addWidget(cloze_check_btn, i + 1, 5)
self._options.append({
'model': {'fld_name': fld_name, 'fld_ord': fld_ord},
'word_check_btn': word_check_btn,
'dict_combo': dict_combo,
'field_combo': field_combo,
'ignore_check_btn': ignore_check_btn,
'model': {
'fld_name': fld_name,
'fld_ord': fld_ord
},
'word_check_btn': word_check_btn,
'dict_combo': dict_combo,
'field_combo': field_combo,
'ignore_check_btn': ignore_check_btn,
'skip_check_btn': skip_check_btn,
'cloze_check_btn': cloze_check_btn
})
@ -548,7 +554,7 @@ class TabContent(QScrollArea):
# hr
if len(services['local']) > 0:
dict_combo.insertSeparator(dict_combo.count())
# web dict service
for service in services['web']:
dict_combo.addItem(service['title'], userData=service['unique'])
@ -561,15 +567,18 @@ class TabContent(QScrollArea):
dict_combo.setCurrentIndex(i)
return True
return False
return set_dict_combo_index()
def fill_field_combo_options(self, field_combo, dict_combo_text, dict_combo_itemdata, dict_fld_name, dict_fld_ord):
def fill_field_combo_options(self, field_combo, dict_combo_text,
dict_combo_itemdata, dict_fld_name,
dict_fld_ord):
'''setup field combobox'''
field_combo.clear()
field_combo.setEditable(False)
#if dict_combo_text in _sl('NOT_DICT_FIELD'):
# if dict_combo_text in _sl('NOT_DICT_FIELD'):
# field_combo.setEnabled(False)
#el
# el
if dict_combo_text in _sl('MDX_SERVER'):
text = dict_fld_name if dict_fld_name else 'http://'
field_combo.setEditable(True)
@ -594,16 +603,26 @@ class TabContent(QScrollArea):
maps = []
for row in self._options:
maps.append({
'fld_name': row['model']['fld_name'],
'fld_ord': row['model']['fld_ord'],
'word_checked': row['word_check_btn'].isChecked(),
'dict_name': row['dict_combo'].currentText().strip(),
'dict_unique': row['dict_combo'].itemData(row['dict_combo'].currentIndex()),
'dict_fld_name': row['field_combo'].currentText().strip(),
'dict_fld_ord': row['field_combo'].itemData(row['field_combo'].currentIndex()),
'ignore': row['ignore_check_btn'].isChecked(),
'skip_valued': row['skip_check_btn'].isChecked(),
'cloze_word': row['cloze_check_btn'].isChecked()
'fld_name':
row['model']['fld_name'],
'fld_ord':
row['model']['fld_ord'],
'word_checked':
row['word_check_btn'].isChecked(),
'dict_name':
row['dict_combo'].currentText().strip(),
'dict_unique':
row['dict_combo'].itemData(row['dict_combo'].currentIndex()),
'dict_fld_name':
row['field_combo'].currentText().strip(),
'dict_fld_ord':
row['field_combo'].itemData(row['field_combo'].currentIndex()),
'ignore':
row['ignore_check_btn'].isChecked(),
'skip_valued':
row['skip_check_btn'].isChecked(),
'cloze_word':
row['cloze_check_btn'].isChecked()
})
return maps
@ -624,7 +643,7 @@ class TabContent(QScrollArea):
b = False
break
self.ignore_all_check_btn.setChecked(b)
def skip_all_update(self):
b = True
for row in self._options:
@ -635,8 +654,7 @@ class TabContent(QScrollArea):
class CTabBar(QTabBar):
def __init__(self, parent = None):
def __init__(self, parent=None):
super(CTabBar, self).__init__(parent)
# style
self.setTabsClosable(True)
@ -651,14 +669,17 @@ class CTabBar(QTabBar):
self._editor.installEventFilter(self)
def eventFilter(self, widget, event):
if ((event.type() == QEvent.MouseButtonPress and \
not self._editor.geometry().contains(event.globalPos()) \
) or \
(event.type() == QEvent.KeyPress and \
event.key() == Qt.Key_Escape)
):
self.hideEditor()
return True
bhide = False
if event.type() == QEvent.MouseButtonPress:
if not self._editor.geometry().contains(event.globalPos()):
bhide = True
if not bhide:
if event.type() == QEvent.KeyPress:
if event.key() == Qt.Key_Escape:
bhide = True
if bhide:
self.hideEditor()
return True
return QTabBar.eventFilter(self, widget, event)
def mouseDoubleClickEvent(self, event):
@ -676,7 +697,7 @@ class CTabBar(QTabBar):
self._editor.selectAll()
self._editor.setEnabled(True)
self._editor.setFocus()
def hideEditor(self):
if self._editor.isVisible():
self._editor.setEnabled(False)

View File

@ -1,4 +1,4 @@
#-*- coding:utf-8 -*-
# -*- coding:utf-8 -*-
#
# Copyright (C) 2018 sthoo <sth201807@gmail.com>
#
@ -17,24 +17,22 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import time
from collections import defaultdict
from aqt.qt import *
from ..lang import _
from ..context import APP_ICON
from ..context import APP_ICON
from ..lang import _
__all__ = ['ProgressWindow']
_INFO_TEMPLATE = u''.join([
u'<strong>' + _('QUERIED') + u'</strong>',
u'<p>' + 45 * u'-' + u'</p>',
u'<p>' + _('SUCCESS') + u' <b>{}</b> ' + _('WORDS') + u'</p>',
u'<p>' + _('SKIPED') + u' <b>{}</b> ' + _('WORDS') + u'</p>',
u'<p>' + _('UPDATE') + u' <b>{}</b> ' + _('FIELDS') + u'</p>',
u'<p>' + _('UPDATE') + u' <b>{}</b> ' + _('FIELDS') + u'</p>',
u'<p>' + _('FAILURE') + u' <b>{}</b> ' + _('WORDS') + u'</p>',
])
@ -66,15 +64,12 @@ class ProgressWindow(object):
self._msg_count.get('words_number', 0),
self._msg_count.get('fields_number', 0),
self._msg_count.get('fails_number', 0),
self._msg_count.get('skips_number', 0)
)
number_info = _INFO_TEMPLATE.format(
words_number,
skips_number,
fields_number,
fails_number
)
self._update(label=number_info, value=words_number+skips_number+fails_number)
self._msg_count.get('skips_number', 0))
number_info = _INFO_TEMPLATE.format(words_number, skips_number,
fields_number, fails_number)
self._update(
label=number_info,
value=words_number + skips_number + fails_number)
self._win.adjustSize()
self.app.processEvents()
@ -95,9 +90,7 @@ class ProgressWindow(object):
self._win.setWindowTitle("FastWQ - Querying...")
self._win.setModal(True)
self._win.setWindowFlags(
self._win.windowFlags() &
~Qt.WindowContextHelpButtonHint
)
self._win.windowFlags() & ~Qt.WindowContextHelpButtonHint)
self._win.setWindowIcon(APP_ICON)
self._win.setAutoReset(True)
self._win.setAutoClose(True)

View File

@ -1,4 +1,4 @@
#-*- coding:utf-8 -*-
# -*- coding:utf-8 -*-
#
# Copyright (C) 2018 sthoo <sth201807@gmail.com>
#
@ -18,10 +18,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from aqt.qt import *
from .base import Dialog, WIDGET_SIZE
from ..context import config
from ..lang import _
from .base import Dialog
__all__ = ['SettingDialog']
@ -36,7 +36,6 @@ class SettingDialog(Dialog):
self.setFixedWidth(400)
self.check_force_update = None
self.check_ignore_accents = None
# self.check_auto_update = None
self.input_thread_number = None
self.build()
@ -53,11 +52,6 @@ class SettingDialog(Dialog):
layout.addWidget(check_ignore_accents)
layout.addSpacing(10)
# check_auto_update = QCheckBox(_("AUTO_UPDATE"))
# check_auto_update.setChecked(config.auto_update)
# layout.addWidget(check_auto_update)
# layout.addSpacing(10)
check_ighore_mdx_wordcase = QCheckBox(_("IGNORE_MDX_WORDCASE"))
check_ighore_mdx_wordcase.setChecked(config.ignore_mdx_wordcase)
layout.addWidget(check_ighore_mdx_wordcase)
@ -84,35 +78,55 @@ class SettingDialog(Dialog):
hbox.setStretchFactor(input_cloze_str, 2)
layout.addLayout(hbox)
buttonBox = QDialogButtonBox(parent=self)
buttonBox.setStandardButtons(QDialogButtonBox.Ok)
buttonBox.accepted.connect(self.accept) # 确定
hbox = QHBoxLayout()
okbtn = QDialogButtonBox(parent=self)
okbtn.setStandardButtons(QDialogButtonBox.Ok)
okbtn.clicked.connect(self.accept)
resetbtn = QDialogButtonBox(parent=self)
resetbtn.setStandardButtons(QDialogButtonBox.Reset)
resetbtn.clicked.connect(self.reset)
hbox.setAlignment(Qt.AlignRight)
hbox.addSpacing(300)
hbox.addWidget(resetbtn)
hbox.addWidget(okbtn)
layout.addSpacing(48)
layout.addWidget(buttonBox)
layout.addLayout(hbox)
self.check_force_update = check_force_update
self.check_ignore_accents = check_ignore_accents
# self.check_auto_update = check_auto_update
self.check_ighore_mdx_wordcase = check_ighore_mdx_wordcase
self.input_thread_number = input_thread_number
self.input_cloze_str = input_cloze_str
layout.setAlignment(Qt.AlignTop|Qt.AlignLeft)
layout.setAlignment(Qt.AlignTop | Qt.AlignLeft)
self.setLayout(layout)
def accept(self):
self.save()
super(SettingDialog, self).accept()
def reset(self):
data = {
'force_update': False,
'ignore_accents': False,
'ignore_mdx_wordcase': False,
'thread_number': 16,
'cloze_str': '{{c1::%s}}'
}
config.update(data)
self.check_force_update.setChecked(config.force_update)
self.check_ignore_accents.setChecked(config.ignore_accents)
self.check_ighore_mdx_wordcase.setChecked(config.ignore_mdx_wordcase)
self.input_thread_number.setValue(config.thread_number)
self.input_cloze_str.setText(config.cloze_str)
def save(self):
data = {
'force_update': self.check_force_update.isChecked(),
'ignore_accents': self.check_ignore_accents.isChecked(),
# 'auto_update': self.check_auto_update.isChecked(),
'ignore_mdx_wordcase': self.check_ighore_mdx_wordcase.isChecked(),
'thread_number': self.input_thread_number.value(),
'cloze_str': self.input_cloze_str.text()
}
config.update(data)

View File

@ -1,4 +1,4 @@
#-*- coding:utf-8 -*-
# -*- coding:utf-8 -*-
#
# Copyright (C) 2018 sthoo <sth201807@gmail.com>
#
@ -18,15 +18,15 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from anki.lang import currentLang
try:
basestring
basestring
except NameError:
basestring = str
basestring = str
__all__ = ['_', '_cl', '_sl']
#Language Define, [Key, zh_CN, en]
# Language Define, [Key, zh_CN, en]
_arr = [
['CHECK_FILENAME_LABEL', u'使用文件名作为标签', u'Use the Filename as Label'],
['EXPORT_MEDIA', u'导出媒体文件', u'Export Media Files'],
@ -42,13 +42,19 @@ _arr = [
['QUERIED', u'查询', u'Queried'],
['FIELDS', u'字段', u'Fields'],
['WORDS', u'单词', u'Words'],
['NOT_DICT_FIELD', u'忽略', u'Ignore'], #不是字典字段
['NOT_DICT_FIELD', u'忽略', u'Ignore'], # 不是字典字段
['NOTE_TYPE_FIELDS', u'<b>笔记字段</b>', u'<b>Note Fields</b>'],
['DICTS', u'<b>字典</b>', u'<b>Dictionary</b>'],
['DICT_FIELDS', u'<b>字典字段</b>', u'<b>Fields</b>'],
['RADIOS_DESC', u'<b>单选框选中为待查询单词字段</b>', u'<b> Select the field to be queried with single selection.</b>'],
[
'RADIOS_DESC', u'<b>单选框选中为待查询单词字段</b>',
u'<b> Select the field to be queried with single selection.</b>'
],
['NO_QUERY_WORD', u'查询字段无单词', u'The query field is empty'],
['CSS_NOT_FOUND', u'没有找到CSS文件请手动选择', u'No CSS file found, please select one manually.'],
[
'CSS_NOT_FOUND', u'没有找到CSS文件请手动选择',
u'No CSS file found, please select one manually.'
],
['ABOUT', u'关于', u'About'],
['REPOSITORY', u'项目地址', u'Project Repo'],
['FEEDBACK', u'反馈', u'Feedback'],
@ -60,7 +66,10 @@ _arr = [
['UPDATE', u'更新', u'Update'],
['AUTO_UPDATE', u'自动检测新版本', u'Auto check new version'],
['CHECK_UPDATE', u'检测更新', u'Check Update'],
['IGNORE_MDX_WORDCASE', u'忽略本地词典单词大小写', u'Ignore MDX dictionary word case'],
[
'IGNORE_MDX_WORDCASE', u'忽略本地词典单词大小写',
u'Ignore MDX dictionary word case'
],
['FORCE_UPDATE', u'强制更新字段', u'Forced Updates of all fields'],
['IGNORE_ACCENTS', u'忽略声调', u'Ignore Accents'],
['SKIP_VALUED', u'跳过有值项', u'Skip non-empty'],
@ -68,7 +77,10 @@ _arr = [
['SETTINGS', u'参数', u'Settings'],
['THREAD_NUMBER', u'线程数', u'Number of Threads'],
['INITLIZING_DICT', u'初始化词典...', u'Initlizing Dictionary...'],
['PLS_SET_DICTIONARY_FIELDS', u'请设置字典和字段', u'Please set the dictionary and fields.'],
[
'PLS_SET_DICTIONARY_FIELDS', u'请设置字典和字段',
u'Please set the dictionary and fields.'
],
['CONFIG_INDEX', u'配置 %s', u'Config %s'],
['SELECT_ALL', u'全选', u'All'],
['DICTS_NAME', u'字典名称', u'Dictionary Name'],
@ -80,7 +92,6 @@ _arr = [
['OPTIONS', u'选项', u'Options'],
['CLOZE_WORD', u'单词填空', u'Cloze word'],
['CLOZE_WORD_FORMAT', '单词填空格式', 'Cloze word formater'],
['BRE_PRON', u'英式发音', u'British Pronunciation'],
['AME_PRON', u'美式发音', u'American Pronunciation'],
['PRON', u'发音', u'Audio Pronunciation'],
@ -103,7 +114,7 @@ def _(key, lang=currentLang):
def disp(s):
return s.lower().capitalize()
if key not in _trans or lang not in _trans[key]:
return disp(key)
return _trans[key][lang]

File diff suppressed because it is too large Load Diff

View File

@ -1,48 +0,0 @@
# -*- coding: utf-8 -*-
from aqt.qt import *
try:
_encoding = QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QApplication.translate(context, text, disambig)
class Ui_DialogUpdates(object):
def setupUi(self, DialogUpdates):
DialogUpdates.setObjectName(u"DialogUpdates")
DialogUpdates.resize(500, 400)
self.verticalLayout = QVBoxLayout(DialogUpdates)
self.verticalLayout.setObjectName(u"verticalLayout")
self.labelUpdates = QLabel(DialogUpdates)
self.labelUpdates.setWordWrap(True)
self.labelUpdates.setOpenExternalLinks(True)
self.labelUpdates.setObjectName(u"labelUpdates")
self.verticalLayout.addWidget(self.labelUpdates)
self.textBrowser = QTextBrowser(DialogUpdates)
self.textBrowser.setObjectName(u"textBrowser")
self.verticalLayout.addWidget(self.textBrowser)
self.horizontalLayout = QHBoxLayout()
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.update = QPushButton(DialogUpdates)
self.update.setObjectName(u"update")
self.horizontalLayout.addWidget(self.update, 0, Qt.AlignCenter)
self.verticalLayout.addLayout(self.horizontalLayout)
self.retranslateUi(DialogUpdates)
QMetaObject.connectSlotsByName(DialogUpdates)
def retranslateUi(self, DialogUpdates):
DialogUpdates.setWindowTitle(_translate("DialogUpdates", "FastWQ - Updater", None))
self.labelUpdates.setText(_translate(
"DialogUpdates",
"<html><head/><body>\
<p>A new version of {0} is available for download! </p>\
<p>Do you want to update {1}to version {2}?</p>\
<p>Changes from your version are listed below:</p>\
</body></html>",
None
))
self.update.setText(_translate("DialogUpdates", "Update", None))

View File

@ -1,311 +0,0 @@
try:
import httplib
except:
import http.client as httplib
try:
import urllib2
except:
import urllib.request as urllib2
import json
import os
import sys
import zipfile
import traceback
import io
import aqt
from aqt import mw
from aqt.qt import *
from aqt.utils import showInfo
from anki.hooks import addHook
from anki.utils import isMac, isWin
from ..context import APP_ICON
from .AnkiHub.updates import Ui_DialogUpdates
from .AnkiHub.markdown2 import markdown
__all__ = ['update']
# taken from Anki's aqt/profiles.py
def defaultBase():
path = mw.pm.addonFolder()
return os.path.dirname(os.path.abspath(path))
headers = {"User-Agent": "AnkiHub"}
dataPath = os.path.join(defaultBase(),'.fastwq_2.1.x_ankihub.json')
class DialogUpdates(QDialog, Ui_DialogUpdates):
def __init__(self, parent, data, oldData, callback):
parent = parent if parent else mw
QDialog.__init__(self, parent)
self.setModal(True)
self.setWindowFlags(
self.windowFlags() &
~Qt.WindowContextHelpButtonHint
)
self.setWindowIcon(APP_ICON)
self.setupUi(self)
totalSize = sum(map(lambda x:x['size'],data['assets']))
def answer():
self.update.setEnabled(False)
callback(self.appendHtml, self.finish)
self.html = u''
self.appendHtml(markdown(data['body']))
#if not automaticAnswer:
self.update.clicked.connect(lambda:answer())
fromVersion = ''
if 'tag_name' in oldData:
fromVersion = u'from {0} '.format(oldData['tag_name'])
self.labelUpdates.setText(
str(self.labelUpdates.text()).format(
data['name'],
fromVersion,
data['tag_name']))
def appendHtml(self,html='',temp=''):
self.html += html
self.textBrowser.setHtml(u'<html><body>{0}{1}{2}</body></html>'.format(self.html, temp, u'<div id="text_bottom"></div>'))
self.textBrowser.scrollToAnchor('text_bottom')
def finish(self):
self.hide()
self.destroy()
showInfo('Updated. Please restart Anki.')
pass
def installZipFile(data, fname):
#base = os.path.join(mw.pm.addonFolder(), 'fastwq')
base = os.path.realpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../'))
if fname.endswith(".py"):
path = os.path.join(base, fname)
with open(path, "wb") as file:
file.write(data)
file.close()
return True
# .zip file
try:
z = zipfile.ZipFile(io.BytesIO(data))
except zipfile.BadZipfile:
return False
for n in z.namelist():
if n.endswith("/"):
# folder; ignore
continue
# write
try:
z.extract(n, base)
except:
print(n)
return True
def asset(a):
return {
'url': a['browser_download_url'],
'size': a['size']
}
def updateSingle(repositories, path, data):
def callback(appendHtml, onReady):
for asset in data['assets']:
code = asset['url']
p, fname = os.path.split(code)
appendHtml(temp='<br />Downloading {1}: {0}%<br/>'.format(0,fname))
try:
urlthread = UrlThread(code)
urlthread.start()
urlthread.join()
response = urlthread.response#urllib2.urlopen(code)
meta = response.info()
file_size = int(meta.get("Content-Length"))
except:
appendHtml('Downloading file error!<br/>')
return
d = b''
dl = 0
i = 0
lastPercent = None
while True:
dkb = response.read(1024)
if not dkb:
break
dl += len(dkb)
d += dkb
if dl*100/file_size>i:
lastPercent = int(dl*100/file_size)
i = lastPercent+1
appendHtml(temp='<br />Downloading {1}: {0}%<br/>'.format(lastPercent,fname))
QApplication.instance().processEvents()
appendHtml('<br />Downloading {1}: 100%<br/>'.format(int(dl*100/file_size),fname))
appendHtml('Installing ...<br/>')
if not installZipFile(d, fname):
appendHtml('Corrupt file<br/>')
else:
repositories[path] = data
repositories[path]['update'] = 'ask'
with open(dataPath,'w') as f:
json.dump(repositories,f,indent=2)
f.close()
appendHtml('Done.<br/>')
onReady() # close the AnkiHub update window
return callback
def update(add=[], VERSION='v0.0.0', background=False, parent=None):
parent = parent if parent else mw
# progress win
if not background:
progresswin = QProgressDialog('Update Checking...', '', 0, 0, parent)
progresswin.setWindowModality(Qt.ApplicationModal)
progresswin.setCancelButton(None)
progresswin.setWindowFlags(
progresswin.windowFlags() &
~Qt.WindowContextHelpButtonHint
)
progresswin.setWindowTitle('FastWQ - Updater')
progresswin.setWindowIcon(APP_ICON)
progresswin.resize(280, 60)
progresswin.show()
else:
progresswin = None
#
conn = httplib.HTTPSConnection("api.github.com")
try:
with open(dataPath,'r') as f:
repositories = json.load(f)
f.close()
except:
repositories = {}
for a in add:
if a not in repositories:
repositories[a] = {
'id': 0,
'update': 'ask'
}
for path,repository in repositories.items():
username,repositoryName = path.split('/')
try:
urlthread = UrlThread("https://api.github.com/repos/{0}/releases/latest".format(path))
urlthread.start()
urlthread.join()
release = json.loads(urlthread.response.read())
except Exception as e:
release = {}
if 'id' in release:
if release['id'] != repository['id']:
data = {
'id': release['id'],
'name': repositoryName,
'tag_name': release['tag_name'],
'body': '### {0}\n'.format(release['name']) + release['body'],
'assets': [asset(release['assets'][1])],
'update': 'ask'
}
if 'tag_name' in repository:
oldVersion = map(int,repository['tag_name'][1:].split('.'))
oldVersion = [x for x in oldVersion]
while len(oldVersion)<3:
oldVersion.append(0)
else:
oldVersion = map(int,VERSION[1:].split('.'))#[0,0,0]
oldVersion = [x for x in oldVersion]
newVersion = map(int,data['tag_name'][1:].split('.'))
newVersion = [x for x in newVersion]
isMinor = len(newVersion)>2 and newVersion[2]>0
while len(newVersion)<3:
newVersion.append(0)
i = oldVersion[2]+1
if oldVersion[0]<newVersion[0] or oldVersion[1]<newVersion[1]:
if isMinor:
i = 1
while i<newVersion[2]:
if progresswin and progresswin.wasCanceled():
break
try:
minorTagName = 'v{0}.{1}.{2}'.format(newVersion[0],oldVersion[1],i)
urlthread = UrlThread("https://api.github.com/repos/{0}/releases/tags/{1}".format(path,minorTagName))
urlthread.start()
urlthread.join()
responseData = urlthread.response.read()
minor = json.loads(responseData)
data['body'] += '\n\n### {0}\n'.format(minor['name']) + minor['body']
except:
pass
i += 1
if oldVersion[0]<newVersion[0] or oldVersion[1]<newVersion[1]:
# new major release necessary!
# if the newest version is minor, fetch the additional assets from the major
if isMinor and (background or not progresswin.wasCanceled()):
try:
majorTagName = 'v{0}.{1}'.format(newVersion[0],newVersion[1])
urlthread = UrlThread(
"https://api.github.com/repos/{0}/releases/tags/{1}".format(path,majorTagName),
"https://api.github.com/repos/{0}/releases/tags/{1}.0".format(path,majorTagName)
)
urlthread.start()
urlthread.join()
responseData = urlthread.response.read()
major = json.loads(responseData)
data['body'] += '\n\n### {0}\n'.format(major['name']) + major['body']
except:
pass
if background or not progresswin.wasCanceled():
if progresswin:
progresswin.hide()
progresswin.destroy()
dialog = DialogUpdates(parent, data, repository, updateSingle(repositories, path, data))
dialog.exec_()
dialog.destroy()
else:
if progresswin:
progresswin.hide()
progresswin.destroy()
return 1
else:
if progresswin:
progresswin.hide()
progresswin.destroy()
return 0
if progresswin:
progresswin.hide()
progresswin.destroy()
return -1
class UrlThread(QThread):
def __init__(self, url, backurl=None):
super(UrlThread, self).__init__()
self.response = None
self.url = url
self.backurl = backurl
self.finished = False
def run(self):
try:
self.response = urllib2.urlopen(self.url)
except:
if self.backurl:
try:
self.response = urllib2.urlopen(self.backurl)
except:
pass
self.finished = True
def join(self):
while not self.finished:
QApplication.instance().processEvents()
self.wait(30)

View File

@ -1,17 +1,19 @@
# -*- coding: utf-8 -*-
from .readmdict import MDX, MDD
from struct import pack, unpack
from io import BytesIO
import re
import sys
import os
import sqlite3
import json
import os
import re
import sqlite3
import sys
# zlib compression is used for engine version >=2.0
import zlib
from io import BytesIO
from struct import pack, unpack
import chardet
from .readmdict import MDD, MDX
# LZO compression is used for engine version < 2.0
try:
import lzo
@ -110,16 +112,22 @@ class IndexBuilder(object):
def _replace_stylesheet(self, txt):
# substitute stylesheet definition
encoding = 'utf-8'
if isinstance(txt, bytes):
encode_type = chardet.detect(txt)
encoding = encode_type['encoding']
txt = txt.decode(encoding)
txt_list = re.split('`\d+`', txt)
txt_tag = re.findall('`\d+`', txt)
txt_styled = txt_list[0]
for j, p in enumerate(txt_list[1:]):
style = self._stylesheet[txt_tag[j][1:-1]]
if p and p[-1] == '\n':
txt_styled = txt_styled + style[0] + p.rstrip() + style[1] + '\r\n'
txt_styled = txt_styled + style[0] + p.rstrip(
) + style[1] + '\r\n'
else:
txt_styled = txt_styled + style[0] + p + style[1]
return txt_styled
return txt_styled.encode(encoding)
def _make_mdx_index(self, db_name):
if os.path.exists(db_name):

View File

@ -1,4 +1,4 @@
#-*- coding:utf-8 -*-
# -*- coding:utf-8 -*-
#
# Copyright (C) 2018 sthoo <sth201807@gmail.com>
#
@ -17,29 +17,26 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import io
import os
import re
import io
import shutil
import unicodedata
from collections import defaultdict
from aqt.qt import *
from aqt.utils import showInfo
from ..constants import Template
from ..context import config
from ..service import service_pool, QueryResult, copy_static_file
from ..libs.snowballstemmer import stemmer
from ..service import QueryResult, copy_static_file, service_pool
from ..service.base import LocalService
from ..utils import wrap_css
from ..libs.snowballstemmer import stemmer
__all__ = [
'InvalidWordException', 'update_note_fields',
'update_note_field', 'promot_choose_css', 'add_to_tmpl',
'query_flds', 'inspect_note'
'InvalidWordException', 'update_note_fields', 'update_note_field',
'promot_choose_css', 'add_to_tmpl', 'query_flds', 'inspect_note'
]
@ -127,19 +124,14 @@ def promot_choose_css(missed_css):
if not os.path.exists(filename) and not css['file'] in checked:
checked.add(css['file'])
showInfo(
Template.miss_css.format(
dict=css['title'],
css=css['file']
)
)
Template.miss_css.format(dict=css['title'], css=css['file']))
try:
filepath = css['dict_path'][:css['dict_path'].rindex(
os.path.sep)+1]
filepath = css['dict_path'][:css['dict_path'].rindex(os.path.
sep) + 1]
filepath = QFileDialog.getOpenFileName(
directory=filepath,
caption=u'Choose css file',
filter=u'CSS (*.css)'
)
filter=u'CSS (*.css)')
if filepath:
shutil.copy(filepath, filename)
wrap_css(filename)
@ -161,15 +153,17 @@ def add_to_tmpl(note, **kwargs):
if js and js.strip():
addings = js.strip()
if addings not in afmt:
if not addings.startswith(u'<script') and not addings.endswith(u'/script>'):
addings = u'\n<script type="text/javascript">\n{}\n</script>'.format(addings)
if not addings.startswith(u'<script') and not addings.endswith(
u'/script>'):
addings = u'\n<script type="text/javascript">\n{}\n</script>'.format(
addings)
afmt += addings
if jsfile:
#new_jsfile = u'_' + \
# jsfile if not jsfile.startswith(u'_') else jsfile
#copy_static_file(jsfile, new_jsfile)
#addings = u'\r\n<script src="{}"></script>'.format(new_jsfile)
#afmt += addings
# new_jsfile = u'_' + \
# jsfile if not jsfile.startswith(u'_') else jsfile
# copy_static_file(jsfile, new_jsfile)
# addings = u'\r\n<script src="{}"></script>'.format(new_jsfile)
# afmt += addings
jsfile = jsfile if isinstance(jsfile, list) else [jsfile]
for fn in jsfile:
addings = '''
@ -204,17 +198,17 @@ def query_flds(note, fileds=None):
continue
if i == len(note.fields):
break
#ignore field
# ignore field
ignore = each.get('ignore', False)
if ignore:
continue
#skip valued
# skip valued
skip = each.get('skip_valued', False)
if skip and len(note.fields[i]) != 0:
continue
#cloze
# cloze
cloze = each.get('cloze_word', False)
#normal
# normal
dict_unique = each.get('dict_unique', '').strip()
dict_fld_ord = each.get('dict_fld_ord', -1)
fld_ord = each.get('fld_ord', -1)
@ -227,9 +221,9 @@ def query_flds(note, fileds=None):
services[dict_unique] = s
if s and s.support:
tasks.append({
'k': dict_unique,
'k': dict_unique,
'w': word,
'f': dict_fld_ord,
'f': dict_fld_ord,
'i': fld_ord,
'cloze': cloze,
})
@ -237,17 +231,17 @@ def query_flds(note, fileds=None):
success_num = 0
result = defaultdict(QueryResult)
for task in tasks:
#try:
service = services.get(task['k'], None)
qr = service.active(task['f'], task['w'])
if qr:
if task['cloze']:
qr['result'] = cloze_deletion(qr['result'], word)
result.update({task['i']: qr})
success_num += 1
#except:
# showInfo(_("NO_QUERY_WORD"))
# pass
try:
service = services.get(task['k'], None)
qr = service.active(task['f'], task['w'])
if qr:
if task['cloze']:
qr['result'] = cloze_deletion(qr['result'], word)
result.update({task['i']: qr})
success_num += 1
except Exception as e:
print(_("NO_QUERY_WORD"), e)
pass
missed_css = list()
for service in services.values():
@ -284,13 +278,15 @@ def cloze_deletion(text, cloze):
continue
word = text[s:e]
if _stemmer.stemWord(word).lower() == term:
l = len(cloze)
ln = len(cloze)
w = word
if w[:l].lower() == cloze.lower():
e = s + l
w = word[:l]
result = result[:s+offset] + (config.cloze_str % w) + result[e+offset:]
offset += len(config.cloze_str)-2
if w[:ln].lower() == cloze.lower():
e = s + ln
w = word[:ln]
result = result[:s + offset] + (
config.cloze_str % w) + result[e + offset:]
offset += len(config.cloze_str) - 2
return result
_stemmer = stemmer('english')

View File

@ -1,4 +1,4 @@
#-*- coding:utf-8 -*-
# -*- coding:utf-8 -*-
#
# Copyright (C) 2018 sthoo <sth201807@gmail.com>
#
@ -19,6 +19,7 @@
import inspect
import os
import random
# use ntpath module to ensure the windows-style (e.g. '\\LDOCE.css')
# path can be processed on Unix platform.
# However, anki version on mac platforms doesn't including this package?
@ -27,32 +28,33 @@ import re
import shutil
import sqlite3
import urllib
import zlib
from collections import defaultdict
from functools import wraps
from hashlib import md5, sha1
import requests
from bs4 import BeautifulSoup
from aqt import mw
from aqt.qt import QMutex, QThread
from ..context import config
from ..lang import _cl
from ..libs import MdxBuilder, StardictBuilder
from ..utils import MapDict, wrap_css
try:
import urllib2
except:
except Exception:
import urllib.request as urllib2
import zlib
import random
from collections import defaultdict
from functools import wraps
from hashlib import md5
from hashlib import sha1
try:
from cookielib import CookieJar
except:
except Exception:
from http.cookiejar import CookieJar
from aqt import mw
from aqt.qt import QThread, QMutex
from bs4 import BeautifulSoup
from ..context import config
from ..libs import MdxBuilder, StardictBuilder
from ..utils import MapDict, wrap_css
from ..lang import _cl
try:
import threading as _threading
@ -69,18 +71,14 @@ __all__ = [
def get_hex_name(prefix, val, suffix):
''' get sha1 hax name '''
hex_digest = sha1(val.encode('utf-8')).hexdigest().lower()
name = '.'.join([
'-'.join([
prefix, hex_digest[:8], hex_digest[8:16],
hex_digest[16:24], hex_digest[24:32], hex_digest[32:],
]),
suffix,
])
name = '.'.join(['-'.join([prefix, hex_digest[:8], hex_digest[8:16], hex_digest[16:24], hex_digest[24:32], hex_digest[32:], ]), suffix, ])
return name
def _is_method_or_func(object):
return inspect.isfunction(object) or inspect.ismethod(object)
def register(labels):
"""
register the dict service with a labels, which will be shown in the dicts list.
@ -120,6 +118,8 @@ def export(labels):
export.EXPORT_INDEX += 1
return _deco
return _with
export.EXPORT_INDEX = 0
@ -181,8 +181,9 @@ def with_styles(**styles):
return _deco
return _with
# bs4 threading lock, overload protection
_BS_LOCKS = [_threading.Lock(), _threading.Lock()]
_BS_LOCKS = [_threading.Lock(), _threading.Lock()] # bs4 threading lock, overload protection
def parse_html(html):
'''
@ -238,6 +239,7 @@ class Service(object):
@property
def unique(self):
return self._unique
@unique.setter
def unique(self, value):
self._unique = value
@ -326,7 +328,7 @@ class WebService(Service):
if response.info().get('Content-Encoding') == 'gzip':
data = zlib.decompress(data, 16 + zlib.MAX_WBITS)
return data
except:
except Exception:
return u''
@classmethod
@ -340,7 +342,7 @@ class WebService(Service):
'(KHTML, like Gecko) Chrome/31.0.1623.0 Safari/537.36'
}).content)
return True
except Exception as e:
except Exception:
pass
class TinyDownloadError(ValueError):
@ -370,7 +372,7 @@ class WebService(Service):
be added onto the stream returned. This is helpful for some web
services that sometimes return MP3s that `mplayer` clips early.
"""
DEFAULT_UA = 'Mozilla/5.0'
DEFAULT_UA = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36'
DEFAULT_TIMEOUT = 3
PADDING = '\0' * 2**11
@ -434,7 +436,7 @@ class WebService(Service):
try:
value_error.payload = response.read()
response.close()
except:
except Exception:
pass
raise value_error
@ -475,7 +477,7 @@ class WebService(Service):
f.write(payload)
f.close()
return True
except:
except Exception:
return False
@ -516,7 +518,7 @@ class LocalService(Service):
def _get_builer(key, func=None):
LocalService._mutex_builder.lock()
key = md5(str(key).encode('utf-8')).hexdigest()
if not func is None:
if not(func is None):
if not LocalService._mdx_builders[key]:
worker = _DictBuildWorker(func)
worker.start()
@ -582,21 +584,22 @@ class MdxService(LocalService):
jsfile = re.findall(r'<script .*?src=[\'\"](.+?)[\'\"]', html, re.DOTALL)
return QueryResult(result=html, js=u'\n'.join(js), jsfile=jsfile)
def _get_definition_mdx(self):
"""according to the word return mdx dictionary page"""
content = self.builder.mdx_lookup(self.word, ignorecase=config.ignore_mdx_wordcase)
ignorecase = config.ignore_mdx_wordcase and (self.word != self.word.lower() or self.word != self.word.upper())
content = self.builder.mdx_lookup(self.word, ignorecase=ignorecase)
str_content = ""
if len(content) > 0:
for c in content:
str_content += c.replace("\r\n","").replace("entry:/","")
str_content += c.replace("\r\n", "").replace("entry:/", "")
return str_content
def _get_definition_mdd(self, word):
"""according to the keyword(param word) return the media file contents"""
word = word.replace('/', '\\')
content = self.builder.mdd_lookup(word, ignorecase=config.ignore_mdx_wordcase)
ignorecase = config.ignore_mdx_wordcase and (word != word.lower() or word != word.upper())
content = self.builder.mdd_lookup(word, ignorecase=ignorecase)
if len(content) > 0:
return [content[0]]
else:
@ -620,7 +623,7 @@ class MdxService(LocalService):
f.write(bytes_list[0])
return savepath
except sqlite3.OperationalError as e:
#showInfo(str(e))
print(e)
pass
return ''
@ -677,7 +680,7 @@ class MdxService(LocalService):
# folder first, and it will also execute the wrap process to generate
# the desired file.
if not os.path.exists(cssfile):
css_src = self.dict_path.replace(self._filename+u'.mdx', f)
css_src = self.dict_path.replace(self._filename + u'.mdx', f)
if os.path.exists(css_src):
shutil.copy(css_src, cssfile)
else:
@ -700,17 +703,19 @@ class MdxService(LocalService):
if os.path.exists(savepath):
return savepath
try:
src_fn = self.dict_path.replace(self._filename+u'.mdx', basename)
src_fn = self.dict_path.replace(self._filename + u'.mdx', basename)
if os.path.exists(src_fn):
shutil.copy(src_fn, savepath)
return savepath
else:
bytes_list = self.builder.mdd_lookup(filepath_in_mdx, ignorecase=config.ignore_mdx_wordcase)
ignorecase = config.ignore_mdx_wordcase and (filepath_in_mdx != filepath_in_mdx.lower() or filepath_in_mdx != filepath_in_mdx.upper())
bytes_list = self.builder.mdd_lookup(filepath_in_mdx, ignorecase=ignorecase)
if bytes_list:
with open(savepath, 'wb') as f:
f.write(bytes_list[0])
return savepath
except sqlite3.OperationalError as e:
print('save default file error', e)
pass
def save_media_files(self, data):
@ -752,7 +757,7 @@ class StardictService(LocalService):
dict_path,
service_wrap(StardictBuilder, dict_path, in_memory=False)
)
#if self.builder:
# if self.builder:
# self.builder.get_header()
@staticmethod
@ -772,7 +777,7 @@ class StardictService(LocalService):
@export([u'默认', u'Default'])
def fld_whole(self):
#self.builder.check_build()
# self.builder.check_build()
try:
result = self.builder[self.word]
result = result.strip().replace('\r\n', '<br />')\
@ -788,7 +793,7 @@ class QueryResult(MapDict):
def __init__(self, *args, **kwargs):
super(QueryResult, self).__init__(*args, **kwargs)
# avoid return None
if self['result'] == None:
if self['result'] is None:
self['result'] = ""
def set_styles(self, **kwargs):

View File

@ -51,6 +51,9 @@ class Cambridge(WebService):
if snd:
result['pronunciation'][pn+'mp3'] = cambridge_url_base + snd.get('data-src-mp3')
header_found = True
# 词性
pg = element.find('span', class_='posgram ico-bg')
#义
body = element.find('div', class_='pos-body')
if body:
@ -63,9 +66,11 @@ class Cambridge(WebService):
trans = tag.find('span', class_='trans')
es = tag.find_all('div', class_='examp emphasized')
l.append(
u'<li>{0}{1}{2}{3}</li>'.format(
u'<li>{0}{1}{2} {3}{4}</li>'.format(
'<span class="epp-xref">{0}</span>'.format(pg.get_text() if pg else ''),
u'<span class="epp-xref">{0}</span>'.format(i.get_text()) if i else u'',
u'<b class="def">{0}</b>'.format(d.get_text()) if d else u'',
u'<span class="trans">{0}</span>'.format(trans.get_text()) if trans else u'',
u''.join(
u'<div class="examp">{0}</div>'.format(e.get_text()) if e else u''