diff --git a/resources/images/news/popscience.png b/resources/images/news/popscience.png new file mode 100644 index 0000000000..ff33483b10 Binary files /dev/null and b/resources/images/news/popscience.png differ diff --git a/resources/images/tweak_epub.png b/resources/images/tweak_epub.png new file mode 100644 index 0000000000..b9fd9e5f1e Binary files /dev/null and b/resources/images/tweak_epub.png differ diff --git a/resources/recipes/popscience.recipe b/resources/recipes/popscience.recipe new file mode 100644 index 0000000000..a1ea91a6ae --- /dev/null +++ b/resources/recipes/popscience.recipe @@ -0,0 +1,59 @@ +import re +from calibre.web.feeds.news import BasicNewsRecipe + +class AdvancedUserRecipe1282101454(BasicNewsRecipe): + title = 'Popular Science' + language = 'en' + __author__ = 'TonytheBookworm' + description = 'Popular Science' + publisher = 'Popular Science' + category = 'gadgets,science' + oldest_article = 7 # change this if you want more current articles. I like to go a week in + max_articles_per_feed = 100 + no_stylesheets = True + remove_javascript = True + + masthead_url = 'http://www.raytheon.com/newsroom/rtnwcm/groups/Public/documents/masthead/rtn08_popscidec_masthead.jpg' + + remove_tags = [dict(name='div', attrs={'id':['toolbar','main_supplements']}), + dict(name='span', attrs={'class':['comments']}), + dict(name='div', attrs={'class':['relatedinfo related-right','node_navigation','content2']}), + dict(name='ul', attrs={'class':['item-list clear-block']})] + feeds = [ + + ('Gadgets', 'http://www.popsci.com/full-feed/gadgets'), + ('Cars', 'http://www.popsci.com/full-feed/cars'), + ('Science', 'http://www.popsci.com/full-feed/science'), + ('Technology', 'http://www.popsci.com/full-feed/technology'), + ('DIY', 'http://www.popsci.com/full-feed/diy'), + + ] + + + #The following will get read of the Gallery: links when found + + def preprocess_html(self, soup) : + print 'SOUP IS: ', soup + weblinks = soup.findAll(['head','h2']) + if weblinks is not None: + for link in weblinks: + if re.search('(Gallery)(:)',str(link)): + + link.parent.extract() + return soup + #----------------------------------------------------------------- + + + + + + + + + + + + + + + diff --git a/src/calibre/ebooks/metadata/epub.py b/src/calibre/ebooks/metadata/epub.py index 041a1ee603..df9a394258 100644 --- a/src/calibre/ebooks/metadata/epub.py +++ b/src/calibre/ebooks/metadata/epub.py @@ -176,6 +176,7 @@ def get_metadata(stream, extract_cover=True): except: import traceback traceback.print_exc() + mi.timestamp = None return mi def get_quick_metadata(stream): diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index e58dce5559..c284900734 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -39,7 +39,7 @@ gprefs.defaults['action-layout-context-menu'] = ( 'Edit Metadata', 'Send To Device', 'Save To Disk', 'Connect Share', 'Copy To Library', None, 'Convert Books', 'View', 'Open Folder', 'Show Book Details', - 'Similar Books', None, 'Remove Books', + 'Similar Books', 'Tweak ePub', None, 'Remove Books', ) gprefs.defaults['action-layout-context-menu-device'] = ( diff --git a/src/calibre/gui2/actions/tweak_epub.py b/src/calibre/gui2/actions/tweak_epub.py index 020e9c0382..96331e2887 100755 --- a/src/calibre/gui2/actions/tweak_epub.py +++ b/src/calibre/gui2/actions/tweak_epub.py @@ -5,30 +5,61 @@ __license__ = 'GPL v3' __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' +from calibre.constants import iswindows, isosx +from calibre.gui2 import error_dialog from calibre.gui2.actions import InterfaceAction +from calibre.gui2.dialogs.tweak_epub import TweakEpub class TweakEpubAction(InterfaceAction): name = 'Tweak ePub' - action_spec = (_('Edit ePub in situ'), 'document_open.png', None, None) - #dont_add_to = frozenset(['toolbar-device', 'context-menu-device']) + action_spec = (_('Tweak ePub'), 'tweak_epub.png', 'Edit ePub in situ', + _('T')) + dont_add_to = frozenset(['toolbar-device', 'context-menu-device']) action_type = 'current' def genesis(self): - self.qaction.triggered.connect(self.edit_epub_in_situ) - print "gui2.actions.tweak_epub:TweakEpubAction.genesis()" + self.qaction.triggered.connect(self._edit_epub_in_situ) - def initialization_complete(self): - print "gui2.actions.tweak_epub:TweakEpubAction.initialization_complete()" + def _edit_epub_in_situ(self, *args): - def library_changed(self, db): - print "gui2.actions.tweak_epub:TweakEpubAction.library_changed()" + # Assure exactly one row selected + rows = self.gui.library_view.selectionModel().selectedRows() + if not rows or len(rows) == 0: + d = error_dialog(self.gui, _('Cannot tweak ePub'), _('No book selected')) + d.exec_() + return + if len(rows) > 1: + d = error_dialog(self.gui, _('Cannot tweak ePub'), _('Multiple books selected')) + d.exec_() + return - def location_selected(self, loc): - print "gui2.actions.tweak_epub:TweakEpubAction.location_selected()" + # Confirm 'EPUB' in formats + row = rows[0].row() + formats = self.gui.library_view.model().db.formats(row).upper().split(',') + if not 'EPUB' in formats: + d = error_dialog(self.gui, _('Cannot tweak ePub'), _('No EPUB available')) + d.exec_() + return - def shutting_down(self): - print "gui2.actions.tweak_epub:TweakEpubAction.shutting_down()" + path_to_epub = self.gui.library_view.model().db.format_abspath(row, 'EPUB') + id = self._get_selected_id() + + # Launch a modal dialog waiting for user to complete or cancel + dlg = TweakEpub(self.gui, path_to_epub) + if dlg.exec_() == dlg.Accepted: + self._update_db(id, dlg._output) + dlg.cleanup() + + def _get_selected_id(self): + rows = self.gui.library_view.selectionModel().selectedRows() + return map(self.gui.library_view.model().id, rows)[0] + + def _update_db(self, id, rebuilt): + ''' + Update the calibre db with the tweaked epub + ''' + print "gui2.actions.tweak_epub:TweakEpubAction._update_db()" + print " updating id %d from %s" % (id, rebuilt) + self.gui.library_view.model().db.add_format_with_hooks(id, 'EPUB', rebuilt, index_is_id=True) - def edit_epub_in_situ(self, *args): - print "gui2.actions.tweak_epub:TweakEpubAction.edit_epub_in_situ()" diff --git a/src/calibre/gui2/dialogs/tweak_epub.py b/src/calibre/gui2/dialogs/tweak_epub.py new file mode 100755 index 0000000000..cc5b526291 --- /dev/null +++ b/src/calibre/gui2/dialogs/tweak_epub.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai +from __future__ import with_statement + +__license__ = 'GPL v3' +__copyright__ = '2010, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + +import os, shutil, subprocess, sys +from contextlib import closing +from zipfile import ZipFile, ZIP_DEFLATED, ZIP_STORED + +from PyQt4 import QtGui +from PyQt4.Qt import QDialog, SIGNAL + +from calibre import prints +from calibre.constants import iswindows, isosx, DEBUG +from calibre.gui2.dialogs.tweak_epub_ui import Ui_Dialog +from calibre.libunzip import extract as zipextract +from calibre.ptempfile import PersistentTemporaryDirectory + +class TweakEpub(QDialog, Ui_Dialog): + ''' + Display controls for tweaking ePubs + + To do: + - need way to kill file browser proc in cleanup() + - Windows file browser launch + - linux file browser launch + ''' + + def __init__(self, parent, epub): + QDialog.__init__(self, parent) + + self._epub = epub + self._exploded = None + self._file_browser_proc = None + self._output = None + + # Run the dialog setup generated from tweak_epub.ui + self.setupUi(self) + + self.connect(self.cancel_button, + SIGNAL("clicked()"), + self.cancel) + self.connect(self.explode_button, + SIGNAL("clicked()"), + self.explode) + self.connect(self.rebuild_button, + SIGNAL("clicked()"), + self.rebuild) + + # Position update dialog overlaying top left of app window + parent_loc = parent.pos() + self.move(parent_loc.x(),parent_loc.y()) + + def cancel(self): + if DEBUG: + prints("gui2.dialogs.tweak_epub:TweakEpub.cancel()") + return QDialog.reject(self) + + def cleanup(self): + ''' + Kill the file browser + ''' + if DEBUG: + prints("gui2.dialogs.tweak_epub:TweakEpub.cleanup()") + # Kill file browser proc + if self._file_browser_proc: + if DEBUG: + prints(" killing file browser proc") + #self._file_browser_proc.terminate() + #self._file_browser_proc.kill() + #self._file_browser_send_signal() + #self._file_browser_proc = None + + # Delete directory containing exploded ePub + if self._exploded is not None: + if DEBUG: + prints(" removing exploded dir\n %s" % self._exploded) + shutil.rmtree(self._exploded, ignore_errors=True) + + + def display_exploded(self): + ''' + Generic subprocess launch of native file browser + User can use right-click to 'Open with ...' + ''' + if DEBUG: + prints("gui2.dialogs.tweak_epub:TweakEpub.display_exploded()") + if isosx: + cmd = 'open %s' % self._exploded + elif iswindows: + cmd = 'start explorer.exe /e,/root,%s' % self._exploded + else: + cmd = '' + + # *** Kovid - need a way of launching this process than can be killed in cleanup() *** + self._file_browser_proc = subprocess.Popen(cmd, shell=True) + + def explode(self): + if DEBUG: + prints("gui2.dialogs.tweak_epub:TweakEpub.explode()") + if self._exploded is None: + if DEBUG: + prints(" exploding %s" % self._epub) + self._exploded = PersistentTemporaryDirectory("_exploded", prefix='') + zipextract(self._epub, self._exploded) + self.display_exploded() + self.rebuild_button.setEnabled(True) + + def rebuild(self): + if DEBUG: + prints("gui2.dialogs.tweak_epub:TweakEpub.rebuild()") + self._output = os.path.join(self._exploded, 'rebuilt.epub') + with closing(ZipFile(self._output, 'w', compression=ZIP_DEFLATED)) as zf: + # Write mimetype + zf.write(os.path.join(self._exploded,'mimetype'), 'mimetype', compress_type=ZIP_STORED) + # Write everything else + exclude_files = ['.DS_Store','mimetype','iTunesMetadata.plist'] + for root, dirs, files in os.walk(self._exploded): + for fn in files: + if fn in exclude_files: + continue + absfn = os.path.join(root, fn) + zfn = absfn[len(self._exploded) + len(os.sep):] + zf.write(absfn, zfn) + return QDialog.accept(self) + diff --git a/src/calibre/gui2/dialogs/tweak_epub.ui b/src/calibre/gui2/dialogs/tweak_epub.ui new file mode 100644 index 0000000000..36c9a7bc22 --- /dev/null +++ b/src/calibre/gui2/dialogs/tweak_epub.ui @@ -0,0 +1,86 @@ + + + Dialog + + + Qt::NonModal + + + + 0 + 0 + 161 + 132 + + + + Tweak ePub + + + false + + + false + + + + + 10 + 10 + 141 + 110 + + + + + + + Display contents of exploded ePub + + + Explode ePub + + + + + + + false + + + Rebuild ePub from exploded contents + + + Rebuild ePub + + + + + + + Discard changes + + + Cancel + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + +