Sync to trunk

This commit is contained in:
John Schember 2009-01-19 08:08:36 -05:00
commit d0437d9545
47 changed files with 14009 additions and 6960 deletions

View File

@ -2,7 +2,7 @@ __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en'
__appname__ = 'calibre'
__version__ = '0.4.128'
__version__ = '0.4.129'
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
'''
Various run time constants.

View File

@ -146,36 +146,7 @@ class PRS505(Device):
self._card_prefix = re.search(card_pat, mount).group(2) + os.sep
def open_windows_nowmi(self):
from calibre import plugins
winutil = plugins['winutil'][0]
volumes = winutil.get_mounted_volumes_for_usb_device(self.VENDOR_ID, self.PRODUCT_ID)
main = None
for device_id in volumes.keys():
if 'PRS-505/UC&' in device_id:
main = volumes[device_id]+':\\'
if not main:
raise DeviceError(_('Unable to detect the %s disk drive. Try rebooting.')%self.__class__.__name__)
self._main_prefix = main
card = self._card_prefix = None
win32api = __import__('win32api')
for device_id in volumes.keys():
if 'PRS-505/UC:' in device_id:
card = volumes[device_id]+':\\'
try:
win32api.GetVolumeInformation(card)
self._card_prefix = card
break
except:
continue
def open_windows(self):
try:
self.open_windows_nowmi()
return
except:
pass
drives = []
wmi = __import__('wmi', globals(), locals(), [], -1)
c = wmi.WMI()

View File

@ -40,6 +40,7 @@ def convert(opts, recipe_arg, notification=None):
c.smart_update(recipe_opts, opts)
opts = recipe_opts
opts.chapter_mark = 'none'
opts.dont_split_on_page_breaks = True
opf = glob.glob(os.path.join(tdir, '*.opf'))
if not opf:
raise Exception('Downloading of recipe: %s failed'%recipe_arg)

View File

@ -129,6 +129,8 @@ class HTMLProcessor(Processor, Rationalizer):
for script in list(self.body.xpath('descendant::script')):
script.getparent().remove(script)
self.fix_markup()
def convert_image(self, img):
rpath = img.get('src', '')
path = os.path.join(os.path.dirname(self.save_path()), *rpath.split('/'))
@ -146,6 +148,17 @@ class HTMLProcessor(Processor, Rationalizer):
self.resource_map[key] = rpath+'_calibre_converted.jpg'
img.set('src', rpath+'_calibre_converted.jpg')
def fix_markup(self):
'''
Perform various markup transforms to get the output to render correctly
in the quirky ADE.
'''
# Replace <br> that are children of <body> with <p>&nbsp;</p>
if hasattr(self.body, 'xpath'):
for br in self.body.xpath('./br'):
br.tag = 'p'
br.text = u'\u00a0'
def save(self):
for meta in list(self.root.xpath('//meta')):
meta.getparent().remove(meta)

View File

@ -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
@ -397,8 +392,7 @@ 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)

View File

@ -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)

View File

@ -0,0 +1,72 @@
<ui version="4.0" >
<class>Dialog</class>
<widget class="QDialog" name="Dialog" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>712</width>
<height>308</height>
</rect>
</property>
<property name="windowTitle" >
<string>Dialog</string>
</property>
<property name="windowIcon" >
<iconset resource="../images.qrc" >
<normaloff>:/images/jobs.svg</normaloff>:/images/jobs.svg</iconset>
</property>
<layout class="QGridLayout" name="gridLayout" >
<item row="0" column="0" >
<widget class="QLabel" name="title" >
<property name="font" >
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text" >
<string>TextLabel</string>
</property>
<property name="alignment" >
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap" >
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QProgressBar" name="bar" >
<property name="value" >
<number>0</number>
</property>
</widget>
</item>
<item row="2" column="0" >
<widget class="QLabel" name="message" >
<property name="text" >
<string>TextLabel</string>
</property>
<property name="alignment" >
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap" >
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0" >
<widget class="QDialogButtonBox" name="button_box" >
<property name="standardButtons" >
<set>QDialogButtonBox::Abort</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../images.qrc" />
</resources>
<connections/>
</ui>

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 805 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 901 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 B

View File

@ -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):

View File

@ -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
@ -308,17 +309,6 @@ class Main(MainWindow, Ui_MainWindow):
self.library_path = dir
db = LibraryDatabase2(self.library_path)
self.library_view.set_database(db)
if self.olddb is not None:
pd = QProgressDialog('', '', 0, 100, self)
pd.setWindowModality(Qt.ApplicationModal)
pd.setCancelButton(None)
pd.setWindowTitle(_('Migrating database'))
pd.show()
number_of_books = db.migrate_old(self.olddb, pd)
self.olddb.close()
if number_of_books == 0:
os.remove(self.olddb.dbpath)
self.olddb = None
prefs['library_path'] = self.library_path
self.library_view.sortByColumn(*dynamic.get('sort_column', ('timestamp', Qt.DescendingOrder)))
if not self.library_view.restore_column_widths():
@ -339,6 +329,8 @@ class Main(MainWindow, Ui_MainWindow):
self.connect(self.search, SIGNAL('search(PyQt_PyObject, PyQt_PyObject)'),
self.tags_view.model().reinit)
self.connect(self.library_view.model(), SIGNAL('count_changed(int)'), self.location_view.count_changed)
self.connect(self.library_view.model(), SIGNAL('count_changed(int)'),
self.tags_view.recount)
self.library_view.model().count_changed()
########################### Cover Flow ################################
self.cover_flow = None
@ -598,29 +590,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()
if duplicates:
files = _('<p>Books with the same title as the following already exist in the database. Add them anyway?<ul>')
for mi, formats in duplicates:
files += '<li>'+mi.title+'</li>\n'
d = WarningDialog(_('Duplicates found!'), _('Duplicates found!'), files+'</ul></p>', self)
d = WarningDialog(_('Duplicates found!'), _('Duplicates found!'),
files+'</ul></p>', self)
if d.exec_() == QDialog.Accepted:
for mi, formats in duplicates:
self.library_view.model().db.import_book(mi, formats )
@ -686,15 +675,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 +700,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 = _('<p>Books with the same title as the following already exist in the database. Add them anyway?<ul>')
for mi in duplicates[2]:
@ -734,9 +720,7 @@ class Main(MainWindow, Ui_MainWindow):
else:
self.upload_books(paths, list(map(sanitize_file_name, names)), infos, on_card=on_card)
finally:
progress.setValue(progress.maximum())
progress.hide()
progress.close()
def upload_books(self, files, names, metadata, on_card=False, memory=None):
'''
@ -979,18 +963,37 @@ class Main(MainWindow, Ui_MainWindow):
self.save_to_disk(checked, True)
def save_to_disk(self, checked, single_dir=False, single_format=None):
rows = self.current_view().selectionModel().selectedRows()
if not rows or len(rows) == 0:
d = error_dialog(self, _('Cannot save to disk'), _('No books selected'))
d.exec_()
return
progress = ProgressDialog(_('Saving to disk...'), min=0, max=len(rows),
parent=self)
def callback(count, msg):
progress.set_value(count)
progress.set_msg(_('Saved')+' '+msg)
QApplication.processEvents()
QApplication.sendPostedEvents()
QApplication.flush()
return not progress.canceled
dir = choose_dir(self, 'save to disk dialog', _('Choose destination directory'))
if not dir:
return
progress.show()
QApplication.processEvents()
QApplication.sendPostedEvents()
QApplication.flush()
try:
if self.current_view() == self.library_view:
failures = self.current_view().model().save_to_disk(rows, dir,
single_dir=single_dir, single_format=single_format)
single_dir=single_dir, callback=callback,
single_format=single_format)
if failures and single_format is not None:
msg = _('<p>Could not save the following books to disk, because the %s format is not available for them:<ul>')%single_format.upper()
for f in failures:
@ -1001,6 +1004,8 @@ class Main(MainWindow, Ui_MainWindow):
else:
paths = self.current_view().model().paths(rows)
self.device_manager.save_books(Dispatcher(self.books_saved), paths, dir)
finally:
progress.hide()
def books_saved(self, job):
if job.exception is not None:
@ -1115,6 +1120,7 @@ class Main(MainWindow, Ui_MainWindow):
os.remove(f.name)
except:
pass
self.tags_view.recount()
if self.current_view() is self.library_view:
current = self.library_view.currentIndex()
self.library_view.model().current_changed(current, QModelIndex())
@ -1375,39 +1381,14 @@ class Main(MainWindow, Ui_MainWindow):
def initialize_database(self):
self.library_path = prefs['library_path']
self.olddb = None
if self.library_path is None: # Need to migrate to new database layout
QMessageBox.information(self, 'Database format changed',
'''\
<p>calibre's book storage format has changed. Instead of storing book files in a database, the
files are now stored in a folder on your filesystem. You will now be asked to choose the folder
in which you want to store your books files. Any existing books will be automatically migrated.
''')
self.database_path = prefs['database_path']
if not os.access(os.path.dirname(self.database_path), os.W_OK):
error_dialog(self, _('Database does not exist'),
_('The directory in which the database should be: %s no longer exists. Please choose a new database location.')%self.database_path).exec_()
self.database_path = choose_dir(self, 'database path dialog',
_('Choose new location for database'))
if not self.database_path:
self.database_path = os.path.expanduser('~').decode(sys.getfilesystemencoding())
if not os.path.exists(self.database_path):
os.makedirs(self.database_path)
self.database_path = os.path.join(self.database_path, 'library1.db')
prefs['database_path'] = self.database_path
home = os.path.dirname(self.database_path)
if not os.path.exists(home):
home = os.getcwd()
dir = unicode(QFileDialog.getExistingDirectory(self,
_('Choose a location for your ebook library.'), home))
_('Choose a location for your ebook library.'), os.getcwd()))
if not dir:
dir = os.path.dirname(self.database_path)
dir = os.path.expanduser('~/Library')
self.library_path = os.path.abspath(dir)
try:
self.olddb = LibraryDatabase(self.database_path)
except:
traceback.print_exc()
self.olddb = None
if not os.path.exists(self.library_path):
os.makedirs(self.library_path)
def read_settings(self):

View File

@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en'
Browsing book collection by tags.
'''
from PyQt4.Qt import QAbstractItemModel, Qt, QVariant, QTreeView, QModelIndex, \
QFont, SIGNAL, QSize, QColor, QIcon
QFont, SIGNAL, QSize, QColor, QIcon, QPoint
from calibre.gui2 import config
NONE = QVariant()
@ -37,6 +37,14 @@ class TagsView(QTreeView):
self.emit(SIGNAL('tags_marked(PyQt_PyObject, PyQt_PyObject)'),
self._model.tokens(), self.match_all.isChecked())
def recount(self, *args):
ci = self.currentIndex()
if not ci.isValid():
ci = self.indexAt(QPoint(10, 10))
self.model().refresh()
if ci.isValid():
self.scrollTo(ci, QTreeView.PositionAtTop)
class TagsModel(QAbstractItemModel):
categories = [_('Authors'), _('Series'), _('Formats'), _('Publishers'), _('News'), _('Tags')]

View File

@ -1390,10 +1390,11 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
return [i[0] for i in self.conn.get('SELECT id FROM books')]
def export_to_dir(self, dir, indices, byauthor=False, single_dir=False,
index_is_id=False):
index_is_id=False, callback=None):
if not os.path.exists(dir):
raise IOError('Target directory does not exist: '+dir)
by_author = {}
count = 0
for index in indices:
id = index if index_is_id else self.id(index)
au = self.conn.get('SELECT author_sort FROM books WHERE id=?',
@ -1403,8 +1404,6 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
if not au:
au = _('Unknown')
au = au.split(',')[0]
else:
au = au.replace(',', ';')
if not by_author.has_key(au):
by_author[au] = []
by_author[au].append(index)
@ -1456,6 +1455,11 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
print 'Error setting metadata for book:', mi.title
traceback.print_exc()
f.close()
count += 1
if callable(callback):
if not callback(count, mi.title):
return
def import_book(self, mi, formats):
@ -1569,12 +1573,13 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
return duplicates
def export_single_format_to_dir(self, dir, indices, format, index_is_id=False):
def export_single_format_to_dir(self, dir, indices, format,
index_is_id=False, callback=None):
dir = os.path.abspath(dir)
if not index_is_id:
indices = map(self.id, indices)
failures = []
for id in indices:
for count, id in enumerate(indices):
try:
data = self.format(id, format, index_is_id=True)
if not data:
@ -1599,6 +1604,9 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
except:
pass
f.close()
if callable(callback):
if not callback(count, title):
break
return failures

View File

@ -38,7 +38,6 @@ class cmd_commit(_cmd_commit):
print attributes['summary']
return attributes['summary']
def expand_bug(self, msg, nick, config, bug_tracker, type='trac'):
prefix = '%s_%s_'%(type, nick)
username = config.get_user_option(prefix+'username')

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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', 'sueddeutsche',
)]
import re, imp, inspect, time, os

View File

@ -0,0 +1,44 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
'''
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?')

View File

@ -48,4 +48,3 @@ class Clarin(BasicNewsRecipe):
rest = artl.partition('-0')[-1]
lmain = rest.partition('.')[0]
return 'http://www.servicios.clarin.com/notas/jsp/clarin/v9/notas/imprimir.jsp?pagid=' + lmain

View File

@ -0,0 +1,55 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
'''
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 = '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">'
soup.head.insert(0,mtag)
soup.prettify()
return soup

View File

@ -4,7 +4,7 @@ class SecurityWatch(BasicNewsRecipe):
title = u'securitywatch'
description = 'security news'
timefmt = ' [%d %b %Y]'
__author__ = 'Oliver'
__author__ = 'Oliver Niesner'
no_stylesheets = True
oldest_article = 14
max_articles_per_feed = 100

View File

@ -0,0 +1,62 @@
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
'''
Fetch sueddeutsche.
'''
from calibre.web.feeds.news import BasicNewsRecipe
class Sueddeutsche(BasicNewsRecipe):
title = u'Sueddeutsche'
description = 'News from Germany'
__author__ = 'Oliver Niesner'
use_embedded_content = False
timefmt = ' [%d %b %Y]'
max_articles_per_feed = 40
no_stylesheets = True
encoding = 'latin1'
remove_tags_after = [dict(name='div', attrs={'class':'artikelBox navigatorBox'})]
#dict(name='table', attrs={'class':'bgf2f2f2 absatz print100'})]
remove_tags = [dict(name='div', attrs={'class':'bannerSuperBanner'}),
dict(name='div', attrs={'class':'bannerSky'}),
dict(name='div', attrs={'class':'footerLinks'}),
dict(name='div', attrs={'class':'seitenanfang'}),
dict(name='td', attrs={'class':'mar5'}),
dict(name='table', attrs={'class':'pageAktiv'}),
dict(name='table', attrs={'class':'xartable'}),
dict(name='table', attrs={'class':'wpnavi'}),
dict(name='table', attrs={'class':'bgcontent absatz'}),
dict(name='table', attrs={'class':'footer'}),
dict(name='table', attrs={'class':'artikelBox'}),
dict(name='table', attrs={'class':'kommentare'}),
dict(name='table', attrs={'class':'pageBoxBot'}),
dict(name='div', attrs={'class':'artikelBox navigatorBox'}),
dict(name='div', attrs={'class':'similar-article-box'}),
dict(name='div', attrs={'class':'videoBigHack'}),
dict(name='td', attrs={'class':'artikelDruckenRight'}),
dict(name='span', attrs={'class':'hidePrint'}),
dict(id='headerLBox'),
dict(id='rechteSpalte'),
dict(id='newsticker-list-small'),
dict(id='ntop5'),
dict(id='ntop5send'),
dict(id='ntop5commented'),
dict(id='nnav-bgheader'),
dict(id='nnav-headerteaser'),
dict(id='nnav-head'),
dict(id='nnav-top'),
dict(id='nnav-logodiv'),
dict(id='nnav-logo'),
dict(id='nnav-oly'),
dict(id='readcomment')]
feeds = [ (u'Sueddeutsche', u'http://www.sueddeutsche.de/app/service/rss/alles/rss.xml') ]
def postprocess_html(self, soup, first_fetch):
for t in soup.findAll(['table', 'tr', 'td']):
t.name = 'div'
return soup

View File

@ -395,7 +395,11 @@ class RecursiveFetcher(object, LoggingInterface):
if self.download_stylesheets:
self.process_stylesheets(soup, newbaseurl)
res = os.path.join(linkdiskpath, basename(iurl))
_fname = basename(iurl)
if not isinstance(_fname, unicode):
_fname.decode('latin1', 'replace')
_fname.encode('ascii', 'replace').replace('%', '')
res = os.path.join(linkdiskpath, _fname)
self.downloaded_paths.append(res)
self.filemap[nurl] = res
if recursion_level < self.max_recursions: