From 8d6bc29107fbda0c6968dad4f42c612a4965faa9 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 18 Jan 2009 11:28:27 -0800 Subject: [PATCH 01/11] New recipes for Ambito and El Argentino by Darko Miletic --- src/calibre/gui2/images/news/ambito.png | Bin 0 -> 508 bytes src/calibre/gui2/images/news/elargentino.png | Bin 0 -> 805 bytes src/calibre/web/feeds/recipes/__init__.py | 2 +- .../web/feeds/recipes/recipe_ambito.py | 44 ++++++++++++++ .../web/feeds/recipes/recipe_elargentino.py | 55 ++++++++++++++++++ 5 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 src/calibre/gui2/images/news/ambito.png create mode 100644 src/calibre/gui2/images/news/elargentino.png create mode 100644 src/calibre/web/feeds/recipes/recipe_ambito.py create mode 100644 src/calibre/web/feeds/recipes/recipe_elargentino.py diff --git a/src/calibre/gui2/images/news/ambito.png b/src/calibre/gui2/images/news/ambito.png new file mode 100644 index 0000000000000000000000000000000000000000..e0a6f409cf01248d35328d5a43c3cb78981d2139 GIT binary patch literal 508 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b zK-vS0-A-oPfdtD69Mgd`SU*F|v9*U87#LMOT^vI!PA7j^WASS~BmaYE35hR!E~f=d zdXkm^1UtU}(RMz!q`RO}jg3j+maEvhpRfDvd1_a`UvOe`!sR6@C(kCV)ID3< z3A&u(`B5d!5AS_mzk?TKk_K03;)W|ihYY@eG{x8dIV#}((P>scQ&(Eb?H!g85?RTn zAEXy7KhnQQ(sF|Y5FBB>`BA!I&4bh5?F*JKZs$K|pfSIc_2l__$tfy3C3jc`9G*G5 zS#mq$^!N2iAol@HPwFU}==xDeuOX>nl8U)=?i#i`+CZxke|-9@AGSZ4mpSFEfPQRh z#m|52apDhnj#QuDpQIwy#HPR;q0_-#G$FlVo{)X>>Wva{|C1#O{@k(_IeADx^wORU zCFhfQoG&m|)iE$Mt40*-YTYsbhMsDPYeY$MQEFmIs%{F9U@$T;u+%j$)HSpSF|@QY tGO{u@)iyA&GBB9Bb5agWLvDUbW?Cfy4W~GsL;y7~c)I$ztaD0e0sy%tz9|3z literal 0 HcmV?d00001 diff --git a/src/calibre/gui2/images/news/elargentino.png b/src/calibre/gui2/images/news/elargentino.png new file mode 100644 index 0000000000000000000000000000000000000000..1e3e64d8a512fc1eba6e2352a617e090892befcd GIT binary patch literal 805 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b zK-vS0-A-oPfdtD69Mgd`SU*F|v9*U87?}J#T^vI!PPb0>^%oA5Xr2Ev>-CnB6$^P+ zs){-%WlU|&Mt(v)YoNk!;@Z~E2`7wzg}W~67a~LkIC?fLym(((a*qR z`3dG+H)4eww%+BF4&{EC&%e*Sy5}X=GF6FJViWfWT4`^eP$M{{cymY4v};e*mlT&? z+R3&|_1B|^+gYU(5{o$Yt4)qt|LA(kwDqkWH|#e^vpxxEDp_~#^V(U?bNF@{nsC1K zUYdP=-4qYE(rI0}&ko5M{Z!+g>})gVOLA0GtA8p`kl|6ATh^%rs~2nzz0y()GixS` zhcln6N?TI@@YyRlpsN~wa>}pNOkR-w>f+g$8_n^PJ>5zff?kKV&zWU3WBv!mgs3K; zeV#_EJ-YWau_qT^_tk{-nWc)~NjW$b+ku0P9x7{Mqw)ftc+<48^W-8gQ zRD5u`(K787hR(|0)KBg2s0z)S|9#V+%|~D7^X@v7ruO8Z?&00>xmnX5oZGS8zVrD0 z&zTiFV~@Y#3iFnYQ$1%?<@V5=^TFE%E8Sa;1CyC*iEBhja#3nxNvduNkYF$}FtF4$ zFw`})2r;y@GBU6-G1oRQure^<5sLyPW3YzY{FKbJN&*^!m+OQAH86O(`njxgN@xNA Dhy6&K literal 0 HcmV?d00001 diff --git a/src/calibre/web/feeds/recipes/__init__.py b/src/calibre/web/feeds/recipes/__init__.py index 8b0165b184..e6bcdaed9c 100644 --- a/src/calibre/web/feeds/recipes/__init__.py +++ b/src/calibre/web/feeds/recipes/__init__.py @@ -22,7 +22,7 @@ recipe_modules = ['recipe_' + r for r in ( 'time_magazine', 'endgadget', 'fudzilla', 'nspm_int', 'nspm', 'pescanik', 'spiegel_int', 'themarketticker', 'tomshardware', 'xkcd', 'ftd', 'zdnet', 'joelonsoftware', 'telepolis', 'common_dreams', 'nin', 'tomshardware_de', - 'pagina12', 'infobae', + 'pagina12', 'infobae', 'ambito', 'elargentino', )] import re, imp, inspect, time, os diff --git a/src/calibre/web/feeds/recipes/recipe_ambito.py b/src/calibre/web/feeds/recipes/recipe_ambito.py new file mode 100644 index 0000000000..56528c27c0 --- /dev/null +++ b/src/calibre/web/feeds/recipes/recipe_ambito.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python + +__license__ = 'GPL v3' +__copyright__ = '2008, Darko Miletic ' +''' +ambito.com +''' + + +from calibre.web.feeds.news import BasicNewsRecipe + +class Ambito(BasicNewsRecipe): + title = 'Ambito.com' + __author__ = 'Darko Miletic' + description = 'Informacion Libre las 24 horas' + oldest_article = 2 + max_articles_per_feed = 100 + no_stylesheets = True + use_embedded_content = False + encoding = 'iso--8859-1' + cover_url = 'http://www.ambito.com/img/logo_.jpg' + + html2lrf_options = [ + '--comment' , description + , '--category' , 'news, Argentina' + , '--publisher' , title + ] + + feeds = [ + (u'Principales Noticias', u'http://www.ambito.com/rss/noticiasp.asp' ) + ,(u'Economia' , u'http://www.ambito.com/rss/noticias.asp?S=Econom%EDa' ) + ,(u'Politica' , u'http://www.ambito.com/rss/noticias.asp?S=Pol%EDtica' ) + ,(u'Informacion General' , u'http://www.ambito.com/rss/noticias.asp?S=Informaci%F3n%20General') + ,(u'Agro' , u'http://www.ambito.com/rss/noticias.asp?S=Agro' ) + ,(u'Internacionales' , u'http://www.ambito.com/rss/noticias.asp?S=Internacionales' ) + ,(u'Deportes' , u'http://www.ambito.com/rss/noticias.asp?S=Deportes' ) + ,(u'Espectaculos' , u'http://www.ambito.com/rss/noticias.asp?S=Espect%E1culos' ) + ,(u'Tecnologia' , u'http://www.ambito.com/rss/noticias.asp?S=Tecnologia' ) + ,(u'Salud' , u'http://www.ambito.com/rss/noticias.asp?S=Salud' ) + ,(u'Ambito Nacional' , u'http://www.ambito.com/rss/noticias.asp?S=Ambito%20Nacional' ) + ] + + def print_version(self, url): + return url.replace('http://www.ambito.com/noticia.asp?','http://www.ambito.com/noticias/imprimir.asp?') diff --git a/src/calibre/web/feeds/recipes/recipe_elargentino.py b/src/calibre/web/feeds/recipes/recipe_elargentino.py new file mode 100644 index 0000000000..7aee232787 --- /dev/null +++ b/src/calibre/web/feeds/recipes/recipe_elargentino.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python + +__license__ = 'GPL v3' +__copyright__ = '2008, Darko Miletic ' +''' +elargentino.com +''' + +from calibre.web.feeds.news import BasicNewsRecipe + +class ElArgentino(BasicNewsRecipe): + title = 'ElArgentino.com' + __author__ = 'Darko Miletic' + description = 'Informacion Libre las 24 horas' + oldest_article = 2 + max_articles_per_feed = 100 + no_stylesheets = True + use_embedded_content = False + encoding = 'utf8' + cover_url = 'http://www.elargentino.com/TemplateWeb/MediosFooter/tapa_elargentino.png' + + html2lrf_options = [ + '--comment' , description + , '--category' , 'news, Argentina' + , '--publisher' , 'ElArgentino.com' + ] + + remove_tags = [ + dict(name='div', attrs={'id':'noprint' }) + ,dict(name='div', attrs={'class':'encabezadoImprimir'}) + ,dict(name='a' , attrs={'target':'_blank' }) + ] + + feeds = [ + (u'Portada' , u'http://www.elargentino.com/Highlights.aspx?Content-Type=text/xml&ChannelDesc=Home' ) + ,(u'Pais' , u'http://www.elargentino.com/Highlights.aspx?ParentType=Section&ParentId=112&Content-Type=text/xml&ChannelDesc=Pa%C3%ADs' ) + ,(u'Economia' , u'http://www.elargentino.com/Highlights.aspx?ParentType=Section&ParentId=107&Content-Type=text/xml&ChannelDesc=Econom%C3%ADa' ) + ,(u'Mundo' , u'http://www.elargentino.com/Highlights.aspx?ParentType=Section&ParentId=113&Content-Type=text/xml&ChannelDesc=Mundo' ) + ,(u'Tecnologia' , u'http://www.elargentino.com/Highlights.aspx?ParentType=Section&ParentId=118&Content-Type=text/xml&ChannelDesc=Tecnolog%C3%ADa' ) + ,(u'Espectaculos', u'http://www.elargentino.com/Highlights.aspx?ParentType=Section&ParentId=114&Content-Type=text/xml&ChannelDesc=Espect%C3%A1culos') + ,(u'Deportes' , u'http://www.elargentino.com/Highlights.aspx?ParentType=Section&ParentId=106&Content-Type=text/xml&ChannelDesc=Deportes' ) + ,(u'Sociedad' , u'http://www.elargentino.com/Highlights.aspx?ParentType=Section&ParentId=109&Content-Type=text/xml&ChannelDesc=Sociedad' ) + ,(u'Entrevistas' , u'http://www.elargentino.com/Highlights.aspx?ParentType=Section&ParentId=115&Content-Type=text/xml&ChannelDesc=Entrevistas' ) + ] + + def print_version(self, url): + main, sep, article_part = url.partition('/nota-') + article_id, rsep, rrest = article_part.partition('-') + return u'http://www.elargentino.com/Impresion.aspx?Id=' + article_id + + def preprocess_html(self, soup): + mtag = '' + soup.head.insert(0,mtag) + soup.prettify() + return soup From edd7ef00b183647ff5f766fd35c8aaedfce8adc2 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 18 Jan 2009 14:00:47 -0800 Subject: [PATCH 02/11] Add progress dialog for saving to disk. Also Fix #1624 (Reading meta-data dialogue box doesn't close in windows XP) --- src/calibre/ebooks/lrf/comic/convert_from.py | 12 +-- src/calibre/gui2/dialogs/progress.py | 48 +++++++++++ src/calibre/gui2/dialogs/progress.ui | 72 ++++++++++++++++ src/calibre/gui2/library.py | 13 ++- src/calibre/gui2/main.py | 84 +++++++++++-------- src/calibre/library/database.py | 18 ++-- src/calibre/trac/bzr_commit_plugin.py | 1 - .../web/feeds/recipes/recipe_clarin.py | 3 +- 8 files changed, 196 insertions(+), 55 deletions(-) create mode 100644 src/calibre/gui2/dialogs/progress.py create mode 100644 src/calibre/gui2/dialogs/progress.ui diff --git a/src/calibre/ebooks/lrf/comic/convert_from.py b/src/calibre/ebooks/lrf/comic/convert_from.py index 0569bf3733..c22f1745ae 100755 --- a/src/calibre/ebooks/lrf/comic/convert_from.py +++ b/src/calibre/ebooks/lrf/comic/convert_from.py @@ -10,11 +10,6 @@ Based on ideas from comiclrf created by FangornUK. import os, sys, shutil, traceback, textwrap from uuid import uuid4 -try: - from reportlab.pdfgen import canvas - _reportlab = True -except: - _reportlab = False @@ -396,10 +391,9 @@ def create_lrf(pages, profile, opts, thumbnail=None): def create_pdf(pages, profile, opts, thumbnail=None): width, height = PROFILES[profile] - - if not _reportlab: - raise RuntimeError('Failed to load reportlab') - + + from reportlab.pdfgen import canvas + pdf = canvas.Canvas(filename=opts.output, pagesize=(width,height+15)) pdf.setAuthor(opts.author) pdf.setTitle(opts.title) diff --git a/src/calibre/gui2/dialogs/progress.py b/src/calibre/gui2/dialogs/progress.py new file mode 100644 index 0000000000..2543cefb4d --- /dev/null +++ b/src/calibre/gui2/dialogs/progress.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python +__license__ = 'GPL v3' +__copyright__ = '2009, Kovid Goyal kovid@kovidgoyal.net' +__docformat__ = 'restructuredtext en' + +'''''' + +from PyQt4.Qt import QDialog, SIGNAL, Qt + +from calibre.gui2.dialogs.progress_ui import Ui_Dialog + +class ProgressDialog(QDialog, Ui_Dialog): + + def __init__(self, title, msg='', min=0, max=99, parent=None): + QDialog.__init__(self, parent) + self.setupUi(self) + self.setWindowTitle(title) + self.title.setText(title) + self.message.setText(msg) + self.setWindowModality(Qt.ApplicationModal) + self.set_min(min) + self.set_max(max) + self.canceled = False + + self.connect(self.button_box, SIGNAL('rejected()'), self._canceled) + + def set_msg(self, msg=''): + self.message.setText(msg) + + def set_value(self, val): + self.bar.setValue(val) + + def set_min(self, min): + self.bar.setMinimum(min) + + def set_max(self, max): + self.bar.setMaximum(max) + + def _canceled(self, *args): + self.canceled = True + self.button_box.setDisabled(True) + self.title.setText(_('Aborting...')) + + def keyPressEvent(self, ev): + if ev.key() == Qt.Key_Escape: + self._canceled() + else: + QDialog.keyPressEvent(self, ev) \ No newline at end of file diff --git a/src/calibre/gui2/dialogs/progress.ui b/src/calibre/gui2/dialogs/progress.ui new file mode 100644 index 0000000000..60488be62d --- /dev/null +++ b/src/calibre/gui2/dialogs/progress.ui @@ -0,0 +1,72 @@ + + Dialog + + + + 0 + 0 + 712 + 308 + + + + Dialog + + + + :/images/jobs.svg:/images/jobs.svg + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + true + + + + + + + 0 + + + + + + + TextLabel + + + Qt::AlignCenter + + + true + + + + + + + QDialogButtonBox::Abort + + + + + + + + + + diff --git a/src/calibre/gui2/library.py b/src/calibre/gui2/library.py index 792d011883..8a737fd608 100644 --- a/src/calibre/gui2/library.py +++ b/src/calibre/gui2/library.py @@ -198,13 +198,18 @@ class BooksModel(QAbstractTableModel): ''' Return list indices of all cells in index.row()''' return [ self.index(index.row(), c) for c in range(self.columnCount(None))] - def save_to_disk(self, rows, path, single_dir=False, single_format=None): + def save_to_disk(self, rows, path, single_dir=False, single_format=None, + callback=None): rows = [row.row() for row in rows] if single_format is None: - return self.db.export_to_dir(path, rows, self.sorted_on[0] == 'authors', - single_dir=single_dir) + return self.db.export_to_dir(path, rows, + self.sorted_on[0] == 'authors', + single_dir=single_dir, + callback=callback) else: - return self.db.export_single_format_to_dir(path, rows, single_format) + return self.db.export_single_format_to_dir(path, rows, + single_format, + callback=callback) def delete_books(self, indices): diff --git a/src/calibre/gui2/main.py b/src/calibre/gui2/main.py index 6ff5df412d..b04ad18c97 100644 --- a/src/calibre/gui2/main.py +++ b/src/calibre/gui2/main.py @@ -28,6 +28,7 @@ from calibre.gui2.cover_flow import CoverFlow, DatabaseImages, pictureflowerror from calibre.library.database import LibraryDatabase from calibre.gui2.dialogs.scheduler import Scheduler from calibre.gui2.update import CheckForUpdates +from calibre.gui2.dialogs.progress import ProgressDialog from calibre.gui2.main_window import MainWindow, option_parser as _option_parser from calibre.gui2.main_ui import Ui_MainWindow from calibre.gui2.device import DeviceManager @@ -598,29 +599,26 @@ class Main(MainWindow, Ui_MainWindow): root = choose_dir(self, 'recursive book import root dir dialog', 'Select root folder') if not root: return - progress = QProgressDialog('', '&'+_('Stop'), - 0, 0, self) - progress.setWindowModality(Qt.ApplicationModal) - progress.setWindowTitle(_('Adding books recursively...')) + progress = ProgressDialog(_('Adding books recursively...'), + min=0, max=0, parent=self) progress.show() def callback(msg): if msg != '.': - progress.setLabelText((_('Added ')+msg) if msg else _('Searching...')) - stop = progress.wasCanceled() + progress.set_msg((_('Added ')+msg) if msg else _('Searching...')) QApplication.processEvents() QApplication.sendPostedEvents() QApplication.flush() - return stop + return progress.canceled try: duplicates = self.library_view.model().db.recursive_import(root, single, callback=callback) finally: - progress.hide() - progress.close() + progress.hide() if duplicates: files = _('

Books with the same title as the following already exist in the database. Add them anyway?

    ') for mi, formats in duplicates: files += '
  • '+mi.title+'
  • \n' - d = WarningDialog(_('Duplicates found!'), _('Duplicates found!'), files+'

', self) + d = WarningDialog(_('Duplicates found!'), _('Duplicates found!'), + files+'

', self) if d.exec_() == QDialog.Accepted: for mi, formats in duplicates: self.library_view.model().db.import_book(mi, formats ) @@ -686,15 +684,13 @@ class Main(MainWindow, Ui_MainWindow): return # Get format and metadata information formats, metadata, names, infos = [], [], [], [] - progress = QProgressDialog(_('Reading metadata...'), _('Stop'), 0, len(paths), self) - progress.setWindowTitle(_('Adding books...')) - progress.setWindowModality(Qt.ApplicationModal) - progress.setLabelText(_('Reading metadata...')) + progress = ProgressDialog(_('Adding books...'), _('Reading metadata...'), + min=0, max=len(paths), parent=self) progress.show() try: for c, book in enumerate(paths): - progress.setValue(c) - if progress.wasCanceled(): + progress.set_value(c) + if progress.canceled: return format = os.path.splitext(book)[1] format = format[1:] if format else None @@ -713,15 +709,14 @@ class Main(MainWindow, Ui_MainWindow): infos.append({'title':mi.title, 'authors':', '.join(mi.authors), 'cover':self.default_thumbnail, 'tags':[]}) title = mi.title if isinstance(mi.title, unicode) else mi.title.decode(preferred_encoding, 'replace') - progress.setLabelText(_('Read metadata from ')+title) + progress.set_msg(_('Read metadata from ')+title) if not to_device: - progress.setLabelText(_('Adding books to database...')) + progress.set_msg(_('Adding books to database...')) model = self.library_view.model() paths = list(paths) duplicates, number_added = model.add_books(paths, formats, metadata) - progress.cancel() if duplicates: files = _('

Books with the same title as the following already exist in the database. Add them anyway?