From 25a4310fb90ccd8639f89e99cdda2387a302e2f0 Mon Sep 17 00:00:00 2001 From: "ken@szboeye.com" <> Date: Tue, 3 May 2011 14:24:21 +0800 Subject: [PATCH 1/6] Add support for the Boeye Digital Reader . --- src/calibre/customize/builtins.py | 3 + src/calibre/customize/profiles.py | 89 ++++++++++++++++++++++++++- src/calibre/devices/boeye/__init__.py | 0 src/calibre/devices/boeye/driver.py | 57 +++++++++++++++++ 4 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 src/calibre/devices/boeye/__init__.py create mode 100644 src/calibre/devices/boeye/driver.py diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index 776b04d5f6..c1da8391e0 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -613,6 +613,7 @@ from calibre.devices.misc import PALMPRE, AVANT, SWEEX, PDNOVEL, \ from calibre.devices.folder_device.driver import FOLDER_DEVICE_FOR_CONFIG from calibre.devices.kobo.driver import KOBO from calibre.devices.bambook.driver import BAMBOOK +from calibre.devices.boeye.driver import BOEYE_BEX, BOEYE_BDX from calibre.library.catalog import CSV_XML, EPUB_MOBI, BIBTEX from calibre.ebooks.epub.fix.unmanifested import Unmanifested @@ -743,6 +744,8 @@ plugins += [ EEEREADER, NEXTBOOK, ITUNES, + BOEYE_BEX, + BOEYE_BDX, USER_DEFINED, ] plugins += [x for x in list(locals().values()) if isinstance(x, type) and \ diff --git a/src/calibre/customize/profiles.py b/src/calibre/customize/profiles.py index 5c29f1e79b..e771a36c2e 100644 --- a/src/calibre/customize/profiles.py +++ b/src/calibre/customize/profiles.py @@ -214,11 +214,51 @@ class NookInput(InputProfile): dpi = 167 fbase = 16 fsizes = [12, 12, 14, 16, 18, 20, 22, 24] + +class BoeyeG5Input(InputProfile): + + author = 'Ken' + name = 'Boeye Digital Reader G5' + short_name = 'boeyeg5' + description = _('This profile is intended for the Boeye G5.') + + # Screen size is a best guess + screen_size = (600, 800) + dpi = 200 + fbase = 16 + fsizes = [12, 14, 16, 18, 20, 22, 24] + +class BoeyeG6Input(InputProfile): + + author = 'Ken' + name = 'Boeye Digital Reader G6' + short_name = 'boeyeg6' + description = _('This profile is intended for the Boeye G6.') + + # Screen size is a best guess + screen_size = (600, 800) + dpi = 166.66 + fbase = 16 + fsizes = [12, 14, 16, 18, 20, 22, 24] + +class BoeyeG10Input(InputProfile): + + author = 'Ken' + name = 'Boeye Digital Reader G10' + short_name = 'boeyeg10' + description = _('This profile is intended for the Boeye G10.') + + # Screen size is a best guess + screen_size = (825, 1200) + dpi = 150 + fbase = 16 + fsizes = [12, 14, 16, 18, 20, 22, 24] + input_profiles = [InputProfile, SonyReaderInput, SonyReader300Input, SonyReader900Input, MSReaderInput, MobipocketInput, HanlinV3Input, HanlinV5Input, CybookG3Input, CybookOpusInput, KindleInput, IlliadInput, - IRexDR1000Input, IRexDR800Input, NookInput] + IRexDR1000Input, IRexDR800Input, NookInput, BoeyeG5Input, BoeyeG6Input, BoeyeG10Input] input_profiles.sort(cmp=lambda x,y:cmp(x.name.lower(), y.name.lower())) @@ -730,6 +770,50 @@ class BambookOutput(OutputProfile): dpi = 168.451 fbase = 12 fsizes = [10, 12, 14, 16] + +class BoeyeG5Output(OutputProfile): + + author = 'Ken' + name = 'Boeye Digital Reader G5' + short_name = 'boeyeg5' + description = _('This profile is intended for the Boeye Digital Reader G5.') + + # Screen size is a best guess + screen_size = (600, 800) + comic_screen_size = (600, 740) + dpi = 200 + fbase = 16 + fsizes = [12, 14, 16, 18, 20, 22, 24] + + +class BoeyeG6Output(OutputProfile): + + author = 'Ken' + name = 'Boeye Digital Reader G6' + short_name = 'boeyeg6' + description = _('This profile is intended for the Boeye Digital Reader G6.') + + # Screen size is a best guess + screen_size = (600, 800) + comic_screen_size = (600, 740) + dpi = 160 + fbase = 16 + fsizes = [12, 14, 16, 18, 20, 22, 24] + +class BoeyeG10Output(OutputProfile): + + author = 'Ken' + name = 'Boeye Digital Reader G10' + short_name = 'boeyeg10' + description = _('This profile is intended for the Boeye Digital Reader G10.') + + # Screen size is a best guess + screen_size = (825, 1200) + comic_screen_size = (824, 1140) + dpi = 150 + fbase = 16 + fsizes = [12, 14, 16, 18, 20, 22, 24] + output_profiles = [OutputProfile, SonyReaderOutput, SonyReader300Output, SonyReader900Output, MSReaderOutput, MobipocketOutput, HanlinV3Output, @@ -737,6 +821,7 @@ output_profiles = [OutputProfile, SonyReaderOutput, SonyReader300Output, iPadOutput, KoboReaderOutput, TabletOutput, SamsungGalaxy, SonyReaderLandscapeOutput, KindleDXOutput, IlliadOutput, IRexDR1000Output, IRexDR800Output, JetBook5Output, NookOutput, - BambookOutput, NookColorOutput, GenericEink, GenericEinkLarge] + BambookOutput, NookColorOutput, BoeyeG5Output, BoeyeG6Output, BoeyeG10Output, + GenericEink, GenericEinkLarge] output_profiles.sort(cmp=lambda x,y:cmp(x.name.lower(), y.name.lower())) diff --git a/src/calibre/devices/boeye/__init__.py b/src/calibre/devices/boeye/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/calibre/devices/boeye/driver.py b/src/calibre/devices/boeye/driver.py new file mode 100644 index 0000000000..fcde1653d1 --- /dev/null +++ b/src/calibre/devices/boeye/driver.py @@ -0,0 +1,57 @@ +__license__ = 'GPL v3' +__copyright__ = '2011, Ken ' +__docformat__ = 'restructuredtext en' + +''' +Device driver for BOEYE serial readers +''' + +import re +from calibre.devices.usbms.driver import USBMS + +class BOEYE_BEX(USBMS): + name = 'BOEYE BEX reader driver' + gui_name = 'BOEYE BEX' + description = _('Communicate with BOEYE BEX Serial eBook readers.') + author = 'szboeye' + supported_platforms = ['windows', 'osx', 'linux'] + + FORMATS = ['epub', 'mobi', 'fb2', 'lit', 'prc', 'pdf', 'rtf', 'txt', 'djvu', 'doc', 'chm', 'html', 'zip', 'pdb'] + + VENDOR_ID = [0x0085] + PRODUCT_ID = [0x600] + + VENDOR_NAME = 'LINUX' + WINDOWS_MAIN_MEM = 'FILE-STOR_GADGET' + OSX_MAIN_MEM = 'Linux File-Stor Gadget Media' + + MAIN_MEMORY_VOLUME_LABEL = 'BOEYE BEX Storage Card' + + EBOOK_DIR_MAIN = 'Documents' + SUPPORTS_SUB_DIRS = True + +class BOEYE_BDX(USBMS): + name = 'BOEYE BDX reader driver' + gui_name = 'BOEYE BDX' + description = _('Communicate with BOEYE BDX serial eBook readers.') + author = 'szboeye' + supported_platforms = ['windows', 'osx', 'linux'] + + FORMATS = ['epub', 'mobi', 'fb2', 'lit', 'prc', 'pdf', 'rtf', 'txt', 'djvu', 'doc', 'chm', 'html', 'zip', 'pdb'] + + VENDOR_ID = [0x0085] + PRODUCT_ID = [0x800] + + VENDOR_NAME = 'LINUX' + WINDOWS_MAIN_MEM = 'FILE-STOR_GADGET' + WINDOWS_CARD_A_MEM = 'FILE-STOR_GADGET' + + OSX_MAIN_MEM = 'Linux File-Stor Gadget Media' + OSX_CARD_A_MEM = 'Linux File-Stor Gadget Media' + + MAIN_MEMORY_VOLUME_LABEL = 'BOEYE BDX Internal Memory' + STORAGE_CARD_VOLUME_LABEL = 'BOEYE BDX Storage Card' + + EBOOK_DIR_MAIN = 'Documents' + EBOOK_DIR_CARD_A = 'Documents' + SUPPORTS_SUB_DIRS = True From 731ff8eac4aef3bf27472f27f7d9d97c8d7d34cf Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 3 May 2011 09:39:41 -0600 Subject: [PATCH 2/6] ... --- recipes/f_secure.recipe | 1 - 1 file changed, 1 deletion(-) diff --git a/recipes/f_secure.recipe b/recipes/f_secure.recipe index f276a4961a..5a03f01ac8 100644 --- a/recipes/f_secure.recipe +++ b/recipes/f_secure.recipe @@ -12,7 +12,6 @@ class AdvancedUserRecipe1301860159(BasicNewsRecipe): max_articles_per_feed = 100 no_stylesheets = True use_embedded_content = False - language = 'en_EN' remove_javascript = True keep_only_tags = [dict(name='div', attrs={'class':'modSectionTd2'})] remove_tags = [dict(name='a'),dict(name='hr')] From 72120ed403490d4a9938b67f476639d92f49fd13 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 3 May 2011 10:15:46 -0600 Subject: [PATCH 3/6] Ensure the Preferences menu in OSX has an action to launch the preferences --- src/calibre/gui2/actions/preferences.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/calibre/gui2/actions/preferences.py b/src/calibre/gui2/actions/preferences.py index 24d20b23f9..b65967e994 100644 --- a/src/calibre/gui2/actions/preferences.py +++ b/src/calibre/gui2/actions/preferences.py @@ -10,7 +10,7 @@ from PyQt4.Qt import QIcon, QMenu, Qt from calibre.gui2.actions import InterfaceAction from calibre.gui2.preferences.main import Preferences from calibre.gui2 import error_dialog -from calibre.constants import DEBUG +from calibre.constants import DEBUG, isosx class PreferencesAction(InterfaceAction): @@ -19,7 +19,8 @@ class PreferencesAction(InterfaceAction): def genesis(self): pm = QMenu() - pm.addAction(QIcon(I('config.png')), _('Preferences'), self.do_config) + acname = _('Change calibre behavior') if isosx else _('Preferences') + pm.addAction(QIcon(I('config.png')), acname, self.do_config) pm.addAction(QIcon(I('wizard.png')), _('Run welcome wizard'), self.gui.run_wizard) if not DEBUG: From 62892d7161d414f18b62bab766f15ad5651ce47f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 3 May 2011 14:10:35 -0600 Subject: [PATCH 4/6] Add Get Books action to main toolbar by default --- src/calibre/gui2/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 60d2a0a7dd..1dfe1d8d14 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -34,7 +34,7 @@ if isosx: ) gprefs.defaults['action-layout-toolbar'] = ( 'Add Books', 'Edit Metadata', None, 'Convert Books', 'View', None, - 'Choose Library', 'Donate', None, 'Fetch News', 'Save To Disk', + 'Choose Library', 'Donate', None, 'Fetch News', 'Store', 'Save To Disk', 'Connect Share', None, 'Remove Books', ) gprefs.defaults['action-layout-toolbar-device'] = ( @@ -48,7 +48,7 @@ else: gprefs.defaults['action-layout-menubar-device'] = () gprefs.defaults['action-layout-toolbar'] = ( 'Add Books', 'Edit Metadata', None, 'Convert Books', 'View', None, - 'Choose Library', 'Donate', None, 'Fetch News', 'Save To Disk', + 'Choose Library', 'Donate', None, 'Fetch News', 'Store', 'Save To Disk', 'Connect Share', None, 'Remove Books', None, 'Help', 'Preferences', ) gprefs.defaults['action-layout-toolbar-device'] = ( From b9973c45404f0457684bbbfa1daf0f143bd492a8 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Tue, 3 May 2011 21:19:47 +0100 Subject: [PATCH 5/6] Add an 'all metadata' edit metadata variant --- src/calibre/gui2/metadata/single.py | 136 ++++++++++++++++++++++- src/calibre/gui2/preferences/behavior.py | 3 +- 2 files changed, 134 insertions(+), 5 deletions(-) diff --git a/src/calibre/gui2/metadata/single.py b/src/calibre/gui2/metadata/single.py index 63d4499966..e85a0adc13 100644 --- a/src/calibre/gui2/metadata/single.py +++ b/src/calibre/gui2/metadata/single.py @@ -13,7 +13,7 @@ from functools import partial from PyQt4.Qt import (Qt, QVBoxLayout, QHBoxLayout, QWidget, QPushButton, QGridLayout, pyqtSignal, QDialogButtonBox, QScrollArea, QFont, QTabWidget, QIcon, QToolButton, QSplitter, QGroupBox, QSpacerItem, - QSizePolicy, QPalette, QFrame, QSize, QKeySequence, QMenu) + QSizePolicy, QPalette, QFrame, QSize, QKeySequence, QMenu, QLabel) from calibre.ebooks.metadata import authors_to_string, string_to_authors from calibre.gui2 import ResizableDialog, error_dialog, gprefs, pixmap_to_data @@ -198,7 +198,7 @@ class MetadataSingleDialogBase(ResizableDialog): ans = self.custom_metadata_widgets for i in range(len(ans)-1): if before is not None and i == 0: - pass# Do something + pass if len(ans[i+1].widgets) == 2: sto(ans[i].widgets[-1], ans[i+1].widgets[1]) else: @@ -206,7 +206,7 @@ class MetadataSingleDialogBase(ResizableDialog): for c in range(2, len(ans[i].widgets), 2): sto(ans[i].widgets[c-1], ans[i].widgets[c+1]) if after is not None: - pass # Do something + pass # }}} def do_view_format(self, path, fmt): @@ -728,7 +728,135 @@ class MetadataSingleDialogAlt1(MetadataSingleDialogBase): # {{{ # }}} -editors = {'default': MetadataSingleDialog, 'alt1': MetadataSingleDialogAlt1} +class MetadataSingleDialogAlt2(MetadataSingleDialogBase): # {{{ + + cc_two_column = False + one_line_comments_toolbar = True + + def do_layout(self): + self.central_widget.clear() + self.labels = [] + sto = QWidget.setTabOrder + + self.central_widget.tabBar().setVisible(False) + tab0 = QWidget(self) + self.central_widget.addTab(tab0, _("&Metadata")) + l = QGridLayout() + tab0.setLayout(l) + + # Basic metadata in col 0 + tl = QGridLayout() + gb = QGroupBox(_('Basic metadata'), tab0) + l.addWidget(gb, 0, 0, 1, 1) + gb.setLayout(tl) + + self.button_box.addButton(self.fetch_metadata_button, + QDialogButtonBox.ActionRole) + self.config_metadata_button.setToolButtonStyle(Qt.ToolButtonTextOnly) + self.config_metadata_button.setText(_('Configure metadata downloading')) + self.button_box.addButton(self.config_metadata_button, + QDialogButtonBox.ActionRole) + sto(self.button_box, self.title) + + def create_row(row, widget, tab_to, button=None, icon=None, span=1): + ql = BuddyLabel(widget) + tl.addWidget(ql, row, 1, 1, 1) + tl.addWidget(widget, row, 2, 1, 1) + if button is not None: + tl.addWidget(button, row, 3, span, 1) + if icon is not None: + button.setIcon(QIcon(I(icon))) + if tab_to is not None: + if button is not None: + sto(widget, button) + sto(button, tab_to) + else: + sto(widget, tab_to) + + tl.addWidget(self.swap_title_author_button, 0, 0, 2, 1) + + create_row(0, self.title, self.title_sort, + button=self.deduce_title_sort_button, span=2, + icon='auto_author_sort.png') + create_row(1, self.title_sort, self.authors) + create_row(2, self.authors, self.author_sort, + button=self.deduce_author_sort_button, + span=2, icon='auto_author_sort.png') + create_row(3, self.author_sort, self.series) + create_row(4, self.series, self.series_index, + button=self.remove_unused_series_button, icon='trash.png') + create_row(5, self.series_index, self.tags) + create_row(6, self.tags, self.rating, button=self.tags_editor_button) + create_row(7, self.rating, self.pubdate) + create_row(8, self.pubdate, self.publisher, + button=self.pubdate.clear_button, icon='trash.png') + create_row(9, self.publisher, self.timestamp) + create_row(10, self.timestamp, self.identifiers, + button=self.timestamp.clear_button, icon='trash.png') + create_row(11, self.identifiers, self.comments, + button=self.clear_identifiers_button, icon='trash.png') + tl.addItem(QSpacerItem(1, 1, QSizePolicy.Fixed, QSizePolicy.Expanding), + 12, 1, 1 ,1) + + # Custom metadata in col 1 + w = getattr(self, 'custom_metadata_widgets_parent', None) + if w is not None: + gb = QGroupBox(_('Custom metadata'), tab0) + gbl = QVBoxLayout() + gb.setLayout(gbl) + sr = QScrollArea(gb) + sr.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + sr.setWidgetResizable(True) + sr.setBackgroundRole(QPalette.Base) + sr.setFrameStyle(QFrame.NoFrame) + sr.setWidget(w) + gbl.addWidget(sr) + l.addWidget(gb, 0, 1, 1, 1) + sp = QSizePolicy() + sp.setVerticalStretch(10) + sp.setHorizontalPolicy(QSizePolicy.Fixed) + sp.setVerticalPolicy(QSizePolicy.Expanding) + gb.setSizePolicy(sp) + self.set_custom_metadata_tab_order() + + # comments span col 0 & 1 + w = QGroupBox(_('Comments'), tab0) + sp = QSizePolicy() + sp.setVerticalStretch(10) + sp.setHorizontalPolicy(QSizePolicy.Expanding) + sp.setVerticalPolicy(QSizePolicy.Expanding) + w.setSizePolicy(sp) + lb = QHBoxLayout() + w.setLayout(lb) + lb.addWidget(self.comments) + l.addWidget(w, 1, 0, 1, 2) + + # Cover & formats in col 3 + gb = QGroupBox(_('Cover'), tab0) + lb = QGridLayout() + gb.setLayout(lb) + lb.addWidget(self.cover, 0, 0, 1, 3, alignment=Qt.AlignCenter) + sto(self.clear_identifiers_button, self.cover.buttons[0]) + for i, b in enumerate(self.cover.buttons[:3]): + lb.addWidget(b, 1, i, 1, 1) + sto(b, self.cover.buttons[i+1]) + hl = QHBoxLayout() + for b in self.cover.buttons[3:]: + hl.addWidget(b) + sto(self.cover.buttons[-2], self.cover.buttons[-1]) + lb.addLayout(hl, 2, 0, 1, 3) + l.addWidget(gb, 0, 2, 1, 1) + l.addWidget(self.formats_manager, 1, 2, 1, 1) + sto(self.cover.buttons[-1], self.formats_manager) + + self.formats_manager.formats.setMaximumWidth(10000) + self.formats_manager.formats.setIconSize(QSize(32, 32)) + +# }}} + + +editors = {'default': MetadataSingleDialog, 'alt1': MetadataSingleDialogAlt1, + 'alt2': MetadataSingleDialogAlt2} def edit_metadata(db, row_list, current_row, parent=None, view_slot=None, set_current_callback=None): diff --git a/src/calibre/gui2/preferences/behavior.py b/src/calibre/gui2/preferences/behavior.py index e062ae2662..1247c54ec9 100644 --- a/src/calibre/gui2/preferences/behavior.py +++ b/src/calibre/gui2/preferences/behavior.py @@ -61,7 +61,8 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): r('bools_are_tristate', db.prefs, restart_required=True) r = self.register - choices = [(_('Default'), 'default'), (_('Compact Metadata'), 'alt1')] + choices = [(_('Default'), 'default'), (_('Compact Metadata'), 'alt1'), + (_('All on 1 tab'), 'alt2')] r('edit_metadata_single_layout', gprefs, choices=choices) def initialize(self): From 3ac69128e7899d8c24bb5c1cfbac1a91c9c26757 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 3 May 2011 16:04:59 -0600 Subject: [PATCH 6/6] Update FrazPC --- recipes/frazpc.recipe | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/recipes/frazpc.recipe b/recipes/frazpc.recipe index 56e45076ac..2d0d54d10c 100644 --- a/recipes/frazpc.recipe +++ b/recipes/frazpc.recipe @@ -1,7 +1,7 @@ #!/usr/bin/env python __license__ = 'GPL v3' -__copyright__ = u'2010, Tomasz Dlugosz ' +__copyright__ = u'2010-2011, Tomasz Dlugosz ' ''' frazpc.pl ''' @@ -19,17 +19,20 @@ class FrazPC(BasicNewsRecipe): use_embedded_content = False no_stylesheets = True - feeds = [(u'Aktualno\u015bci', u'http://www.frazpc.pl/feed'), (u'Recenzje', u'http://www.frazpc.pl/kat/recenzje-2/feed') ] - - keep_only_tags = [dict(name='div', attrs={'id':'FRAZ_CONTENT'})] - - remove_tags = [dict(name='p', attrs={'class':'gray tagsP fs11'})] - - preprocess_regexps = [ - (re.compile(i[0], re.IGNORECASE | re.DOTALL), i[1]) for i in - [(r'
(Skomentuj|Komentarz(e)?\([0-9]*\))  \|', lambda match: '')] + feeds = [ + (u'Aktualno\u015bci', u'http://www.frazpc.pl/feed/aktualnosci'), + (u'Artyku\u0142y', u'http://www.frazpc.pl/feed/artykuly') ] + keep_only_tags = [dict(name='div', attrs={'class':'article'})] + + remove_tags = [ + dict(name='div', attrs={'class':'title-wrapper'}), + dict(name='p', attrs={'class':'tags'}), + dict(name='p', attrs={'class':'article-links'}), + dict(name='div', attrs={'class':'comments_box'}) + ] + + preprocess_regexps = [(re.compile(r'\| Komentarze \([0-9]*\)'), lambda match: '')] + remove_attributes = [ 'width', 'height' ]