From d7a2bbb2cf3e1c0b603fa7433f808e240c772e9a Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 10 Jun 2012 20:11:11 +0530 Subject: [PATCH 1/8] NZZ Webpaper by Bernd Leinfelder --- recipes/nzz_webpaper.recipe | 90 +++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 recipes/nzz_webpaper.recipe diff --git a/recipes/nzz_webpaper.recipe b/recipes/nzz_webpaper.recipe new file mode 100644 index 0000000000..202cfeadab --- /dev/null +++ b/recipes/nzz_webpaper.recipe @@ -0,0 +1,90 @@ +from calibre import strftime + +__license__ = 'GPL v3' +__copyright__ = '2012, Bernd Leinfelder ' + +''' +webpaper.nzz.ch +''' + +from calibre.web.feeds.recipes import BasicNewsRecipe + +class Nzz(BasicNewsRecipe): + title = 'NZZ Webpaper' + __author__ = 'Bernd Leinfelder' + description = 'Neue Zuercher Zeitung Webpaper - Erfordert NZZ Digital Abonnement' + timefmt = ' [%a, %d %b, %Y]' + publisher = 'NZZ AG' + needs_subscription = True + category = 'news, politics, nachrichten, Switzerland' + oldest_article = 2 + max_articles_per_feed = 100 + no_stylesheets = True + encoding = 'utf-8' + use_embedded_content = False + language = 'de' + extra_css = 'h1 {font: sans-serif large;}\n.byline {font:monospace;}' + + conversion_options = { + 'comments' : description + ,'tags' : category + ,'language' : language + ,'publisher' : publisher + } + + remove_tags = [dict(name='footer')] + + remove_tags_before = dict(name='article') + remove_tags_after= dict(name='footer') + + def parse_index(self): + baseref = 'https://webpaper.nzz.ch' + soup = self.index_to_soup(baseref) + + articles = {} + key = None + ans = [] + + issuelist = soup.find(id="issueSelectorList") + + feeds = issuelist.findAll("a") + for f in feeds: + section = f.string + sectionref = baseref + f['href'] + + # print "section is "+section +" and ref is "+sectionref + ans.append(section) + + articlesoup = self.index_to_soup(sectionref) + + articlesoup = articlesoup.findAll('article','article') + for a in articlesoup: + artlink = a.find('a') + + arthref = baseref + artlink['href'] + arthead = a.find('h2') + artcaption = arthead.string + + pubdate = strftime('%a, %d %b') + + if not artcaption is None: + # print " found article named "+artcaption+" at "+arthref + if not articles.has_key(section): + articles[section] = [] + articles[section].append( + dict(title=artcaption, url=arthref, date=pubdate, description='', content='')) + + ans = [(key, articles[key]) for key in ans if articles.has_key(key)] + return ans + + def get_browser(self): + br = BasicNewsRecipe.get_browser() + if self.username is not None and self.password is not None: + br.open('https://webpaper.nzz.ch/login') + br.select_form(nr=0) + br['_username'] = self.username + br['_password'] = self.password + br.submit() + return br + + From b37a8caeb7eca758c4e6b126ee0d912db243472d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 11 Jun 2012 06:44:12 +0530 Subject: [PATCH 2/8] QtCurve disable reading of config files --- src/qtcurve/common/config_file.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/qtcurve/common/config_file.c b/src/qtcurve/common/config_file.c index 639f696747..cbff7efa90 100644 --- a/src/qtcurve/common/config_file.c +++ b/src/qtcurve/common/config_file.c @@ -976,6 +976,7 @@ class QtCConfig QtCConfig::QtCConfig(const QString &filename) { + if (filename.isEmpty()) return; // Changed by Kovid to ensure config files are never read QFile f(filename); #if QT_VERSION >= 0x040000 @@ -1748,17 +1749,13 @@ bool qtcReadConfig(const char *file, Options *opts, Options *defOpts) #endif else { +// Changed by Kovid to ensure config files are never read #ifdef __cplusplus - QtCConfig cfg(file); - - if(cfg.ok()) - { + QtCConfig cfg(QString("")); #else - GHashTable *cfg=loadConfig(file); - - if(cfg) - { + GHashTable *cfg=NULL; #endif + if (0) { int i; opts->version=readVersionEntry(cfg, VERSION_KEY); From d96a4cf70029d8b69015c459eee417a9730f3f58 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 11 Jun 2012 07:02:55 +0530 Subject: [PATCH 3/8] Calibre style: Platform specific dialog button orders --- src/qtcurve/style/qtcurve.cpp | 11 ++++++++++- src/qtcurve/style/qtcurve.h | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/qtcurve/style/qtcurve.cpp b/src/qtcurve/style/qtcurve.cpp index 483d220520..d5afb529e8 100644 --- a/src/qtcurve/style/qtcurve.cpp +++ b/src/qtcurve/style/qtcurve.cpp @@ -963,6 +963,7 @@ Style::Style() itsAnimateStep(0), itsTitlebarHeight(0), calibre_icon_map(QHash()), + is_kde_session(False), itsPos(-1, -1), itsHoverWidget(0L), #ifdef Q_WS_X11 @@ -977,6 +978,7 @@ Style::Style() , itsName(name) #endif { + is_kde_session = (getenv("KDE_FULL_SESSION") != NULL); const char *env=getenv(QTCURVE_PREVIEW_CONFIG); if(env && 0==strcmp(env, QTCURVE_PREVIEW_CONFIG)) { @@ -3602,7 +3604,14 @@ int Style::styleHint(StyleHint hint, const QStyleOption *option, const QWidget * #endif return 0; case SH_DialogButtonLayout: - return opts.gtkButtonOrder ? QDialogButtonBox::GnomeLayout : QDialogButtonBox::KdeLayout; +// Changed by Kovid to use platform specific button orders. +#ifdef _WIN32 + return QDialogButtonBox::WinLayout; +#elif defined(__APPLE__) + return QDialogButtonBox::MacLayout; +#else + return is_kde_session ? QDialogButtonBox::KdeLayout : QDialogButtonBox::GnomeLayout; +#endif case SH_MessageBox_TextInteractionFlags: return Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse; case SH_LineEdit_PasswordCharacter: diff --git a/src/qtcurve/style/qtcurve.h b/src/qtcurve/style/qtcurve.h index 7a472afffe..43cd882c2f 100644 --- a/src/qtcurve/style/qtcurve.h +++ b/src/qtcurve/style/qtcurve.h @@ -355,6 +355,7 @@ class Style : public QCommonStyle mutable QList itsMdiButtons[2]; // 0=left, 1=right mutable int itsTitlebarHeight; QHash calibre_icon_map; + bool is_kde_session; // Required for Q3Header hover... QPoint itsPos; From 7f321ef0d9e3f1cfc8964ad3cb5cd0faadaab27f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 11 Jun 2012 10:43:39 +0530 Subject: [PATCH 4/8] Calibre style: Fix various compiler warnings on non X11 platforms --- src/qtcurve/style/blurhelper.cpp | 5 +++++ src/qtcurve/style/qtcurve.cpp | 5 ++++- src/qtcurve/style/utils.cpp | 1 + src/qtcurve/style/windowmanager.cpp | 2 ++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/qtcurve/style/blurhelper.cpp b/src/qtcurve/style/blurhelper.cpp index b658d9ab6f..1bfdfc2f82 100644 --- a/src/qtcurve/style/blurhelper.cpp +++ b/src/qtcurve/style/blurhelper.cpp @@ -209,6 +209,9 @@ namespace QtCurve // force update if( widget->isVisible() ) { widget->update(); } + + #else + Q_UNUSED(widget); #endif @@ -220,6 +223,8 @@ namespace QtCurve { #ifdef Q_WS_X11 XChangeProperty( QX11Info::display(), widget->winId(), _atom, XA_CARDINAL, 32, PropModeReplace, 0, 0 ); + #else + Q_UNUSED(widget); #endif } diff --git a/src/qtcurve/style/qtcurve.cpp b/src/qtcurve/style/qtcurve.cpp index d5afb529e8..dcb24f00f1 100644 --- a/src/qtcurve/style/qtcurve.cpp +++ b/src/qtcurve/style/qtcurve.cpp @@ -731,6 +731,7 @@ inline int numButtons(EScrollbar type) case SCROLLBAR_NONE: return 0; } + return 2; } static inline void drawRect(QPainter *p, const QRect &r) @@ -963,7 +964,7 @@ Style::Style() itsAnimateStep(0), itsTitlebarHeight(0), calibre_icon_map(QHash()), - is_kde_session(False), + is_kde_session(0), itsPos(-1, -1), itsHoverWidget(0L), #ifdef Q_WS_X11 @@ -978,7 +979,9 @@ Style::Style() , itsName(name) #endif { +#if !defined(_WIN32) && !defined(__APPLE__) is_kde_session = (getenv("KDE_FULL_SESSION") != NULL); +#endif const char *env=getenv(QTCURVE_PREVIEW_CONFIG); if(env && 0==strcmp(env, QTCURVE_PREVIEW_CONFIG)) { diff --git a/src/qtcurve/style/utils.cpp b/src/qtcurve/style/utils.cpp index cc3b84f7b7..7f2cae9266 100644 --- a/src/qtcurve/style/utils.cpp +++ b/src/qtcurve/style/utils.cpp @@ -74,6 +74,7 @@ namespace QtCurve else return false; #else + Q_UNUSED(widget); return compositingActive(); #endif } diff --git a/src/qtcurve/style/windowmanager.cpp b/src/qtcurve/style/windowmanager.cpp index cc03d3a239..4a1e6113e0 100644 --- a/src/qtcurve/style/windowmanager.cpp +++ b/src/qtcurve/style/windowmanager.cpp @@ -680,6 +680,8 @@ namespace QtCurve NETRootInfo rootInfo(QX11Info::display(), NET::WMMoveResize); rootInfo.moveResizeRequest( widget->window()->winId(), position.x(), position.y(), NET::Move); #endif // QTC_QT_ONLY + #else + Q_UNUSED(position); #endif } From 0ed633752ad0848b96ccc897abee40f78e1358f7 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 11 Jun 2012 15:10:42 +0530 Subject: [PATCH 5/8] AZW3 Output: Handle the case of a link pointing to the last line of text in the document. Fixes #1011330 (cannot convert rtf to azw3) --- src/calibre/ebooks/mobi/writer8/skeleton.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/calibre/ebooks/mobi/writer8/skeleton.py b/src/calibre/ebooks/mobi/writer8/skeleton.py index ebdaab1672..7f79f12726 100644 --- a/src/calibre/ebooks/mobi/writer8/skeleton.py +++ b/src/calibre/ebooks/mobi/writer8/skeleton.py @@ -372,6 +372,11 @@ class Chunker(object): # the chunk immediately after pos_fid = (chunk.sequence_number, 0, offset) break + if chunk is self.chunk_table[-1]: + # This can happen for aids very close to the end of the the + # end of the text (https://bugs.launchpad.net/bugs/1011330) + pos_fid = (chunk.sequence_number, offset-chunk.insert_pos, + offset) if pos_fid is None: raise ValueError('Could not find chunk for aid: %r'% match.group(1)) From 13bdcf83b57d2a36fd6d78720c143d0700d7a3c3 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 11 Jun 2012 15:59:56 +0530 Subject: [PATCH 6/8] Update Qt to 4.8.2 in windows binary build and turn on LTCG --- setup/installer/windows/freeze.py | 2 +- setup/installer/windows/notes.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setup/installer/windows/freeze.py b/setup/installer/windows/freeze.py index f87d587f21..7904ddce6b 100644 --- a/setup/installer/windows/freeze.py +++ b/setup/installer/windows/freeze.py @@ -14,7 +14,7 @@ from setup.build_environment import msvc, MT, RC from setup.installer.windows.wix import WixMixIn OPENSSL_DIR = r'Q:\openssl' -QT_DIR = 'Q:\\Qt\\4.8.1' +QT_DIR = 'Q:\\Qt\\4.8.2' QT_DLLS = ['Core', 'Gui', 'Network', 'Svg', 'WebKit', 'Xml', 'XmlPatterns'] QTCURVE = r'C:\plugins\styles' LIBUNRAR = 'C:\\Program Files\\UnrarDLL\\unrar.dll' diff --git a/setup/installer/windows/notes.rst b/setup/installer/windows/notes.rst index 7fe978d30b..62afda4df8 100644 --- a/setup/installer/windows/notes.rst +++ b/setup/installer/windows/notes.rst @@ -97,7 +97,7 @@ Now, run configure and make:: -no-plugin-manifests is needed so that loading the plugins does not fail looking for the CRT assembly - configure -opensource -release -qt-zlib -qt-libmng -qt-libpng -qt-libtiff -qt-libjpeg -release -platform win32-msvc2008 -no-qt3support -webkit -xmlpatterns -no-phonon -no-style-plastique -no-style-cleanlooks -no-style-motif -no-style-cde -no-declarative -no-scripttools -no-audio-backend -no-multimedia -no-dbus -no-openvg -no-opengl -no-qt3support -confirm-license -nomake examples -nomake demos -nomake docs -no-plugin-manifests -openssl -I Q:\openssl\include -L Q:\openssl\lib && nmake + configure -opensource -release -ltcg -qt-zlib -qt-libmng -qt-libpng -qt-libtiff -qt-libjpeg -release -platform win32-msvc2008 -no-qt3support -webkit -xmlpatterns -no-phonon -no-style-plastique -no-style-cleanlooks -no-style-motif -no-style-cde -no-declarative -no-scripttools -no-audio-backend -no-multimedia -no-dbus -no-openvg -no-opengl -no-qt3support -confirm-license -nomake examples -nomake demos -nomake docs -no-plugin-manifests -openssl -I Q:\openssl\include -L Q:\openssl\lib && nmake Add the path to the bin folder inside the Qt dir to your system PATH. From 23e620a0d5c2f0a12f1f40d03ef3597a4e27b629 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 12 Jun 2012 09:12:16 +0530 Subject: [PATCH 7/8] Update the version of ipython in the OS X build --- setup/installer/osx/app/main.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/setup/installer/osx/app/main.py b/setup/installer/osx/app/main.py index 2cf7e1df48..96edbc2c8f 100644 --- a/setup/installer/osx/app/main.py +++ b/setup/installer/osx/app/main.py @@ -482,6 +482,10 @@ class Py2App(object): shutil.rmtree(tdir) shutil.rmtree(os.path.join(self.site_packages, 'calibre', 'plugins')) self.remove_bytecode(join(self.resources_dir, 'Python', 'site-packages')) + # Create dummy IPython README_STARTUP + with open(join(self.site_packages, + 'IPython/config/profile/README_STARTUP'), 'wb') as f: + f.write('\n') @flush def add_modules_from_dir(self, src): @@ -551,6 +555,15 @@ class Py2App(object): if dest2.endswith('.so'): self.fix_dependencies_in_lib(dest2) self.remove_bytecode(join(self.resources_dir, 'Python', 'lib')) + confdir = join(self.resources_dir, 'Python', + 'lib/python%s/config'%self.version_info) + os.makedirs(confdir) + shutil.copy2(join(src, 'config/Makefile'), confdir) + incdir = join(self.resources_dir, 'Python', + 'include/python'+self.version_info) + os.makedirs(incdir) + shutil.copy2(join(src.replace('/lib/', '/include/'), 'pyconfig.h'), + incdir) @flush def remove_bytecode(self, dest): From 74e0716c27e03bb275c055c4b1633e5ffb744b13 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 12 Jun 2012 09:34:10 +0530 Subject: [PATCH 8/8] Get Books: Update the Project Gutenberg plugin for the changes to the PG site --- .../gui2/store/stores/gutenberg_plugin.py | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/calibre/gui2/store/stores/gutenberg_plugin.py b/src/calibre/gui2/store/stores/gutenberg_plugin.py index 64d8401f4e..cbf3a2f565 100644 --- a/src/calibre/gui2/store/stores/gutenberg_plugin.py +++ b/src/calibre/gui2/store/stores/gutenberg_plugin.py @@ -22,10 +22,10 @@ from calibre.gui2.store.search_result import SearchResult from calibre.gui2.store.web_store_dialog import WebStoreDialog class GutenbergStore(BasicStoreConfig, StorePlugin): - + def open(self, parent=None, detail_item=None, external=False): url = 'http://gutenberg.org/' - + if detail_item: detail_item = url_slash_cleaner(url + detail_item) @@ -39,46 +39,46 @@ class GutenbergStore(BasicStoreConfig, StorePlugin): def search(self, query, max_results=10, timeout=60): url = 'http://m.gutenberg.org/ebooks/search.mobile/?default_prefix=all&sort_order=title&query=' + urllib.quote_plus(query) - + br = browser() - + counter = max_results with closing(br.open(url, timeout=timeout)) as f: doc = html.fromstring(f.read()) - for data in doc.xpath('//ol[@class="results"]//li[contains(@class, "icon_title") and not(contains(@class, "toplink"))]'): + for data in doc.xpath('//ol[@class="results"]/li[@class="booklink"]'): if counter <= 0: break id = ''.join(data.xpath('./a/@href')) id = id.split('.mobile')[0] - + title = ''.join(data.xpath('.//span[@class="title"]/text()')) author = ''.join(data.xpath('.//span[@class="subtitle"]/text()')) - + counter -= 1 - + s = SearchResult() s.cover_url = '' - + s.detail_item = id.strip() s.title = title.strip() s.author = author.strip() s.price = '$0.00' s.drm = SearchResult.DRM_UNLOCKED - + yield s def get_details(self, search_result, timeout): url = url_slash_cleaner('http://m.gutenberg.org/' + search_result.detail_item) - + br = browser() with closing(br.open(url, timeout=timeout)) as nf: doc = html.fromstring(nf.read()) - + for save_item in doc.xpath('//li[contains(@class, "icon_save")]/a'): type = save_item.get('type') href = save_item.get('href') - + if type: ext = mimetypes.guess_extension(type) if ext: