diff --git a/resources/recipes/pc_mag.recipe b/resources/recipes/pc_mag.recipe index 7d6049ec2b..227d777034 100644 --- a/resources/recipes/pc_mag.recipe +++ b/resources/recipes/pc_mag.recipe @@ -9,8 +9,9 @@ __description__ = 'PCMag (www.pcmag.com) delivers authoritative, labs-based comp ''' http://www.pcmag.com/ ''' - +import re from calibre.web.feeds.news import BasicNewsRecipe +from calibre.ebooks.BeautifulSoup import Comment class pcMag(BasicNewsRecipe): __author__ = 'Lorenzo Vigentini' @@ -33,9 +34,6 @@ class pcMag(BasicNewsRecipe): remove_javascript = True no_stylesheets = True - keep_only_tags = [ - dict(name='div', attrs={'id':'articleContent'}) - ] feeds = [ (u'Tech Commentary from the Editors of PC Magazine', u'http://rssnewsapps.ziffdavis.com/PCMAG_commentary.xml'), @@ -49,8 +47,13 @@ class pcMag(BasicNewsRecipe): (u'Technology News from Ziff Davis', u'http://rssnewsapps.ziffdavis.com/pcmagbreakingnews.xml') ] + keep_only_tags = [dict(attrs={'class':'content-page'})] remove_tags = [ - dict(name='div', attrs={'id':['microAd','intellitxt','articleDeckTalkback','inlineDigg','underArticleLinks','w_talkback']}), - dict(name='span', attrs={'id':['highlights_content','yahooBuzzBadge-48558872521263350499378']}) - ] + dict(attrs={'class':['control-side','comment','highlights_content','btn-holder','subscribe-panel', + 'grey-box comments-box']}), + dict(id=['inlineDigg']), + dict(text=lambda text:isinstance(text, Comment)), + dict(name='img', width='1'), + ] + preprocess_regexps = [(re.compile(r" + + + + Cover + + + +
+ cover +
+ + + ''' TITLEPAGE_COVER = '''\ @@ -301,7 +329,9 @@ class EPUBOutput(OutputFormatPlugin): else: href = self.default_cover() if href is not None: - tp = self.TITLEPAGE_COVER%unquote(href) + templ = self.NONSVG_TITLEPAGE_COVER if self.opts.no_svg_cover \ + else self.TITLEPAGE_COVER + tp = templ%unquote(href) id, href = m.generate('titlepage', 'titlepage.xhtml') item = m.add(id, href, guess_type('t.xhtml')[0], data=etree.fromstring(tp)) diff --git a/src/calibre/ebooks/metadata/archive.py b/src/calibre/ebooks/metadata/archive.py index 0af41c274f..45d549b6ea 100644 --- a/src/calibre/ebooks/metadata/archive.py +++ b/src/calibre/ebooks/metadata/archive.py @@ -64,3 +64,45 @@ class ArchiveExtract(FileTypePlugin): of.write(zf.read(fname)) return of.name +def get_comic_book_info(d, mi): + series = d.get('series', '') + if series.strip(): + mi.series = series + if d.get('volume', -1) > -1: + mi.series_index = float(d['volume']) + if d.get('rating', -1) > -1: + mi.rating = d['rating'] + for x in ('title', 'publisher'): + y = d.get(x, '').strip() + if y: + setattr(mi, x, y) + tags = d.get('tags', []) + if tags: + mi.tags = tags + authors = [] + for credit in d.get('credits', []): + if credit.get('role', '') in ('Writer', 'Artist', 'Cartoonist', + 'Creator'): + x = credit.get('person', '') + if x: + x = ' '.join((reversed(x.split(', ')))) + authors.append(x) + if authors: + mi.authors = authors + + + +def get_cbz_metadata(stream): + from calibre.utils.zipfile import ZipFile + from calibre.ebooks.metadata import MetaInformation + import json + + zf = ZipFile(stream) + mi = MetaInformation(None, None) + if zf.comment: + m = json.loads(zf.comment) + if hasattr(m, 'keys'): + for cat in m.keys(): + if cat.startswith('ComicBookInfo'): + get_comic_book_info(m[cat], mi) + return mi diff --git a/src/calibre/ebooks/oeb/stylizer.py b/src/calibre/ebooks/oeb/stylizer.py index c9f228a091..0557a1f74d 100644 --- a/src/calibre/ebooks/oeb/stylizer.py +++ b/src/calibre/ebooks/oeb/stylizer.py @@ -96,6 +96,8 @@ class CSSSelector(etree.XPath): path = css_to_xpath(css) except UnicodeEncodeError: # Bug in css_to_xpath path = '/' + except NotImplementedError: # Probably a subselect like :hover + path = '/' path = self.LOCAL_NAME_RE.sub(r"local-name() = '", path) etree.XPath.__init__(self, path, namespaces=namespaces) self.css = css @@ -534,6 +536,8 @@ class Style(object): result = base else: result = self._unit_convert(width, base=base) + if isinstance(result, (unicode, str, bytes)): + result = self._profile.width self._width = result return self._width @@ -555,6 +559,8 @@ class Style(object): result = base else: result = self._unit_convert(height, base=base) + if isinstance(result, (unicode, str, bytes)): + result = self._profile.height self._height = result return self._height diff --git a/src/calibre/gui2/convert/epub_output.py b/src/calibre/gui2/convert/epub_output.py index 2afa662fb4..57027d9315 100644 --- a/src/calibre/gui2/convert/epub_output.py +++ b/src/calibre/gui2/convert/epub_output.py @@ -17,7 +17,8 @@ class PluginWidget(Widget, Ui_Form): def __init__(self, parent, get_option, get_help, db=None, book_id=None): Widget.__init__(self, parent, 'epub_output', - ['dont_split_on_page_breaks', 'flow_size', 'no_default_epub_cover'] + ['dont_split_on_page_breaks', 'flow_size', + 'no_default_epub_cover', 'no_svg_cover'] ) self.db, self.book_id = db, book_id self.initialize_options(get_option, get_help, db, book_id) diff --git a/src/calibre/gui2/convert/epub_output.ui b/src/calibre/gui2/convert/epub_output.ui index f282214996..7f92ec3087 100644 --- a/src/calibre/gui2/convert/epub_output.ui +++ b/src/calibre/gui2/convert/epub_output.ui @@ -21,7 +21,7 @@ - + Split files &larger than: @@ -31,7 +31,7 @@ - + KB @@ -47,7 +47,7 @@ - + Qt::Vertical @@ -67,6 +67,13 @@ + + + + No &SVG cover + + + diff --git a/src/calibre/gui2/convert/regex_builder.py b/src/calibre/gui2/convert/regex_builder.py index 83e548f81d..1ecb595e73 100644 --- a/src/calibre/gui2/convert/regex_builder.py +++ b/src/calibre/gui2/convert/regex_builder.py @@ -8,7 +8,7 @@ import re from PyQt4.QtCore import SIGNAL, Qt from PyQt4.QtGui import QDialog, QWidget, QDialogButtonBox, QFileDialog, \ - QBrush, QSyntaxHighlighter, QTextCharFormat + QBrush, QTextCursor, QTextEdit from calibre.gui2.convert.regex_builder_ui import Ui_RegexBuilder from calibre.gui2.convert.xexp_edit_ui import Ui_Form as Ui_Edit @@ -17,31 +17,6 @@ from calibre.gui2 import error_dialog from calibre.ebooks.oeb.iterator import EbookIterator from calibre.gui2.dialogs.choose_format import ChooseFormatDialog -class RegexHighlighter(QSyntaxHighlighter): - - def __init__(self, *args): - QSyntaxHighlighter.__init__(self, *args) - - self.regex = u'' - - def update_regex(self, regex): - self.regex = regex - self.rehighlight() - - def highlightBlock(self, text): - valid_regex = True - text = qstring_to_unicode(text) - format = QTextCharFormat() - format.setBackground(QBrush(Qt.yellow)) - - if self.regex: - try: - for mo in re.finditer(self.regex, text): - self.setFormat(mo.start(), mo.end() - mo.start(), format) - except: - valid_regex = False - self.emit(SIGNAL('regex_valid(PyQt_PyObject)'), valid_regex) - class RegexBuilder(QDialog, Ui_RegexBuilder): def __init__(self, db, book_id, regex, *args): @@ -49,9 +24,7 @@ class RegexBuilder(QDialog, Ui_RegexBuilder): self.setupUi(self) self.regex.setText(regex) - self.regex_valid(True) - self.highlighter = RegexHighlighter(self.preview.document()) - self.highlighter.update_regex(regex) + self.regex_valid() if not db or not book_id: self.button_box.addButton(QDialogButtonBox.Open) @@ -62,7 +35,7 @@ class RegexBuilder(QDialog, Ui_RegexBuilder): self.connect(self.regex, SIGNAL('textChanged(QString)'), self.regex_valid) self.connect(self.test, SIGNAL('clicked()'), self.do_test) - def regex_valid(self, valid): + def regex_valid(self): regex = qstring_to_unicode(self.regex.text()) if regex: try: @@ -70,11 +43,29 @@ class RegexBuilder(QDialog, Ui_RegexBuilder): self.regex.setStyleSheet('QLineEdit { color: black; background-color: rgba(0,255,0,20%); }') except: self.regex.setStyleSheet('QLineEdit { color: black; background-color: rgb(255,0,0,20%); }') + return False else: self.regex.setStyleSheet('QLineEdit { color: black; background-color: white; }') + return True def do_test(self): - self.highlighter.update_regex(qstring_to_unicode(self.regex.text())) + selections = [] + if self.regex_valid(): + text = qstring_to_unicode(self.preview.toPlainText()) + regex = qstring_to_unicode(self.regex.text()) + + try: + for match in re.finditer(regex, text): + cursor = QTextCursor(self.preview.document()) + cursor.setPosition(match.start(), QTextCursor.MoveAnchor) + cursor.setPosition(match.end(), QTextCursor.KeepAnchor) + sel = QTextEdit.ExtraSelection() + sel.cursor = cursor + sel.format.setBackground(QBrush(Qt.yellow)) + selections.append(sel) + except: + pass + self.preview.setExtraSelections(selections) def select_format(self, db, book_id): format = None diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index e6cdf2bda9..c1e9da8b74 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -350,7 +350,8 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): self.view_menu = QMenu() self.view_menu.addAction(_('View')) - self.view_menu.addAction(_('View specific format')) + ac = self.view_menu.addAction(_('View specific format')) + ac.setShortcut(Qt.AltModifier+Qt.Key_V) self.action_view.setMenu(self.view_menu) self.delete_menu = QMenu() diff --git a/src/calibre/gui2/viewer/documentview.py b/src/calibre/gui2/viewer/documentview.py index 7ca9b1bd95..a1ecf14dfd 100644 --- a/src/calibre/gui2/viewer/documentview.py +++ b/src/calibre/gui2/viewer/documentview.py @@ -394,13 +394,14 @@ class Document(QWebPage): return self.mainFrame().contentsSize().width() # offsetWidth gives inaccurate results def set_bottom_padding(self, amount): - padding = '%dpx'%amount - try: - old_padding = unicode(self.javascript('$("body").css("padding-bottom")').toString()) - except: - old_padding = '' + body = self.mainFrame().documentElement().findFirst('body') + if body.isNull(): + return + old_padding = unicode(body.styleProperty('padding-bottom', + body.ComputedStyle)).strip() + padding = u'%dpx'%amount if old_padding != padding: - self.javascript('$("body").css("padding-bottom", "%s")' % padding) + body.setStyleProperty('padding-bottom', padding + ' !important') class EntityDeclarationProcessor(object): @@ -423,7 +424,7 @@ class DocumentView(QWebView): QWebView.__init__(self, *args) self.debug_javascript = False self.shortcuts = Shortcuts(SHORTCUTS, 'shortcuts/viewer') - self.self_closing_pat = re.compile(r'<([a-z]+)\s+([^>]+)/>', + self.self_closing_pat = re.compile(r'<([a-z1-6]+)\s+([^>]+)/>', re.IGNORECASE) self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)) self._size_hint = QSize(510, 680)