Pull from trunk

This commit is contained in:
Kovid Goyal 2009-03-12 11:36:45 -07:00
commit e66a543fa7
36 changed files with 1542 additions and 784 deletions

View File

@ -52,7 +52,8 @@ if __name__ == '__main__':
resources, clean, gui, translations, update, \ resources, clean, gui, translations, update, \
tag_release, upload_demo, build_linux, build_windows, \ tag_release, upload_demo, build_linux, build_windows, \
build_osx, upload_installers, upload_user_manual, \ build_osx, upload_installers, upload_user_manual, \
upload_to_pypi, stage3, stage2, stage1, upload upload_to_pypi, stage3, stage2, stage1, upload, \
upload_rss
entry_points['console_scripts'].append( entry_points['console_scripts'].append(
'calibre_postinstall = calibre.linux:post_install') 'calibre_postinstall = calibre.linux:post_install')
@ -170,6 +171,7 @@ if __name__ == '__main__':
'upload_installers': upload_installers, 'upload_installers': upload_installers,
'upload_user_manual': upload_user_manual, 'upload_user_manual': upload_user_manual,
'upload_to_pypi': upload_to_pypi, 'upload_to_pypi': upload_to_pypi,
'upload_rss' : upload_rss,
'stage3' : stage3, 'stage3' : stage3,
'stage2' : stage2, 'stage2' : stage2,
'stage1' : stage1, 'stage1' : stage1,

View File

@ -31,6 +31,8 @@ mimetypes.add_type('application/adobe-page-template+xml', '.xpgt')
mimetypes.add_type('application/x-font-opentype', '.otf') mimetypes.add_type('application/x-font-opentype', '.otf')
mimetypes.add_type('application/x-font-truetype', '.ttf') mimetypes.add_type('application/x-font-truetype', '.ttf')
mimetypes.add_type('application/oebps-package+xml', '.opf') mimetypes.add_type('application/oebps-package+xml', '.opf')
mimetypes.add_type('application/ereader', '.pdb')
guess_type = mimetypes.guess_type
import cssutils import cssutils
cssutils.log.setLevel(logging.WARN) cssutils.log.setLevel(logging.WARN)

View File

@ -1306,7 +1306,10 @@ class BeautifulStoneSoup(Tag, SGMLParser):
if self.convertEntities: if self.convertEntities:
if ref.lower().startswith('x'): # if ref.lower().startswith('x'): #
ref = int(ref[1:], 16) # Added by Kovid to handle hex numeric entities ref = int(ref[1:], 16) # Added by Kovid to handle hex numeric entities
data = unichr(int(ref)) try:
data = unichr(int(ref))
except ValueError: # Bad numerical entity. Added by Kovid
data = u''
else: else:
data = '&#%s;' % ref data = '&#%s;' % ref
self.handle_data(data) self.handle_data(data)

View File

@ -346,19 +346,22 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
pix = QPixmap() pix = QPixmap()
pix.loadFromData(cover_data) pix.loadFromData(cover_data)
if pix.isNull(): if pix.isNull():
error_dialog(self.window, "The cover is not a valid picture").exec_() error_dialog(self.window, _('Bad cover'),
_('The cover is not a valid picture')).exec_()
else: else:
self.cover.setPixmap(pix) self.cover.setPixmap(pix)
self.cover_changed = True self.cover_changed = True
self.cpixmap = pix self.cpixmap = pix
except LibraryThingError, err: except LibraryThingError, err:
error_dialog(self, _('Could not fetch cover'), _('<b>Could not fetch cover.</b><br/>')+repr(err)).exec_() error_dialog(self, _('Cannot fetch cover'),
_('<b>Could not fetch cover.</b><br/>')+repr(err)).exec_()
finally: finally:
self.fetch_cover_button.setEnabled(True) self.fetch_cover_button.setEnabled(True)
self.unsetCursor() self.unsetCursor()
else: else:
error_dialog(self, _('Cannot fetch cover'), _('You must specify the ISBN identifier for this book.')).exec_() error_dialog(self, _('Cannot fetch cover'),
_('You must specify the ISBN identifier for this book.')).exec_()
def fetch_metadata(self): def fetch_metadata(self):

View File

@ -818,7 +818,8 @@ class Main(MainWindow, Ui_MainWindow):
rows = self.library_view.selectionModel().selectedRows() rows = self.library_view.selectionModel().selectedRows()
previous = self.library_view.currentIndex() previous = self.library_view.currentIndex()
if not rows or len(rows) == 0: if not rows or len(rows) == 0:
d = error_dialog(self, _('Cannot edit metadata'), _('No books selected')) d = error_dialog(self, _('Cannot edit metadata'),
_('No books selected'))
d.exec_() d.exec_()
return return
@ -1152,6 +1153,8 @@ class Main(MainWindow, Ui_MainWindow):
self.job_manager.server.run_free_job('lrfviewer', kwdargs=dict(args=args)) self.job_manager.server.run_free_job('lrfviewer', kwdargs=dict(args=args))
else: else:
args = ['ebook-viewer', name] args = ['ebook-viewer', name]
if isosx:
args.append('--raise-window')
self.job_manager.server.run_free_job('ebook-viewer', kwdargs=dict(args=args)) self.job_manager.server.run_free_job('ebook-viewer', kwdargs=dict(args=args))
else: else:
QDesktopServices.openUrl(QUrl('file:'+name))#launch(name) QDesktopServices.openUrl(QUrl('file:'+name))#launch(name)

View File

@ -604,6 +604,10 @@ def config(defaults=None):
c = Config('viewer', desc) c = Config('viewer', desc)
else: else:
c = StringConfig(defaults, desc) c = StringConfig(defaults, desc)
c.add_opt('--raise-window', default=False,
help=_('If specified, viewer window will try to come to the '
'front when started.'))
return c return c
def option_parser(): def option_parser():
@ -617,7 +621,7 @@ View an ebook.
def main(args=sys.argv): def main(args=sys.argv):
parser = option_parser() parser = option_parser()
args = parser.parse_args(args)[-1] opts, args = parser.parse_args(args)
pid = os.fork() if False and islinux else -1 pid = os.fork() if False and islinux else -1
if pid <= 0: if pid <= 0:
app = Application(args) app = Application(args)
@ -627,6 +631,8 @@ def main(args=sys.argv):
main = EbookViewer(args[1] if len(args) > 1 else None) main = EbookViewer(args[1] if len(args) > 1 else None)
sys.excepthook = main.unhandled_exception sys.excepthook = main.unhandled_exception
main.show() main.show()
if opts.raise_window:
main.raise_()
with main: with main:
return app.exec_() return app.exec_()
return 0 return 0

View File

@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en'
HTTP server for remote access to the calibre database. HTTP server for remote access to the calibre database.
''' '''
import sys, textwrap, mimetypes, operator, os, re, logging import sys, textwrap, operator, os, re, logging
from itertools import repeat from itertools import repeat
from logging.handlers import RotatingFileHandler from logging.handlers import RotatingFileHandler
from datetime import datetime from datetime import datetime
@ -18,7 +18,7 @@ from PyQt4.Qt import QImage, QApplication, QByteArray, Qt, QBuffer
from calibre.constants import __version__, __appname__ from calibre.constants import __version__, __appname__
from calibre.utils.genshi.template import MarkupTemplate from calibre.utils.genshi.template import MarkupTemplate
from calibre import fit_image from calibre import fit_image, guess_type
from calibre.resources import jquery, server_resources, build_time from calibre.resources import jquery, server_resources, build_time
from calibre.library import server_config as config from calibre.library import server_config as config
from calibre.library.database2 import LibraryDatabase2, FIELD_MAP from calibre.library.database2 import LibraryDatabase2, FIELD_MAP
@ -77,7 +77,7 @@ class LibraryServer(object):
<id>urn:calibre:${record[FM['id']]}</id> <id>urn:calibre:${record[FM['id']]}</id>
<author><name>${authors}</name></author> <author><name>${authors}</name></author>
<updated>${record[FM['timestamp']].strftime('%Y-%m-%dT%H:%M:%S+00:00')}</updated> <updated>${record[FM['timestamp']].strftime('%Y-%m-%dT%H:%M:%S+00:00')}</updated>
<link type="application/epub+zip" href="/get/epub/${record[FM['id']]}" /> <link type="${mimetype}" href="/get/${fmt}/${record[FM['id']]}" />
<link rel="x-stanza-cover-image" type="image/jpeg" href="/get/cover/${record[FM['id']]}" /> <link rel="x-stanza-cover-image" type="image/jpeg" href="/get/cover/${record[FM['id']]}" />
<link rel="x-stanza-cover-image-thumbnail" type="image/jpeg" href="/get/thumb/${record[FM['id']]}" /> <link rel="x-stanza-cover-image-thumbnail" type="image/jpeg" href="/get/thumb/${record[FM['id']]}" />
<content type="xhtml"> <content type="xhtml">
@ -218,7 +218,7 @@ class LibraryServer(object):
fmt = self.db.format(id, format, index_is_id=True, as_file=True, mode='rb') fmt = self.db.format(id, format, index_is_id=True, as_file=True, mode='rb')
if fmt is None: if fmt is None:
raise cherrypy.HTTPError(404, 'book: %d does not have format: %s'%(id, format)) raise cherrypy.HTTPError(404, 'book: %d does not have format: %s'%(id, format))
mt = mimetypes.guess_type('dummy.'+format.lower())[0] mt = guess_type('dummy.'+format.lower())[0]
if mt is None: if mt is None:
mt = 'application/octet-stream' mt = 'application/octet-stream'
cherrypy.response.headers['Content-Type'] = mt cherrypy.response.headers['Content-Type'] = mt
@ -258,8 +258,9 @@ class LibraryServer(object):
for record in iter(self.db): for record in iter(self.db):
r = record[FIELD_MAP['formats']] r = record[FIELD_MAP['formats']]
r = r.upper() if r else '' r = r.upper() if r else ''
if 'EPUB' in r: if 'EPUB' in r or 'PDB' in r:
authors = ' & '.join([i.replace('|', ',') for i in record[FIELD_MAP['authors']].split(',')]) authors = ' & '.join([i.replace('|', ',') for i in
record[FIELD_MAP['authors']].split(',')])
extra = [] extra = []
rating = record[FIELD_MAP['rating']] rating = record[FIELD_MAP['rating']]
if rating > 0: if rating > 0:
@ -270,12 +271,18 @@ class LibraryServer(object):
extra.append('TAGS: %s<br />'%', '.join(tags.split(','))) extra.append('TAGS: %s<br />'%', '.join(tags.split(',')))
series = record[FIELD_MAP['series']] series = record[FIELD_MAP['series']]
if series: if series:
extra.append('SERIES: %s [%d]<br />'%(series, record[FIELD_MAP['series_index']])) extra.append('SERIES: %s [%d]<br />'%(series,
books.append(self.STANZA_ENTRY.generate(authors=authors, record[FIELD_MAP['series_index']]))
record=record, FM=FIELD_MAP, fmt = 'epub' if 'EPUB' in r else 'pdb'
port=self.opts.port, mimetype = guess_type('dummy.'+fmt)[0]
extra = ''.join(extra), books.append(self.STANZA_ENTRY.generate(
).render('xml').decode('utf8')) authors=authors,
record=record, FM=FIELD_MAP,
port=self.opts.port,
extra = ''.join(extra),
mimetype=mimetype,
fmt=fmt,
).render('xml').decode('utf8'))
updated = self.db.last_modified() updated = self.db.last_modified()
cherrypy.response.headers['Last-Modified'] = self.last_modified(updated) cherrypy.response.headers['Last-Modified'] = self.last_modified(updated)

View File

@ -33,9 +33,10 @@ def get_linux_data(version='1.0.0'):
data['title'] = 'Download calibre for linux' data['title'] = 'Download calibre for linux'
data['supported'] = [] data['supported'] = []
for name, title in [ for name, title in [
('ubuntu', 'Ubuntu Jaunty Jackalope'),
('debian', 'Debian Sid'), ('debian', 'Debian Sid'),
('exherbo', 'Exherbo'), ('exherbo', 'Exherbo'),
('foresight', 'Foresight 2.1'),
('ubuntu', 'Ubuntu Jaunty Jackalope'),
]: ]:
data['supported'].append(CoolDistro(name, title, data['supported'].append(CoolDistro(name, title,
prefix='http://calibre.kovidgoyal.net')) prefix='http://calibre.kovidgoyal.net'))

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2009-03-06 17:12+0000\n" "X-Launchpad-Export-Date: 2009-03-11 18:28+0000\n"
"X-Generator: Launchpad (build Unknown)\n" "X-Generator: Launchpad (build Unknown)\n"
"Generated-By: pygettext.py 1.5\n" "Generated-By: pygettext.py 1.5\n"

View File

@ -17,7 +17,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2009-03-06 17:12+0000\n" "X-Launchpad-Export-Date: 2009-03-11 18:28+0000\n"
"X-Generator: Launchpad (build Unknown)\n" "X-Generator: Launchpad (build Unknown)\n"
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41 #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41

View File

@ -8,13 +8,13 @@ msgstr ""
"Project-Id-Version: calibre\n" "Project-Id-Version: calibre\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" "Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2009-02-26 19:09+0000\n" "POT-Creation-Date: 2009-02-26 19:09+0000\n"
"PO-Revision-Date: 2009-03-04 20:00+0000\n" "PO-Revision-Date: 2009-03-11 12:54+0000\n"
"Last-Translator: Plazec <Unknown>\n" "Last-Translator: raduz <raduzator@gmail.com>\n"
"Language-Team: Czech <cs@li.org>\n" "Language-Team: Czech <cs@li.org>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2009-03-06 17:12+0000\n" "X-Launchpad-Export-Date: 2009-03-11 18:28+0000\n"
"X-Generator: Launchpad (build Unknown)\n" "X-Generator: Launchpad (build Unknown)\n"
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41 #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
@ -610,8 +610,8 @@ msgid ""
"Create the output in a zip file. If this option is specified, the --output " "Create the output in a zip file. If this option is specified, the --output "
"should be the name of a file not a directory." "should be the name of a file not a directory."
msgstr "" msgstr ""
"Výstuo je uložen do ZIP souboru. Pokud je zvolena tato volba, položka --" "Výstup je uložen do ZIP souboru. Pokud je zvolena tato volba, položka --"
"output by měly obsahovat název souboru, nikoliv adresáře." "output by měla obsahovat název souboru, nikoliv adresáře."
#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:933 #: /home/kovid/work/calibre/src/calibre/ebooks/html.py:933
msgid "Control the following of links in HTML files." msgid "Control the following of links in HTML files."

View File

@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2009-03-06 17:12+0000\n" "X-Launchpad-Export-Date: 2009-03-11 18:28+0000\n"
"X-Generator: Launchpad (build Unknown)\n" "X-Generator: Launchpad (build Unknown)\n"
"Generated-By: pygettext.py 1.5\n" "Generated-By: pygettext.py 1.5\n"

View File

@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2009-03-06 17:12+0000\n" "X-Launchpad-Export-Date: 2009-03-11 18:28+0000\n"
"X-Generator: Launchpad (build Unknown)\n" "X-Generator: Launchpad (build Unknown)\n"
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41 #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41

View File

@ -17,7 +17,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2009-03-06 17:12+0000\n" "X-Launchpad-Export-Date: 2009-03-11 18:28+0000\n"
"X-Generator: Launchpad (build Unknown)\n" "X-Generator: Launchpad (build Unknown)\n"
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41 #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41

View File

@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: calibre 0.4.22\n" "Project-Id-Version: calibre 0.4.22\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-02-26 19:09+0000\n" "POT-Creation-Date: 2009-02-26 19:09+0000\n"
"PO-Revision-Date: 2009-03-05 20:05+0000\n" "PO-Revision-Date: 2009-03-07 19:24+0000\n"
"Last-Translator: Vincent C. <Unknown>\n" "Last-Translator: Vincent C. <Unknown>\n"
"Language-Team: fr\n" "Language-Team: fr\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2009-03-06 17:12+0000\n" "X-Launchpad-Export-Date: 2009-03-11 18:28+0000\n"
"X-Generator: Launchpad (build Unknown)\n" "X-Generator: Launchpad (build Unknown)\n"
"Generated-By: pygettext.py 1.5\n" "Generated-By: pygettext.py 1.5\n"
@ -4160,6 +4160,29 @@ msgid ""
"expression on a few sample filenames. The group names for the various " "expression on a few sample filenames. The group names for the various "
"metadata entries are documented in tooltips.</p></body></html>" "metadata entries are documented in tooltips.</p></body></html>"
msgstr "" msgstr ""
"Copy text \t\n"
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" "
"\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style "
"type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:'DejaVu Sans'; font-size:10pt; "
"font-weight:400; font-style:normal;\">\n"
"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-"
"right:0px; -qt-block-indent:0; text-indent:0px;\">Indiquer un modèle "
"d'expression régulière à utiliser pour déduire les méta-données à partir des "
"noms de fichiers. </p>\n"
"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-"
"right:0px; -qt-block-indent:0; text-indent:0px;\">Un <a "
"href=\"http://docs.python.org/lib/re-syntax.html\"><span style=\" text-"
"decoration: underline; color:#0000ff;\">renvoi</span></a> sur la syntaxe "
"d'une expression régulière est disponible.</p>\n"
"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-"
"right:0px; -qt-block-indent:0; text-indent:0px;\">Utiliser la fonctionnalité "
"de <span style=\" font-weight:600;\">test</span> ci-dessous pour valider "
"votre expression régulière avec quelques exemples de noms de fichiers. Les "
"groupes pour chacune des entrées de méta-données sont affichés dans les "
"bulles d'aide.</p></body></html>"
#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:104 #: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:104
msgid "Regular &expression" msgid "Regular &expression"
@ -4200,7 +4223,7 @@ msgstr "Pas de correspondance"
#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:111 #: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:111
msgid "Authors:" msgid "Authors:"
msgstr "Auteurs" msgstr "Auteurs:"
#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:112 #: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:112
msgid "Regular expression (?P<authors>)" msgid "Regular expression (?P<authors>)"
@ -4477,12 +4500,12 @@ msgstr "Sauvegarder sur le disque"
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:195 #: /home/kovid/work/calibre/src/calibre/gui2/main.py:195
msgid "Save to disk in a single directory" msgid "Save to disk in a single directory"
msgstr "Sauvegarde vers le disque dans un répertoire" msgstr "Sauvegarder sur le disque dans un seul répetoire"
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:196 #: /home/kovid/work/calibre/src/calibre/gui2/main.py:196
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1261 #: /home/kovid/work/calibre/src/calibre/gui2/main.py:1261
msgid "Save only %s format to disk" msgid "Save only %s format to disk"
msgstr "Sauvegarde seulement le format %s vers le disque" msgstr "Sauvegarder seulement le format %s vers le disque"
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:199 #: /home/kovid/work/calibre/src/calibre/gui2/main.py:199
#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:364 #: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:364
@ -4491,7 +4514,7 @@ msgstr "Visualiser"
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:200 #: /home/kovid/work/calibre/src/calibre/gui2/main.py:200
msgid "View specific format" msgid "View specific format"
msgstr "Afficher le format spécifique" msgstr "Visualiser le format spécifique"
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:217 #: /home/kovid/work/calibre/src/calibre/gui2/main.py:217
msgid "Convert individually" msgid "Convert individually"
@ -4904,11 +4927,11 @@ msgstr "Réinitialisation de la recherche rapide"
#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:347 #: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:347
msgid "Match any" msgid "Match any"
msgstr "" msgstr "Aucune correspondance"
#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:348 #: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:348
msgid "Match all" msgid "Match all"
msgstr "" msgstr "Toutes les correspondances"
#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:349 #: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:349
msgid "Sort by &popularity" msgid "Sort by &popularity"

View File

@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2009-03-06 17:12+0000\n" "X-Launchpad-Export-Date: 2009-03-11 18:28+0000\n"
"X-Generator: Launchpad (build Unknown)\n" "X-Generator: Launchpad (build Unknown)\n"
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41 #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41

View File

@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2009-03-06 17:12+0000\n" "X-Launchpad-Export-Date: 2009-03-11 18:28+0000\n"
"X-Generator: Launchpad (build Unknown)\n" "X-Generator: Launchpad (build Unknown)\n"
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41 #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41

View File

@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2009-03-06 17:12+0000\n" "X-Launchpad-Export-Date: 2009-03-11 18:28+0000\n"
"X-Generator: Launchpad (build Unknown)\n" "X-Generator: Launchpad (build Unknown)\n"
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41 #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41

View File

@ -15,7 +15,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2009-03-06 17:12+0000\n" "X-Launchpad-Export-Date: 2009-03-11 18:28+0000\n"
"X-Generator: Launchpad (build Unknown)\n" "X-Generator: Launchpad (build Unknown)\n"
"Generated-By: pygettext.py 1.5\n" "Generated-By: pygettext.py 1.5\n"

View File

@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2009-03-06 17:12+0000\n" "X-Launchpad-Export-Date: 2009-03-11 18:28+0000\n"
"X-Generator: Launchpad (build Unknown)\n" "X-Generator: Launchpad (build Unknown)\n"
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41 #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41

View File

@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2009-03-06 17:12+0000\n" "X-Launchpad-Export-Date: 2009-03-11 18:28+0000\n"
"X-Generator: Launchpad (build Unknown)\n" "X-Generator: Launchpad (build Unknown)\n"
"Generated-By: pygettext.py 1.5\n" "Generated-By: pygettext.py 1.5\n"

View File

@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2009-03-06 17:12+0000\n" "X-Launchpad-Export-Date: 2009-03-11 18:28+0000\n"
"X-Generator: Launchpad (build Unknown)\n" "X-Generator: Launchpad (build Unknown)\n"
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41 #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41

View File

@ -8,13 +8,13 @@ msgstr ""
"Project-Id-Version: calibre\n" "Project-Id-Version: calibre\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" "Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2009-02-26 19:09+0000\n" "POT-Creation-Date: 2009-02-26 19:09+0000\n"
"PO-Revision-Date: 2009-01-30 09:03+0000\n" "PO-Revision-Date: 2009-03-11 01:37+0000\n"
"Last-Translator: Andrzej MoST (Marcin Ostajewski) <Unknown>\n" "Last-Translator: Andrzej MoST (Marcin Ostajewski) <Unknown>\n"
"Language-Team: Polish <pl@li.org>\n" "Language-Team: Polish <pl@li.org>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2009-03-06 17:12+0000\n" "X-Launchpad-Export-Date: 2009-03-11 18:28+0000\n"
"X-Generator: Launchpad (build Unknown)\n" "X-Generator: Launchpad (build Unknown)\n"
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41 #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
@ -159,7 +159,7 @@ msgstr "Odczyt metadanych z e-booków w archiwach RAR"
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:227 #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:227
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:237 #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:237
msgid "Set metadata in %s files" msgid "Set metadata in %s files"
msgstr "" msgstr "Ustaw metadane w %s plikach"
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:28 #: /home/kovid/work/calibre/src/calibre/customize/ui.py:28
msgid "Installed plugins" msgid "Installed plugins"
@ -481,7 +481,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:221 #: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:221
msgid "Do not force text to be justified in output." msgid "Do not force text to be justified in output."
msgstr "" msgstr "Nie wymuszaj wyjustowania tekstu w pliku wynikowym."
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:223 #: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:223
msgid "" msgid ""
@ -1216,7 +1216,7 @@ msgstr "Wydrukuj wygenerowany HTML do wyjścia standardowego i zamknij."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/fb2/convert_from.py:30 #: /home/kovid/work/calibre/src/calibre/ebooks/lrf/fb2/convert_from.py:30
msgid "Keep generated HTML files after completing conversion to LRF." msgid "Keep generated HTML files after completing conversion to LRF."
msgstr "" msgstr "Zachowaj wygenerowany plik HTML po konwersji do LRF."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/feeds/convert_from.py:20 #: /home/kovid/work/calibre/src/calibre/ebooks/lrf/feeds/convert_from.py:20
msgid "Options to control the behavior of feeds2disk" msgid "Options to control the behavior of feeds2disk"
@ -1450,7 +1450,7 @@ msgstr "Wypakuj miniaturkę z pliku LRF"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:606 #: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:606
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/mobi.py:191 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/mobi.py:191
msgid "Set the publisher" msgid "Set the publisher"
msgstr "" msgstr "Ustaw wydawcę"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:607 #: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:607
msgid "Set the book classification" msgid "Set the book classification"
@ -1715,7 +1715,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/mobi.py:193 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/mobi.py:193
msgid "Set the ISBN" msgid "Set the ISBN"
msgstr "" msgstr "Ustaw ISBN"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/opf2.py:1014 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/opf2.py:1014
msgid "Set the dc:language field" msgid "Set the dc:language field"

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2009-03-06 17:12+0000\n" "X-Launchpad-Export-Date: 2009-03-11 18:28+0000\n"
"X-Generator: Launchpad (build Unknown)\n" "X-Generator: Launchpad (build Unknown)\n"
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41 #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41

View File

@ -13,7 +13,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2009-03-06 17:12+0000\n" "X-Launchpad-Export-Date: 2009-03-11 18:28+0000\n"
"X-Generator: Launchpad (build Unknown)\n" "X-Generator: Launchpad (build Unknown)\n"
"X-Poedit-Country: RUSSIAN FEDERATION\n" "X-Poedit-Country: RUSSIAN FEDERATION\n"
"X-Poedit-Language: Russian\n" "X-Poedit-Language: Russian\n"

View File

@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2009-03-06 17:12+0000\n" "X-Launchpad-Export-Date: 2009-03-11 18:28+0000\n"
"X-Generator: Launchpad (build Unknown)\n" "X-Generator: Launchpad (build Unknown)\n"
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41 #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41

View File

@ -13,7 +13,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2009-03-06 17:12+0000\n" "X-Launchpad-Export-Date: 2009-03-11 18:28+0000\n"
"X-Generator: Launchpad (build Unknown)\n" "X-Generator: Launchpad (build Unknown)\n"
"Generated-By: pygettext.py 1.5\n" "Generated-By: pygettext.py 1.5\n"

View File

@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2009-03-06 17:12+0000\n" "X-Launchpad-Export-Date: 2009-03-11 18:28+0000\n"
"X-Generator: Launchpad (build Unknown)\n" "X-Generator: Launchpad (build Unknown)\n"
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41 #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41

View File

@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2009-03-06 17:12+0000\n" "X-Launchpad-Export-Date: 2009-03-11 18:28+0000\n"
"X-Generator: Launchpad (build Unknown)\n" "X-Generator: Launchpad (build Unknown)\n"
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41 #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41

View File

@ -0,0 +1,443 @@
"""PyRSS2Gen - A Python library for generating RSS 2.0 feeds."""
__name__ = "PyRSS2Gen"
__version__ = (1, 0, 0)
__author__ = "Andrew Dalke <dalke@dalkescientific.com>"
_generator_name = __name__ + "-" + ".".join(map(str, __version__))
import datetime
# Could make this the base class; will need to add 'publish'
class WriteXmlMixin:
def write_xml(self, outfile, encoding = "iso-8859-1"):
from xml.sax import saxutils
handler = saxutils.XMLGenerator(outfile, encoding)
handler.startDocument()
self.publish(handler)
handler.endDocument()
def to_xml(self, encoding = "iso-8859-1"):
try:
import cStringIO as StringIO
except ImportError:
import StringIO
f = StringIO.StringIO()
self.write_xml(f, encoding)
return f.getvalue()
def _element(handler, name, obj, d = {}):
if isinstance(obj, basestring) or obj is None:
# special-case handling to make the API easier
# to use for the common case.
handler.startElement(name, d)
if obj is not None:
handler.characters(obj)
handler.endElement(name)
else:
# It better know how to emit the correct XML.
obj.publish(handler)
def _opt_element(handler, name, obj):
if obj is None:
return
_element(handler, name, obj)
def _format_date(dt):
"""convert a datetime into an RFC 822 formatted date
Input date must be in GMT.
"""
# Looks like:
# Sat, 07 Sep 2002 00:00:01 GMT
# Can't use strftime because that's locale dependent
#
# Isn't there a standard way to do this for Python? The
# rfc822 and email.Utils modules assume a timestamp. The
# following is based on the rfc822 module.
return "%s, %02d %s %04d %02d:%02d:%02d GMT" % (
["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"][dt.weekday()],
dt.day,
["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][dt.month-1],
dt.year, dt.hour, dt.minute, dt.second)
##
# A couple simple wrapper objects for the fields which
# take a simple value other than a string.
class IntElement:
"""implements the 'publish' API for integers
Takes the tag name and the integer value to publish.
(Could be used for anything which uses str() to be published
to text for XML.)
"""
element_attrs = {}
def __init__(self, name, val):
self.name = name
self.val = val
def publish(self, handler):
handler.startElement(self.name, self.element_attrs)
handler.characters(str(self.val))
handler.endElement(self.name)
class DateElement:
"""implements the 'publish' API for a datetime.datetime
Takes the tag name and the datetime to publish.
Converts the datetime to RFC 2822 timestamp (4-digit year).
"""
def __init__(self, name, dt):
self.name = name
self.dt = dt
def publish(self, handler):
_element(handler, self.name, _format_date(self.dt))
####
class Category:
"""Publish a category element"""
def __init__(self, category, domain = None):
self.category = category
self.domain = domain
def publish(self, handler):
d = {}
if self.domain is not None:
d["domain"] = self.domain
_element(handler, "category", self.category, d)
class Cloud:
"""Publish a cloud"""
def __init__(self, domain, port, path,
registerProcedure, protocol):
self.domain = domain
self.port = port
self.path = path
self.registerProcedure = registerProcedure
self.protocol = protocol
def publish(self, handler):
_element(handler, "cloud", None, {
"domain": self.domain,
"port": str(self.port),
"path": self.path,
"registerProcedure": self.registerProcedure,
"protocol": self.protocol})
class Image:
"""Publish a channel Image"""
element_attrs = {}
def __init__(self, url, title, link,
width = None, height = None, description = None):
self.url = url
self.title = title
self.link = link
self.width = width
self.height = height
self.description = description
def publish(self, handler):
handler.startElement("image", self.element_attrs)
_element(handler, "url", self.url)
_element(handler, "title", self.title)
_element(handler, "link", self.link)
width = self.width
if isinstance(width, int):
width = IntElement("width", width)
_opt_element(handler, "width", width)
height = self.height
if isinstance(height, int):
height = IntElement("height", height)
_opt_element(handler, "height", height)
_opt_element(handler, "description", self.description)
handler.endElement("image")
class Guid:
"""Publish a guid
Defaults to being a permalink, which is the assumption if it's
omitted. Hence strings are always permalinks.
"""
def __init__(self, guid, isPermaLink = 1):
self.guid = guid
self.isPermaLink = isPermaLink
def publish(self, handler):
d = {}
if self.isPermaLink:
d["isPermaLink"] = "true"
else:
d["isPermaLink"] = "false"
_element(handler, "guid", self.guid, d)
class TextInput:
"""Publish a textInput
Apparently this is rarely used.
"""
element_attrs = {}
def __init__(self, title, description, name, link):
self.title = title
self.description = description
self.name = name
self.link = link
def publish(self, handler):
handler.startElement("textInput", self.element_attrs)
_element(handler, "title", self.title)
_element(handler, "description", self.description)
_element(handler, "name", self.name)
_element(handler, "link", self.link)
handler.endElement("textInput")
class Enclosure:
"""Publish an enclosure"""
def __init__(self, url, length, type):
self.url = url
self.length = length
self.type = type
def publish(self, handler):
_element(handler, "enclosure", None,
{"url": self.url,
"length": str(self.length),
"type": self.type,
})
class Source:
"""Publish the item's original source, used by aggregators"""
def __init__(self, name, url):
self.name = name
self.url = url
def publish(self, handler):
_element(handler, "source", self.name, {"url": self.url})
class SkipHours:
"""Publish the skipHours
This takes a list of hours, as integers.
"""
element_attrs = {}
def __init__(self, hours):
self.hours = hours
def publish(self, handler):
if self.hours:
handler.startElement("skipHours", self.element_attrs)
for hour in self.hours:
_element(handler, "hour", str(hour))
handler.endElement("skipHours")
class SkipDays:
"""Publish the skipDays
This takes a list of days as strings.
"""
element_attrs = {}
def __init__(self, days):
self.days = days
def publish(self, handler):
if self.days:
handler.startElement("skipDays", self.element_attrs)
for day in self.days:
_element(handler, "day", day)
handler.endElement("skipDays")
class RSS2(WriteXmlMixin):
"""The main RSS class.
Stores the channel attributes, with the "category" elements under
".categories" and the RSS items under ".items".
"""
rss_attrs = {"version": "2.0"}
element_attrs = {}
def __init__(self,
title,
link,
description,
language = None,
copyright = None,
managingEditor = None,
webMaster = None,
pubDate = None, # a datetime, *in* *GMT*
lastBuildDate = None, # a datetime
categories = None, # list of strings or Category
generator = _generator_name,
docs = "http://blogs.law.harvard.edu/tech/rss",
cloud = None, # a Cloud
ttl = None, # integer number of minutes
image = None, # an Image
rating = None, # a string; I don't know how it's used
textInput = None, # a TextInput
skipHours = None, # a SkipHours with a list of integers
skipDays = None, # a SkipDays with a list of strings
items = None, # list of RSSItems
):
self.title = title
self.link = link
self.description = description
self.language = language
self.copyright = copyright
self.managingEditor = managingEditor
self.webMaster = webMaster
self.pubDate = pubDate
self.lastBuildDate = lastBuildDate
if categories is None:
categories = []
self.categories = categories
self.generator = generator
self.docs = docs
self.cloud = cloud
self.ttl = ttl
self.image = image
self.rating = rating
self.textInput = textInput
self.skipHours = skipHours
self.skipDays = skipDays
if items is None:
items = []
self.items = items
def publish(self, handler):
handler.startElement("rss", self.rss_attrs)
handler.startElement("channel", self.element_attrs)
_element(handler, "title", self.title)
_element(handler, "link", self.link)
_element(handler, "description", self.description)
self.publish_extensions(handler)
_opt_element(handler, "language", self.language)
_opt_element(handler, "copyright", self.copyright)
_opt_element(handler, "managingEditor", self.managingEditor)
_opt_element(handler, "webMaster", self.webMaster)
pubDate = self.pubDate
if isinstance(pubDate, datetime.datetime):
pubDate = DateElement("pubDate", pubDate)
_opt_element(handler, "pubDate", pubDate)
lastBuildDate = self.lastBuildDate
if isinstance(lastBuildDate, datetime.datetime):
lastBuildDate = DateElement("lastBuildDate", lastBuildDate)
_opt_element(handler, "lastBuildDate", lastBuildDate)
for category in self.categories:
if isinstance(category, basestring):
category = Category(category)
category.publish(handler)
_opt_element(handler, "generator", self.generator)
_opt_element(handler, "docs", self.docs)
if self.cloud is not None:
self.cloud.publish(handler)
ttl = self.ttl
if isinstance(self.ttl, int):
ttl = IntElement("ttl", ttl)
_opt_element(handler, "tt", ttl)
if self.image is not None:
self.image.publish(handler)
_opt_element(handler, "rating", self.rating)
if self.textInput is not None:
self.textInput.publish(handler)
if self.skipHours is not None:
self.skipHours.publish(handler)
if self.skipDays is not None:
self.skipDays.publish(handler)
for item in self.items:
item.publish(handler)
handler.endElement("channel")
handler.endElement("rss")
def publish_extensions(self, handler):
# Derived classes can hook into this to insert
# output after the three required fields.
pass
class RSSItem(WriteXmlMixin):
"""Publish an RSS Item"""
element_attrs = {}
def __init__(self,
title = None, # string
link = None, # url as string
description = None, # string
author = None, # email address as string
categories = None, # list of string or Category
comments = None, # url as string
enclosure = None, # an Enclosure
guid = None, # a unique string
pubDate = None, # a datetime
source = None, # a Source
):
if title is None and description is None:
raise TypeError(
"must define at least one of 'title' or 'description'")
self.title = title
self.link = link
self.description = description
self.author = author
if categories is None:
categories = []
self.categories = categories
self.comments = comments
self.enclosure = enclosure
self.guid = guid
self.pubDate = pubDate
self.source = source
# It sure does get tedious typing these names three times...
def publish(self, handler):
handler.startElement("item", self.element_attrs)
_opt_element(handler, "title", self.title)
_opt_element(handler, "link", self.link)
self.publish_extensions(handler)
_opt_element(handler, "description", self.description)
_opt_element(handler, "author", self.author)
for category in self.categories:
if isinstance(category, basestring):
category = Category(category)
category.publish(handler)
_opt_element(handler, "comments", self.comments)
if self.enclosure is not None:
self.enclosure.publish(handler)
_opt_element(handler, "guid", self.guid)
pubDate = self.pubDate
if isinstance(pubDate, datetime.datetime):
pubDate = DateElement("pubDate", pubDate)
_opt_element(handler, "pubDate", pubDate)
if self.source is not None:
self.source.publish(handler)
handler.endElement("item")
def publish_extensions(self, handler):
# Derived classes can hook into this to insert
# output after the title and link elements
pass

View File

@ -5,7 +5,7 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
Builtin recipes. Builtin recipes.
''' '''
recipe_modules = ['recipe_' + r for r in ( recipe_modules = ['recipe_' + r for r in (
'newsweek', 'atlantic', 'economist', 'portfolio', 'newsweek', 'atlantic', 'economist', 'portfolio', 'the_register',
'nytimes', 'usatoday', 'outlook_india', 'bbc', 'greader', 'wsj', 'nytimes', 'usatoday', 'outlook_india', 'bbc', 'greader', 'wsj',
'wired', 'globe_and_mail', 'smh', 'espn', 'business_week', 'miami_herald', 'wired', 'globe_and_mail', 'smh', 'espn', 'business_week', 'miami_herald',
'ars_technica', 'upi', 'new_yorker', 'irish_times', 'iht', 'lanacion', 'ars_technica', 'upi', 'new_yorker', 'irish_times', 'iht', 'lanacion',
@ -86,11 +86,15 @@ def compile_recipe(src):
match = re.search(r'coding[:=]\s*([-\w.]+)', src[:200]) match = re.search(r'coding[:=]\s*([-\w.]+)', src[:200])
enc = match.group(1) if match else 'utf-8' enc = match.group(1) if match else 'utf-8'
src = src.decode(enc) src = src.decode(enc)
src = re.sub(r'from __future__.*', '', src)
f = open(temp, 'wb') f = open(temp, 'wb')
src = 'from %s.web.feeds.news import BasicNewsRecipe, AutomaticNewsRecipe\n'%__appname__ + src src = 'from %s.web.feeds.news import BasicNewsRecipe, AutomaticNewsRecipe\n'%__appname__ + src
src = 'from %s.ebooks.lrf.web.profiles import DefaultProfile, FullContentProfile\n'%__appname__ + src src = 'from %s.ebooks.lrf.web.profiles import DefaultProfile, FullContentProfile\n'%__appname__ + src
src = '# coding: utf-8\n' + src src = '# coding: utf-8\n' + src
f.write(src.replace('from libprs500', 'from calibre').encode('utf-8')) src = 'from __future__ import with_statement\n' + src
src = src.replace('from libprs500', 'from calibre').encode('utf-8')
f.write(src)
f.close() f.close()
module = imp.find_module(temp.namebase, [temp.dirname()]) module = imp.find_module(temp.namebase, [temp.dirname()])
module = imp.load_module(temp.namebase, *module) module = imp.load_module(temp.namebase, *module)

View File

@ -13,6 +13,7 @@ class SecurityWatch(BasicNewsRecipe):
filter_regexps = [r'ad\.doubleclick'] filter_regexps = [r'ad\.doubleclick']
filter_regexps = [r'advert'] filter_regexps = [r'advert']
language = _('English') language = _('English')
extra_css = 'div {text-align:left}'
remove_tags = [dict(id='topBannerContainer'), remove_tags = [dict(id='topBannerContainer'),
dict(id='topBannerSmall'), dict(id='topBannerSmall'),
@ -30,3 +31,7 @@ class SecurityWatch(BasicNewsRecipe):
feeds = [(u'securitywatch', u'http://feeds.ziffdavisenterprise.com/RSS/security_watch/')] feeds = [(u'securitywatch', u'http://feeds.ziffdavisenterprise.com/RSS/security_watch/')]
def postprocess_html(self, soup, first_fetch):
for t in soup.findAll(['table', 'tr', 'td']):
t.name = 'div'
return soup

View File

@ -0,0 +1,19 @@
from calibre.web.feeds.recipes import BasicNewsRecipe
class TheRegister(BasicNewsRecipe):
title = u'The Register'
__author__ = 'vgrama'
language = _('English')
oldest_article = 1
max_articles_per_feed = 100
use_embedded_content = False
feeds = [(u'Register', u'http://www.theregister.co.uk/headlines.atom')]
remove_tags = [
dict(name='div', attrs={'id':'leader'}),
dict(name='div', attrs={'id':'footer'}),
dict(name='div', attrs={'id':'masthead'})]
def print_version(self, url):
return '%s/print.html' % url

View File

@ -4,7 +4,8 @@ __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import shutil, os, glob, re, cStringIO, sys, tempfile, time, textwrap, socket, \ import shutil, os, glob, re, cStringIO, sys, tempfile, time, textwrap, socket, \
struct struct, subprocess
from datetime import datetime
from setuptools.command.build_py import build_py as _build_py, convert_path from setuptools.command.build_py import build_py as _build_py, convert_path
from distutils.core import Command from distutils.core import Command
from subprocess import check_call, call, Popen from subprocess import check_call, call, Popen
@ -664,6 +665,7 @@ class stage3(OptionlessCommand):
('upload_installers', None), ('upload_installers', None),
('upload_user_manual', None), ('upload_user_manual', None),
('upload_to_pypi', None), ('upload_to_pypi', None),
('upload_rss', None),
] ]
@classmethod @classmethod
@ -706,3 +708,66 @@ class upload(OptionlessCommand):
('stage2', None), ('stage2', None),
('stage3', None) ('stage3', None)
] ]
class upload_rss(OptionlessCommand):
from bzrlib import log as blog
class ChangelogFormatter(blog.LogFormatter):
supports_tags = True
supports_merge_revisions = False
def __init__(self, num_of_versions=20):
from calibre.utils.rss_gen import RSS2
self.num_of_versions = num_of_versions
self.rss = RSS2(
title = 'calibre releases',
link = 'http://calibre.kovidgoyal.net/wiki/Changelog',
description = 'Latest release of calibre',
lastBuildDate = datetime.utcnow()
)
self.current_entry = None
def log_revision(self, r):
from calibre.utils.rss_gen import RSSItem, Guid
if len(self.rss.items) > self.num_of_versions-1:
return
msg = r.rev.message
match = re.match(r'version\s+(\d+\.\d+.\d+)', msg)
if match:
if self.current_entry is not None:
mkup = '<div><ul>%s</ul></div>'
self.current_entry.description = mkup%(''.join(
self.current_entry.description))
self.rss.items.append(self.current_entry)
timestamp = r.rev.timezone + r.rev.timestamp
self.current_entry = RSSItem(
title = 'calibre %s released'%match.group(1),
link = 'http://calibre.kovidgoyal.net/download',
guid = Guid(match.group(), False),
pubDate = datetime(*time.gmtime(timestamp)[:6]),
description = []
)
elif self.current_entry is not None:
if re.search(r'[a-zA-Z]', msg) and len(msg.strip()) > 5:
if 'translation' not in msg and not msg.startswith('IGN'):
msg = msg.replace('<', '&lt;').replace('>', '&gt;')
msg = re.sub('#(\d+)', r'<a href="http://calibre.kovidgoyal.net/ticket/\1">#\1</a>',
msg)
self.current_entry.description.append(
'<li>%s</li>'%msg.strip())
def run(self):
from bzrlib import log, branch
bzr_path = os.path.expanduser('~/work/calibre')
b = branch.Branch.open(bzr_path)
lf = upload_rss.ChangelogFormatter()
log.show_log(b, lf)
lf.rss.write_xml(open('/tmp/releases.xml', 'wb'))
subprocess.check_call('scp /tmp/releases.xml divok:/var/www/calibre.kovidgoyal.net/htdocs/downloads'.split())