Sync to trunk

This commit is contained in:
John Schember 2009-02-13 19:36:59 -05:00
commit e8226b8479
59 changed files with 8429 additions and 7641 deletions

View File

@ -38,6 +38,10 @@ def freeze():
'/usr/lib/libxml2.so.2', '/usr/lib/libxml2.so.2',
'/usr/lib/libxslt.so.1', '/usr/lib/libxslt.so.1',
'/usr/lib/libxslt.so.1', '/usr/lib/libxslt.so.1',
'/usr/lib/libgthread-2.0.so.0',
'/usr/lib/libglib-2.0.so.0',
'/usr/lib/gcc/i686-pc-linux-gnu/4.3.3/libstdc++.so.6',
'/usr/lib/libpng12.so.0',
'/usr/lib/libexslt.so.0', '/usr/lib/libexslt.so.0',
'/usr/lib/libMagickWand.so', '/usr/lib/libMagickWand.so',
'/usr/lib/libMagickCore.so', '/usr/lib/libMagickCore.so',

View File

@ -69,7 +69,7 @@ def sanitize_file_name(name, substitute='_', as_unicode=False):
one = re.sub(r'^\.+$', '_', one) one = re.sub(r'^\.+$', '_', one)
if as_unicode: if as_unicode:
one = one.decode(filesystem_encoding) one = one.decode(filesystem_encoding)
return one return one.replace('..', '_')
class CommandLineError(Exception): class CommandLineError(Exception):
@ -382,8 +382,10 @@ def walk(dir):
for f in record[-1]: for f in record[-1]:
yield os.path.join(record[0], f) yield os.path.join(record[0], f)
def strftime(fmt, t=time.localtime()): def strftime(fmt, t=None):
''' A version of strtime that returns unicode strings. ''' ''' A version of strtime that returns unicode strings. '''
if t is None:
t = time.localtime()
if iswindows: if iswindows:
if isinstance(fmt, unicode): if isinstance(fmt, unicode):
fmt = fmt.encode('mbcs') fmt = fmt.encode('mbcs')

View File

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

View File

@ -32,7 +32,7 @@ class PRS505(Device):
BCD = [0x229] #: Needed to disambiguate 505 and 700 on linux BCD = [0x229] #: Needed to disambiguate 505 and 700 on linux
PRODUCT_NAME = 'PRS-505' PRODUCT_NAME = 'PRS-505'
VENDOR_NAME = 'SONY' VENDOR_NAME = 'SONY'
FORMATS = ['lrf', 'epub', 'lrx', 'rtf', 'pdf', 'txt'] FORMATS = ['epub', 'lrf', 'lrx', 'rtf', 'pdf', 'txt']
MEDIA_XML = 'database/cache/media.xml' MEDIA_XML = 'database/cache/media.xml'
CACHE_XML = 'Sony Reader/database/cache.xml' CACHE_XML = 'Sony Reader/database/cache.xml'

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?python <?python
from uuid import uuid4 from uuid import uuid4
import re
?> ?>
<ncx version="2005-1" <ncx version="2005-1"
xml:lang="en" xml:lang="en"
@ -19,7 +20,7 @@ from uuid import uuid4
<py:def function="navpoint(np, level)"> <py:def function="navpoint(np, level)">
${'%*s'%(4*level,'')}<navPoint id="${str(uuid4())}" playOrder="${str(np.play_order)}"> ${'%*s'%(4*level,'')}<navPoint id="${str(uuid4())}" playOrder="${str(np.play_order)}">
${'%*s'%(4*level,'')}<navLabel> ${'%*s'%(4*level,'')}<navLabel>
${'%*s'%(4*level,'')}<text>${np.text}</text> ${'%*s'%(4*level,'')}<text>${re.sub(r'\s+', ' ', np.text)}</text>
${'%*s'%(4*level,'')}</navLabel> ${'%*s'%(4*level,'')}</navLabel>
${'%*s'%(4*level,'')}<content src="${unicode(np.href)+(('#' + unicode(np.fragment)) if np.fragment else '')}" /> ${'%*s'%(4*level,'')}<content src="${unicode(np.href)+(('#' + unicode(np.fragment)) if np.fragment else '')}" />
<py:for each="np2 in np">${navpoint(np2, level+1)}</py:for> <py:for each="np2 in np">${navpoint(np2, level+1)}</py:for>

View File

@ -186,6 +186,8 @@ class MobiReader(object):
self.processed_html = self.processed_html.decode(self.book_header.codec, 'ignore') self.processed_html = self.processed_html.decode(self.book_header.codec, 'ignore')
for pat in ENCODING_PATS: for pat in ENCODING_PATS:
self.processed_html = pat.sub('', self.processed_html) self.processed_html = pat.sub('', self.processed_html)
self.processed_html = re.sub(r'&(\S+?);', entity_to_unicode,
self.processed_html)
self.extract_images(processed_records, output_dir) self.extract_images(processed_records, output_dir)
self.replace_page_breaks() self.replace_page_breaks()
self.cleanup_html() self.cleanup_html()
@ -271,6 +273,8 @@ class MobiReader(object):
for key in tag.attrib.keys(): for key in tag.attrib.keys():
tag.attrib.pop(key) tag.attrib.pop(key)
continue continue
if tag.tag == 'pre' and not tag.text:
tag.tag = 'div'
styles, attrib = [], tag.attrib styles, attrib = [], tag.attrib
if attrib.has_key('style'): if attrib.has_key('style'):
style = attrib.pop('style').strip() style = attrib.pop('style').strip()
@ -452,6 +456,7 @@ class MobiReader(object):
pos = end pos = end
self.processed_html += self.mobi_html[pos:] self.processed_html += self.mobi_html[pos:]
def extract_images(self, processed_records, output_dir): def extract_images(self, processed_records, output_dir):
if self.verbose: if self.verbose:
print 'Extracting images...' print 'Extracting images...'

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

View File

@ -245,7 +245,7 @@ class BooksModel(QAbstractTableModel):
if num > 0: if num > 0:
self.beginInsertRows(QModelIndex(), 0, num-1) self.beginInsertRows(QModelIndex(), 0, num-1)
self.endInsertRows() self.endInsertRows()
self.count_changed() self.count_changed()
def search(self, text, refinement, reset=True): def search(self, text, refinement, reset=True):
self.db.search(text) self.db.search(text)

View File

@ -330,12 +330,17 @@ class Main(MainWindow, Ui_MainWindow):
self.cover_flow.setVisible(False) self.cover_flow.setVisible(False)
if not config['separate_cover_flow']: if not config['separate_cover_flow']:
self.library.layout().addWidget(self.cover_flow) self.library.layout().addWidget(self.cover_flow)
self.connect(self.cover_flow, SIGNAL('currentChanged(int)'), self.sync_cf_to_listview) self.connect(self.cover_flow, SIGNAL('currentChanged(int)'),
self.connect(self.cover_flow, SIGNAL('itemActivated(int)'), self.show_book_info) self.sync_cf_to_listview)
self.connect(self.status_bar.cover_flow_button, SIGNAL('toggled(bool)'), self.toggle_cover_flow) self.connect(self.cover_flow, SIGNAL('itemActivated(int)'),
self.connect(self.cover_flow, SIGNAL('stop()'), self.status_bar.cover_flow_button.toggle) self.show_book_info)
QObject.connect(self.library_view.selectionModel(), SIGNAL('currentRowChanged(QModelIndex, QModelIndex)'), self.connect(self.status_bar.cover_flow_button,
self.sync_cf_to_listview) SIGNAL('toggled(bool)'), self.toggle_cover_flow)
self.connect(self.cover_flow, SIGNAL('stop()'),
self.status_bar.cover_flow_button.toggle)
QObject.connect(self.library_view.selectionModel(),
SIGNAL('currentRowChanged(QModelIndex, QModelIndex)'),
self.sync_cf_to_listview)
self.db_images = DatabaseImages(self.library_view.model()) self.db_images = DatabaseImages(self.library_view.model())
self.cover_flow.setImages(self.db_images) self.cover_flow.setImages(self.db_images)
else: else:
@ -482,7 +487,8 @@ class Main(MainWindow, Ui_MainWindow):
if not hasattr(index, 'row') and self.library_view.currentIndex().row() != index: if not hasattr(index, 'row') and self.library_view.currentIndex().row() != index:
index = self.library_view.model().index(index, 0) index = self.library_view.model().index(index, 0)
self.library_view.setCurrentIndex(index) self.library_view.setCurrentIndex(index)
if hasattr(index, 'row') and self.cover_flow.isVisible() and self.cover_flow.currentSlide() != index.row(): if hasattr(index, 'row') and self.cover_flow.isVisible() and \
self.cover_flow.currentSlide() != index.row():
self.cover_flow.setCurrentSlide(index.row()) self.cover_flow.setCurrentSlide(index.row())
def another_instance_wants_to_talk(self, msg): def another_instance_wants_to_talk(self, msg):
@ -709,6 +715,7 @@ class Main(MainWindow, Ui_MainWindow):
t.process_duplicates() t.process_duplicates()
if t.number_of_books_added > 0: if t.number_of_books_added > 0:
self.library_view.model().books_added(t.number_of_books_added) self.library_view.model().books_added(t.number_of_books_added)
self.db_images.reset()
def upload_books(self, files, names, metadata, on_card=False, memory=None): def upload_books(self, files, names, metadata, on_card=False, memory=None):
''' '''

View File

@ -28,7 +28,7 @@ What formats does |app| support conversion to/from?
| | | | | | | | | | | |
| | LIT | ✔ | ✔ | ✔ | | | LIT | ✔ | ✔ | ✔ |
| | | | | | | | | | | |
| | PRC | ✔ | ✔ | ✔ | | | PRC** | ✔ | ✔ | ✔ |
| | | | | | | | | | | |
| | EPUB | ✔ | ✔ | ✔ | | | EPUB | ✔ | ✔ | ✔ |
| | | | | | | | | | | |
@ -49,6 +49,7 @@ What formats does |app| support conversion to/from?
| | LRS | | ✔ | | | | LRS | | ✔ | |
+-------------------+--------+------------------+-----------------------+-----------------------+ +-------------------+--------+------------------+-----------------------+-----------------------+
** PRC is a generic format, |app| supports PRC files with TextRead and MOBIBook headers
What are the best source formats to convert? What are the best source formats to convert?
@ -146,7 +147,7 @@ When you first run |app|, it will ask you for a folder in which to store your bo
Why doesn't |app| let me store books in my own directory structure? Why doesn't |app| let me store books in my own directory structure?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The whole point if |app|'s library management features is that they provide an interface for locating books that is *much* more efficient than any possible directory scheme you could come up with for your collection. Indeed, once you become comfortable using |app|'s interface to find, sort and browse your collection, you wont ever feel the need to hunt through the files on your disk to find a book again. By managing books in its own directory struture of Author -> Title -> Book files, |app| is able to achieve a high level of reliability and standardization. The whole point of |app|'s library management features is that they provide an interface for locating books that is *much* more efficient than any possible directory scheme you could come up with for your collection. Indeed, once you become comfortable using |app|'s interface to find, sort and browse your collection, you wont ever feel the need to hunt through the files on your disk to find a book again. By managing books in its own directory struture of Author -> Title -> Book files, |app| is able to achieve a high level of reliability and standardization.
Why doesn't |app| have a column for foo? Why doesn't |app| have a column for foo?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -1,419 +1,386 @@
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>' __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
import re
from pkg_resources import resource_filename
from trac.core import Component, implements
from trac.web.chrome import INavigationContributor, ITemplateProvider, add_stylesheet
from trac.web.main import IRequestHandler
from trac.util import Markup
__appname__ = 'calibre' __appname__ = 'calibre'
DOWNLOAD_DIR = '/var/www/calibre.kovidgoyal.net/htdocs/downloads' import re, textwrap
MOBILEREAD = 'https://dev.mobileread.com/dist/kovid/calibre/'
class OS(dict): DEPENDENCIES = [
"""Dictionary with a default value for unknown keys.""" #(Generic, version, gentoo, ubuntu, fedora)
def __init__(self, dict): ('python', '2.5', None, None, None),
self.update(dict) ('setuptools', '0.6c5', 'setuptools', 'python-setuptools', 'python-setuptools-devel'),
if not dict.has_key('img'): ('Python Imaging Library', '1.1.6', 'imaging', 'python-imaging', 'python-imaging'),
self['img'] = self['name'] ('libusb', '0.1.12', None, None, None),
('Qt', '4.4.0', 'qt', 'libqt4-core libqt4-gui', 'qt4'),
('PyQt', '4.4.2', 'PyQt4', 'python-qt4', 'PyQt4'),
('python-mechanize', '0.1.11', 'dev-python/mechanize', 'python-mechanize', 'python-mechanize'),
('ImageMagick', '6.3.5', 'imagemagick', 'imagemagick', 'ImageMagick'),
('xdg-utils', '1.0.2', 'xdg-utils', 'xdg-utils', 'xdg-utils'),
('dbus-python', '0.82.2', 'dbus-python', 'python-dbus', 'dbus-python'),
('lxml', '2.0.5', 'lxml', 'python-lxml', 'python-lxml'),
('python-dateutil', '1.4.1', 'python-dateutil', 'python-dateutil', 'python-dateutil'),
('BeautifulSoup', '3.0.5', 'beautifulsoup', 'python-beautifulsoup', 'python-BeautifulSoup'),
('help2man', '1.36.4', 'help2man', 'help2man', 'help2man'),
]
class Distribution(object):
DEPENDENCIES = [ class CoolDistro:
#(Generic, version, gentoo, ubuntu, fedora)
('python', '2.5', None, None, None),
('setuptools', '0.6c5', 'setuptools', 'python-setuptools', 'python-setuptools-devel'),
('Python Imaging Library', '1.1.6', 'imaging', 'python-imaging', 'python-imaging'),
('libusb', '0.1.12', None, None, None),
('Qt', '4.4.0', 'qt', 'libqt4-core libqt4-gui', 'qt4'),
('PyQt', '4.4.2', 'PyQt4', 'python-qt4', 'PyQt4'),
('mechanize for python', '0.1.11', 'dev-python/mechanize', 'python-mechanize', 'python-mechanize'),
('ImageMagick', '6.3.5', 'imagemagick', 'imagemagick', 'ImageMagick'),
('xdg-utils', '1.0.2', 'xdg-utils', 'xdg-utils', 'xdg-utils'),
('dbus-python', '0.82.2', 'dbus-python', 'python-dbus', 'dbus-python'),
('lxml', '2.0.5', 'lxml', 'python-lxml', 'python-lxml'),
('python-dateutil', '1.4.1', 'python-dateutil', 'python-dateutil', 'python-dateutil'),
('BeautifulSoup', '3.0.5', 'beautifulsoup', 'python-beautifulsoup', 'python-BeautifulSoup'),
('help2man', '1.36.4', 'help2man', 'help2man', 'help2man'),
]
DISTRO_MAP = {'gentoo':2, 'ubuntu':3, 'fedora':4, 'debian':3} def __init__(self, name, title, prefix=''):
self.title = title
url = prefix + '/chrome/dl/images/%s_logo.png'
self.img = url%name
INSTALLERS = ('emerge -avn', 'apt-get install', 'yum install') def get_linux_data(version='1.0.0'):
AS_ROOT = (True, False, True) data = {'version':version, 'app':__appname__}
data['title'] = 'Download calibre for linux'
data['supported'] = []
for name, title in [
('ubuntu', 'Ubuntu Jaunty Jackalope'),
('debian', 'Debian Sid'),
('exherbo', 'Exherbo'),
]:
data['supported'].append(CoolDistro(name, title,
prefix='http://calibre.kovidgoyal.net'))
data['dependencies'] = DEPENDENCIES
return data
TITLEMAP = {'gentoo':'Gentoo', 'ubuntu':'Ubuntu Intrepid Ibex', if __name__ == '__main__':
'fedora':'Fedora 10', 'debian':'Debian sid', 'generic': 'Install from source'} import os
from calibre.utils.genshi.template import MarkupTemplate
import cherrypy
class Test:
def index(self):
raw = open(os.path.dirname(os.path.abspath(__file__))+'/templates/linux.html').read()
return MarkupTemplate(raw).generate(**get_linux_data()).render('xhtml')
index.exposed = True
t = Test()
t.index()
cherrypy.quickstart(t)
else:
from pkg_resources import resource_filename
MANUAL_MAP = { from trac.core import Component, implements
'fedora' : '''<li>You have to upgrade Qt to at least 4.4.0 and PyQt to at least 4.4.2</li>''', from trac.web.chrome import INavigationContributor, ITemplateProvider, add_stylesheet
} from trac.web.main import IRequestHandler
from trac.util import Markup
def __init__(self, os):
self.os = os
self.img = os DOWNLOAD_DIR = '/var/www/calibre.kovidgoyal.net/htdocs/downloads'
self.title = self.TITLEMAP[os] MOBILEREAD = 'https://dev.mobileread.com/dist/kovid/calibre/'
self.app = __appname__
self.is_generic = os == 'generic' class OS(dict):
offset = 0 """Dictionary with a default value for unknown keys."""
if not self.is_generic: def __init__(self, dict):
index = self.DISTRO_MAP[self.os] self.update(dict)
if os == 'debian': if not dict.has_key('img'):
self.as_root = True self['img'] = self['name']
else: self.as_root = self.AS_ROOT[index-2]
prefix = ''
if not self.as_root: prefix = 'sudo ' class Download(Component):
cmd = prefix + self.INSTALLERS[index-2] implements(INavigationContributor, IRequestHandler, ITemplateProvider)
pre = ' \\\n '.ljust(len(cmd)+4)
for dep in self.DEPENDENCIES: request_pat = re.compile(r'\/download$|\/download_\S+')
if len(cmd) > 70+offset:
offset += 70 # INavigationContributor methods
cmd += pre def get_active_navigation_item(self, req):
cmd += ' ' return 'download'
if dep[index]: cmd += dep[index]
self.command = cmd.strip() def get_navigation_items(self, req):
easy_install = 'easy_install' yield 'mainnav', 'download', Markup('<a href="/download">Get %s</a>'%(__appname__,))
if os == 'debian':
easy_install = 'easy_install-2.5' def get_templates_dirs(self):
self.command += '\n'+prefix+easy_install+' -U calibre \n'+prefix+'calibre_postinstall' return [resource_filename(__name__, 'templates')]
def get_htdocs_dirs(self):
return [('dl', resource_filename(__name__, 'htdocs'))]
# IRequestHandler methods
def match_request(self, req):
return self.__class__.request_pat.match(req.path_info)
def process_request(self, req):
add_stylesheet(req, 'dl/css/download.css')
if req.path_info == '/download':
return self.top_level(req)
elif req.path_info == '/download_linux_binary_installer':
req.send(LINUX_INSTALLER.replace('%version', self.version_from_filename()), 'text/x-python')
else:
match = re.match(r'\/download_(\S+)', req.path_info)
if match:
os = match.group(1)
if os == 'windows':
return self.windows(req)
elif os == 'osx':
return self.osx(req)
elif os == 'linux':
return self.linux(req)
def top_level(self, req):
operating_systems = [
OS({'name' : 'windows', 'title' : 'Windows'}),
OS({'name' : 'osx', 'title' : 'OS X'}),
OS({'name' : 'linux', 'title' : 'Linux'}),
]
data = dict(title='Get ' + __appname__,
operating_systems=operating_systems, width=200,
font_size='xx-large', top_level=True)
return 'download.html', data, None
def version_from_filename(self):
try: try:
self.manual = Markup(self.MANUAL_MAP[os]) return open(DOWNLOAD_DIR+'/latest_version', 'rb').read().strip()
except KeyError: except:
self.manual = None return '0.0.0'
else:
self.img = 'linux' def windows(self, req):
version = self.version_from_filename()
file = '%s-%s.exe'%(__appname__, version,)
data = dict(version = version, name='windows',
installer_name='Windows installer',
title='Download %s for windows'%(__appname__),
compatibility='%s works on Windows XP and Windows Vista.'%(__appname__,),
path=MOBILEREAD+file, app=__appname__,
note=Markup(\
'''
<p>If you are using the <b>SONY PRS-500</b> and %(appname)s does not detect your reader, read on:</p>
<blockquote>
<p>
If you are using 64-bit windows, you're out of luck.
</p>
<p>
There may be a conflict with the USB driver from SONY. In windows, you cannot install two drivers
for one device. In order to resolve the conflict:
<ol>
<li>Start Device Manager by clicking Start->Run, typing devmgmt.msc and pressing enter.</li>
<li>Uninstall all PRS500 related drivers. You will find them in two locations:
<ul>
<li>Under "Libusb-Win32"</li>
<li>Under "Universal Serial ..." (... depends on the version of windows)</li>
</ul>
You can uninstall a driver by right clicking on it and selecting uninstall.
</li>
<li>Once the drivers have been uninstalled, find the file prs500.inf (it will be in the
driver folder in the folder in which you installed %(appname)s. Right click on it and
select Install.</li>
</ol>
</p>
</blockquote>
'''%dict(appname=__appname__)))
return 'binary.html', data, None
def osx(self, req):
version = self.version_from_filename()
file = 'calibre-%s.dmg'%(version,)
data = dict(version = version, name='osx',
installer_name='OS X universal dmg',
title='Download %s for OS X'%(__appname__),
compatibility='%s works on OS X Tiger and above.'%(__appname__,),
path=MOBILEREAD+file, app=__appname__,
note=Markup(\
'''
<ol>
<li>Before trying to use the command line tools, you must run the app at least once. This will ask you for you password and then setup the symbolic links for the command line tools.</li>
<li>The app cannot be run from within the dmg. You must drag it to a folder on your filesystem (The Desktop, Applications, wherever).</li>
<li>In order for localization of the user interface in your language, select your language in the configuration dialog (by clicking the hammer icon next to the search bar) and select your language.</li>
</ol>
'''))
return 'binary.html', data, None
def linux(self, req):
data = get_linux_data(version=self.version_from_filename())
return 'linux.html', data, None
class Download(Component): LINUX_INSTALLER = textwrap.dedent(r'''
implements(INavigationContributor, IRequestHandler, ITemplateProvider) import sys, os, shutil, tarfile, subprocess, tempfile, urllib2, re, stat
request_pat = re.compile(r'\/download$|\/download_\S+') MOBILEREAD='https://dev.mobileread.com/dist/kovid/calibre/'
# INavigationContributor methods class TerminalController:
def get_active_navigation_item(self, req): BOL = '' #: Move the cursor to the beginning of the line
return 'download' UP = '' #: Move the cursor up one line
DOWN = '' #: Move the cursor down one line
LEFT = '' #: Move the cursor left one char
RIGHT = '' #: Move the cursor right one char
def get_navigation_items(self, req): # Deletion:
yield 'mainnav', 'download', Markup('<a href="/download">Get %s</a>'%(__appname__,)) CLEAR_SCREEN = '' #: Clear the screen and move to home position
CLEAR_EOL = '' #: Clear to the end of the line.
CLEAR_BOL = '' #: Clear to the beginning of the line.
CLEAR_EOS = '' #: Clear to the end of the screen
def get_templates_dirs(self): # Output modes:
return [resource_filename(__name__, 'templates')] BOLD = '' #: Turn on bold mode
BLINK = '' #: Turn on blink mode
DIM = '' #: Turn on half-bright mode
REVERSE = '' #: Turn on reverse-video mode
NORMAL = '' #: Turn off all modes
def get_htdocs_dirs(self): # Cursor display:
return [('dl', resource_filename(__name__, 'htdocs'))] HIDE_CURSOR = '' #: Make the cursor invisible
SHOW_CURSOR = '' #: Make the cursor visible
# IRequestHandler methods # Terminal size:
def match_request(self, req): COLS = None #: Width of the terminal (None for unknown)
return self.__class__.request_pat.match(req.path_info) LINES = None #: Height of the terminal (None for unknown)
def process_request(self, req): # Foreground colors:
add_stylesheet(req, 'dl/css/download.css') BLACK = BLUE = GREEN = CYAN = RED = MAGENTA = YELLOW = WHITE = ''
if req.path_info == '/download':
return self.top_level(req)
elif req.path_info == '/download_linux_binary_installer':
req.send(LINUX_INSTALLER.replace('%version', self.version_from_filename()), 'text/x-python')
else:
match = re.match(r'\/download_(\S+)', req.path_info)
if match:
os = match.group(1)
if os == 'windows':
return self.windows(req)
elif os == 'osx':
return self.osx(req)
elif os == 'linux':
return self.linux(req)
elif 'binary' in os:
return self.linux_binary(req)
else:
return self.linux_distro(req, os)
def linux_distro(self, req, os): # Background colors:
version = self.version_from_filename() BG_BLACK = BG_BLUE = BG_GREEN = BG_CYAN = ''
distro = Distribution(os) BG_RED = BG_MAGENTA = BG_YELLOW = BG_WHITE = ''
data = dict(distro=distro,title=distro.title, version=version)
return 'distro.html', data, None
def top_level(self, req): _STRING_CAPABILITIES = """
operating_systems = [ BOL=cr UP=cuu1 DOWN=cud1 LEFT=cub1 RIGHT=cuf1
OS({'name' : 'windows', 'title' : 'Windows'}), CLEAR_SCREEN=clear CLEAR_EOL=el CLEAR_BOL=el1 CLEAR_EOS=ed BOLD=bold
OS({'name' : 'osx', 'title' : 'OS X'}), BLINK=blink DIM=dim REVERSE=rev UNDERLINE=smul NORMAL=sgr0
OS({'name' : 'linux', 'title' : 'Linux'}), HIDE_CURSOR=cinvis SHOW_CURSOR=cnorm""".split()
] _COLORS = """BLACK BLUE GREEN CYAN RED MAGENTA YELLOW WHITE""".split()
data = dict(title='Get ' + __appname__, _ANSICOLORS = "BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE".split()
operating_systems=operating_systems, width=200,
font_size='xx-large', top_level=True)
return 'download.html', data, None
def version_from_filename(self): def __init__(self, term_stream=sys.stdout):
# Curses isn't available on all platforms
try: import curses
except: return
# If the stream isn't a tty, then assume it has no capabilities.
if not hasattr(term_stream, 'isatty') or not term_stream.isatty(): return
# Check the terminal type. If we fail, then assume that the
# terminal has no capabilities.
try: curses.setupterm()
except: return
# Look up numeric capabilities.
self.COLS = curses.tigetnum('cols')
self.LINES = curses.tigetnum('lines')
# Look up string capabilities.
for capability in self._STRING_CAPABILITIES:
(attrib, cap_name) = capability.split('=')
setattr(self, attrib, self._tigetstr(cap_name) or '')
# Colors
set_fg = self._tigetstr('setf')
if set_fg:
for i,color in zip(range(len(self._COLORS)), self._COLORS):
setattr(self, color, curses.tparm(set_fg, i) or '')
set_fg_ansi = self._tigetstr('setaf')
if set_fg_ansi:
for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS):
setattr(self, color, curses.tparm(set_fg_ansi, i) or '')
set_bg = self._tigetstr('setb')
if set_bg:
for i,color in zip(range(len(self._COLORS)), self._COLORS):
setattr(self, 'BG_'+color, curses.tparm(set_bg, i) or '')
set_bg_ansi = self._tigetstr('setab')
if set_bg_ansi:
for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS):
setattr(self, 'BG_'+color, curses.tparm(set_bg_ansi, i) or '')
def _tigetstr(self, cap_name):
# String capabilities can include "delays" of the form "$<2>".
# For any modern terminal, we should be able to just ignore
# these, so strip them out.
import curses
cap = curses.tigetstr(cap_name) or ''
return re.sub(r'\$<\d+>[/*]?', '', cap)
def render(self, template):
return re.sub(r'\$\$|\${\w+}', self._render_sub, template)
def _render_sub(self, match):
s = match.group()
if s == '$$': return s
else: return getattr(self, s[2:-1])
class ProgressBar:
BAR = '%3d%% ${GREEN}[${BOLD}%s%s${NORMAL}${GREEN}]${NORMAL}\n'
HEADER = '${BOLD}${CYAN}%s${NORMAL}\n\n'
def __init__(self, term, header):
self.term = term
if not (self.term.CLEAR_EOL and self.term.UP and self.term.BOL):
raise ValueError("Terminal isn't capable enough -- you "
"should use a simpler progress dispaly.")
self.width = self.term.COLS or 75
self.bar = term.render(self.BAR)
self.header = self.term.render(self.HEADER % header.center(self.width))
self.cleared = 1 #: true if we haven't drawn the bar yet.
def update(self, percent, message=''):
if isinstance(message, unicode):
message = message.encode('utf-8', 'ignore')
if self.cleared:
sys.stdout.write(self.header)
self.cleared = 0
n = int((self.width-10)*percent)
msg = message.center(self.width)
sys.stdout.write(
self.term.BOL + self.term.UP + self.term.CLEAR_EOL +
(self.bar % (100*percent, '='*n, '-'*(self.width-10-n))) +
self.term.CLEAR_EOL + msg)
sys.stdout.flush()
def clear(self):
if not self.cleared:
sys.stdout.write(self.term.BOL + self.term.CLEAR_EOL +
self.term.UP + self.term.CLEAR_EOL +
self.term.UP + self.term.CLEAR_EOL)
self.cleared = 1
def download_tarball():
try: try:
return open(DOWNLOAD_DIR+'/latest_version', 'rb').read().strip() pb = ProgressBar(TerminalController(sys.stdout), 'Downloading calibre...')
except: except ValueError:
return '0.0.0' print 'Downloading calibre...'
pb = None
def windows(self, req): local = 'calibre-test.tar.bz2'
version = self.version_from_filename() src = open(local) if os.access(local, os.R_OK) else urllib2.urlopen(MOBILEREAD+'calibre-%version-i686.tar.bz2')
file = '%s-%s.exe'%(__appname__, version,) if hasattr(src, 'info'):
data = dict(version = version, name='windows', size = int(src.info()['content-length'])
installer_name='Windows installer',
title='Download %s for windows'%(__appname__),
compatibility='%s works on Windows XP and Windows Vista.'%(__appname__,),
path=MOBILEREAD+file, app=__appname__,
note=Markup(\
'''
<p>If you are using the <b>SONY PRS-500</b> and %(appname)s does not detect your reader, read on:</p>
<blockquote>
<p>
If you are using 64-bit windows, you're out of luck.
</p>
<p>
There may be a conflict with the USB driver from SONY. In windows, you cannot install two drivers
for one device. In order to resolve the conflict:
<ol>
<li>Start Device Manager by clicking Start->Run, typing devmgmt.msc and pressing enter.</li>
<li>Uninstall all PRS500 related drivers. You will find them in two locations:
<ul>
<li>Under "Libusb-Win32"</li>
<li>Under "Universal Serial ..." (... depends on the version of windows)</li>
</ul>
You can uninstall a driver by right clicking on it and selecting uninstall.
</li>
<li>Once the drivers have been uninstalled, find the file prs500.inf (it will be in the
driver folder in the folder in which you installed %(appname)s. Right click on it and
select Install.</li>
</ol>
</p>
</blockquote>
'''%dict(appname=__appname__)))
return 'binary.html', data, None
def linux_binary(self, req):
version = self.version_from_filename()
return 'pyinstaller.html', {'app':__appname__, 'version':version}, None
def osx(self, req):
version = self.version_from_filename()
file = 'calibre-%s.dmg'%(version,)
data = dict(version = version, name='osx',
installer_name='OS X universal dmg',
title='Download %s for OS X'%(__appname__),
compatibility='%s works on OS X Tiger and above.'%(__appname__,),
path=MOBILEREAD+file, app=__appname__,
note=Markup(\
'''
<ol>
<li>Before trying to use the command line tools, you must run the app at least once. This will ask you for you password and then setup the symbolic links for the command line tools.</li>
<li>The app cannot be run from within the dmg. You must drag it to a folder on your filesystem (The Desktop, Applications, wherever).</li>
<li>In order for localization of the user interface in your language, select your language in the configuration dialog (by clicking the hammer icon next to the search bar) and select your language.</li>
</ol>
'''))
return 'binary.html', data, None
def linux(self, req):
operating_systems = [
OS({'name' : 'binary', 'title': 'Binary Installer'}),
OS({'name' : 'gentoo', 'title': 'Gentoo'}),
OS({'name' : 'ubuntu', 'title': 'Ubuntu'}),
OS({'name' : 'fedora', 'title': 'Fedora'}),
OS({'name' : 'debian', 'title': 'Debian'}),
OS({'name' : 'generic','title': 'Install from source', 'img':'linux'}),
]
data = dict(title='Choose linux distribution', width=100,
operating_systems=operating_systems, font_size='x-large', top_level=False)
return 'download.html', data, None
LINUX_INSTALLER = r'''
import sys, os, shutil, tarfile, subprocess, tempfile, urllib2, re, stat
MOBILEREAD='https://dev.mobileread.com/dist/kovid/calibre/'
class TerminalController:
BOL = '' #: Move the cursor to the beginning of the line
UP = '' #: Move the cursor up one line
DOWN = '' #: Move the cursor down one line
LEFT = '' #: Move the cursor left one char
RIGHT = '' #: Move the cursor right one char
# Deletion:
CLEAR_SCREEN = '' #: Clear the screen and move to home position
CLEAR_EOL = '' #: Clear to the end of the line.
CLEAR_BOL = '' #: Clear to the beginning of the line.
CLEAR_EOS = '' #: Clear to the end of the screen
# Output modes:
BOLD = '' #: Turn on bold mode
BLINK = '' #: Turn on blink mode
DIM = '' #: Turn on half-bright mode
REVERSE = '' #: Turn on reverse-video mode
NORMAL = '' #: Turn off all modes
# Cursor display:
HIDE_CURSOR = '' #: Make the cursor invisible
SHOW_CURSOR = '' #: Make the cursor visible
# Terminal size:
COLS = None #: Width of the terminal (None for unknown)
LINES = None #: Height of the terminal (None for unknown)
# Foreground colors:
BLACK = BLUE = GREEN = CYAN = RED = MAGENTA = YELLOW = WHITE = ''
# Background colors:
BG_BLACK = BG_BLUE = BG_GREEN = BG_CYAN = ''
BG_RED = BG_MAGENTA = BG_YELLOW = BG_WHITE = ''
_STRING_CAPABILITIES = """
BOL=cr UP=cuu1 DOWN=cud1 LEFT=cub1 RIGHT=cuf1
CLEAR_SCREEN=clear CLEAR_EOL=el CLEAR_BOL=el1 CLEAR_EOS=ed BOLD=bold
BLINK=blink DIM=dim REVERSE=rev UNDERLINE=smul NORMAL=sgr0
HIDE_CURSOR=cinvis SHOW_CURSOR=cnorm""".split()
_COLORS = """BLACK BLUE GREEN CYAN RED MAGENTA YELLOW WHITE""".split()
_ANSICOLORS = "BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE".split()
def __init__(self, term_stream=sys.stdout):
# Curses isn't available on all platforms
try: import curses
except: return
# If the stream isn't a tty, then assume it has no capabilities.
if not hasattr(term_stream, 'isatty') or not term_stream.isatty(): return
# Check the terminal type. If we fail, then assume that the
# terminal has no capabilities.
try: curses.setupterm()
except: return
# Look up numeric capabilities.
self.COLS = curses.tigetnum('cols')
self.LINES = curses.tigetnum('lines')
# Look up string capabilities.
for capability in self._STRING_CAPABILITIES:
(attrib, cap_name) = capability.split('=')
setattr(self, attrib, self._tigetstr(cap_name) or '')
# Colors
set_fg = self._tigetstr('setf')
if set_fg:
for i,color in zip(range(len(self._COLORS)), self._COLORS):
setattr(self, color, curses.tparm(set_fg, i) or '')
set_fg_ansi = self._tigetstr('setaf')
if set_fg_ansi:
for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS):
setattr(self, color, curses.tparm(set_fg_ansi, i) or '')
set_bg = self._tigetstr('setb')
if set_bg:
for i,color in zip(range(len(self._COLORS)), self._COLORS):
setattr(self, 'BG_'+color, curses.tparm(set_bg, i) or '')
set_bg_ansi = self._tigetstr('setab')
if set_bg_ansi:
for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS):
setattr(self, 'BG_'+color, curses.tparm(set_bg_ansi, i) or '')
def _tigetstr(self, cap_name):
# String capabilities can include "delays" of the form "$<2>".
# For any modern terminal, we should be able to just ignore
# these, so strip them out.
import curses
cap = curses.tigetstr(cap_name) or ''
return re.sub(r'\$<\d+>[/*]?', '', cap)
def render(self, template):
return re.sub(r'\$\$|\${\w+}', self._render_sub, template)
def _render_sub(self, match):
s = match.group()
if s == '$$': return s
else: return getattr(self, s[2:-1])
class ProgressBar:
BAR = '%3d%% ${GREEN}[${BOLD}%s%s${NORMAL}${GREEN}]${NORMAL}\n'
HEADER = '${BOLD}${CYAN}%s${NORMAL}\n\n'
def __init__(self, term, header):
self.term = term
if not (self.term.CLEAR_EOL and self.term.UP and self.term.BOL):
raise ValueError("Terminal isn't capable enough -- you "
"should use a simpler progress dispaly.")
self.width = self.term.COLS or 75
self.bar = term.render(self.BAR)
self.header = self.term.render(self.HEADER % header.center(self.width))
self.cleared = 1 #: true if we haven't drawn the bar yet.
def update(self, percent, message=''):
if isinstance(message, unicode):
message = message.encode('utf-8', 'ignore')
if self.cleared:
sys.stdout.write(self.header)
self.cleared = 0
n = int((self.width-10)*percent)
msg = message.center(self.width)
sys.stdout.write(
self.term.BOL + self.term.UP + self.term.CLEAR_EOL +
(self.bar % (100*percent, '='*n, '-'*(self.width-10-n))) +
self.term.CLEAR_EOL + msg)
sys.stdout.flush()
def clear(self):
if not self.cleared:
sys.stdout.write(self.term.BOL + self.term.CLEAR_EOL +
self.term.UP + self.term.CLEAR_EOL +
self.term.UP + self.term.CLEAR_EOL)
self.cleared = 1
def download_tarball():
try:
pb = ProgressBar(TerminalController(sys.stdout), 'Downloading calibre...')
except ValueError:
print 'Downloading calibre...'
pb = None
local = 'calibre-test.tar.bz2'
src = open(local) if os.access(local, os.R_OK) else urllib2.urlopen(MOBILEREAD+'calibre-%version-i686.tar.bz2')
if hasattr(src, 'info'):
size = int(src.info()['content-length'])
else:
src.seek(0, 2)
size = src.tell()
src.seek(0)
f = tempfile.NamedTemporaryFile()
while f.tell() < size:
f.write(src.read(4*1024))
percent = f.tell()/float(size)
if pb is not None:
pb.update(percent)
else: else:
print '%d%%, '%int(percent*100), src.seek(0, 2)
f.seek(0) size = src.tell()
return f src.seek(0)
f = tempfile.NamedTemporaryFile()
while f.tell() < size:
f.write(src.read(4*1024))
percent = f.tell()/float(size)
if pb is not None:
pb.update(percent)
else:
print '%d%%, '%int(percent*100),
f.seek(0)
return f
def extract_tarball(tar, destdir): def extract_tarball(tar, destdir):
print 'Extracting application files...' print 'Extracting application files...'
if hasattr(tar, 'read'): if hasattr(tar, 'read'):
try: try:
tarfile.open(fileobj=tar, mode='r').extractall(destdir) tarfile.open(fileobj=tar, mode='r').extractall(destdir)
except: # tarfile.py on Fedora 9 is buggy except: # tarfile.py on Fedora 9 is buggy
subprocess.check_call(['tar', 'xjf', tar.name, '-C', destdir]) subprocess.check_call(['tar', 'xjf', tar.name, '-C', destdir])
else: else:
tarfile.open(tar, 'r').extractall(destdir) tarfile.open(tar, 'r').extractall(destdir)
def main(): def main():
defdir = '/opt/calibre' defdir = '/opt/calibre'
destdir = raw_input('Enter the installation directory for calibre (Its contents will be deleted!)[%s]: '%defdir).strip() destdir = raw_input('Enter the installation directory for calibre (Its contents will be deleted!)[%s]: '%defdir).strip()
if not destdir: if not destdir:
destdir = defdir destdir = defdir
destdir = os.path.abspath(destdir) destdir = os.path.abspath(destdir)
if os.path.exists(destdir): if os.path.exists(destdir):
shutil.rmtree(destdir) shutil.rmtree(destdir)
os.makedirs(destdir) os.makedirs(destdir)
f = download_tarball() f = download_tarball()
print 'Extracting files to %s ...'%destdir
extract_tarball(f, destdir)
pi = os.path.join(destdir, 'calibre_postinstall')
subprocess.call(pi, shell=True)
return 0
''')
print 'Extracting files to %s ...'%destdir
extract_tarball(f, destdir)
pi = os.path.join(destdir, 'calibre_postinstall')
subprocess.call(pi, shell=True)
return 0
'''

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@ -1,68 +0,0 @@
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://genshi.edgewall.org/"
xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="layout.html" />
<head>
<title>$title</title>
</head>
<body>
<div id="ctxtnav" class="nav"></div>
<div id="content" class="download">
<h1><img src="${href.chrome('/dl/images/%s_logo.png'%(distro.img,))}" valign="middle" width="60" height="80"/> $title</h1>
See the <a href="/wiki/Changelog">Changelog</a> for the changes in the latest version. <span py:if="not distro.is_generic"><b>Note:</b> As of 0.4.80 this install
will not work on 64-bit CPUs. Try the precompiled binary available <a href="/download_binary">here</a> instead.</span>
<div py:if="not distro.is_generic">
First verify that you have a sufficiently new installation of python
<pre class="wiki">python --version</pre> should return at least 2.5.1<br />
<p py:if="distro.os == 'gentoo'">
Make sure your python is compiled with the sqlite USE flag.
</p>
<br />
Run the following commands in a terminal <span py:if="distro.as_root">as root</span>
<pre class="wiki">${distro.command}</pre>
<div py:if="distro.manual">
<h2>Manual steps</h2>
<ul>
${distro.manual}
</ul>
</div>
</div>
<div py:if="distro.is_generic">
<ol>
<li>Make sure that your system has <code>python &gt;= 2.5</code></li>
<li>Install the various dependencies listed below: Make sure that any python packages are installed into python2.5 (e.g. setuptools, python-imaging, PyQt4, etc). You will also have to install the development versions of the packages (these packages usually have -dev added to their names).</li>
<li>Run the following commands in a terminal:
<pre class="wiki">
wget -O- http://calibre.kovidgoyal.net/downloads/calibre-${version}.tar.gz | tar xvz
cd calibre*
python setup.py build &amp;&amp; sudo python setup.py install
</pre></li>
</ol>
<h2>Dependencies</h2>
<table border="1" cellpadding="10">
<tr><th style="font-weight:bold">Name</th><th style="font-weight:bold">Minimum version</th></tr>
<tr py:for="dep in distro.DEPENDENCIES">
<td>${dep[0]}</td><td>${dep[1]}</td>
</tr>
<tr>
<td>HAL</td><td>0.5.10</td>
</tr>
</table>
</div>
While you wait for the installation to complete, please consider donating to support the development of ${distro.app}.
<div>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
<input type="hidden" name="cmd" value="_s-xclick" />
<input type="hidden" name="hosted_button_id" value="3029289" />
<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="Donate to support calibre development" />
<img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1" />
</form>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,155 @@
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://genshi.edgewall.org/"
xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="layout.html" />
<head>
<title>${title}</title>
<style type="text/css">
table tr th.distro_type {
font-family: monospace;
font-weight: bold;
font-size: larger;
vertical-align:middle;
text-align: center;
border-bottom: solid 1pt black;
}
.right {
margin-left:2em;
border-left: solid 1pt black;
}
table#install_info {
border-collapse: collapse;
border-width: 1pt;
border-style: solid;
table-layout: fixed;
width: 95%;
background: #F7F7F0 none repeat scroll 0 0;
}
table#dependencies {
border-collapse: collapse;
border-width: 0pt;
font-family:monospace;
}
.tdata {vertical-align: top;}
</style>
</head>
<body>
<div id="ctxtnav" class="nav"></div>
<div id="content" class="download">
<h1>${title}</h1>
<p>
The latest release of ${app} is ${version}. See the
<a href="/wiki/Changelog">Changelog</a> for a list of new features.
</p>
<p>
${app} is available in the software repositories of the following
linux distributions:
<table id="install_info">
<col width="150" /><col width="*" />
<tr>
<th class="left distro_type">Supported<br/>distributions</th>
<th class="right distro_type">Unsupported distributions</th>
</tr>
<tr class="tdata">
<td class="left" style="overflow-y:scroll">
<div py:for="distro in supported"
style="text-align:center;margin-top:2ex;">
<div>
<img width="64px" height="64px"
src="${distro.img}" alt="${distro.title}" />
</div>
${distro.title}
</div>
</td>
<td class="right">
<div style="margin-left:2em">
<h3>Binary install</h3>
<p>
${app} has a binary installer that has been
tested on a number of distributions on both
32-bit and 64-bit x86 machines. To install,
copy paste the following command into a terminal
and press Enter:
</p>
<pre class="wiki">
sudo python -c "import urllib2; exec urllib2.urlopen('http://calibre.kovidgoyal.net/download_linux_binary_installer').read(); main()"
</pre>
<h4>Note</h4>
<ul>
<li>
When running the command line utilities,
they will segfault after completion. This can
be ignored.
</li>
<li>
You must have help2man and xdg-utils installed
on your system before running the installer.
</li>
<li>
On a 64bit machine, you must have 32-bit versions
of common libraries like X11, freetype, fontconfig,
expat and their varios dependencies installed.
</li>
</ul>
<h3>Source install</h3>
<p>
<ol>
<li>
Make sure your system has python &ge; ${dependencies[0][1]}
</li>
<li>
Install the various dependencies listed below
</li>
<li>
Run the following commands in a terminal:
</li>
</ol>
<pre class="wiki">
wget -O- http://calibre.kovidgoyal.net/downloads/${app}-${version}.tar.gz | tar xvz
cd calibre*
python setup.py build &amp;&amp; sudo python setup.py install
</pre>
Note that if your distribution does not have a
correctly compiled libunrar.so, ${app} will not
support rar files.
</p>
</div>
</td>
</tr>
</table>
</p>
<p>
While you wait for the download to complete, please consider
donating to support the development of ${app}.
</p>
<div>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
<input type="hidden" name="cmd" value="_s-xclick" />
<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!" />
<img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1" />
<input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----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-----END PKCS7-----" />
</form>
</div>
<hr/>
<h3>Dependencies</h3>
${app} has the following dependencies (the listed version is the minimum version)
<br/><br/>
<table id="dependencies">
<tr>
<th class="distro_type" style="margin-right:2em">Package</th>
<th class="distro_type">Version</th>
</tr>
<tr class="dependency" py:for="dep in dependencies">
<td style="margin-right:2em">${dep[0]}</td><td>${dep[1]}</td>
</tr>
</table>
</div>
</body>
</html>

View File

@ -1,47 +0,0 @@
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://genshi.edgewall.org/"
xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="layout.html" />
<head>
<title>Download $app for Linux</title>
</head>
<body>
<div id="ctxtnav" class="nav"></div>
<div id="content" class="binary">
<h1>Download $app for Linux</h1>
<p>This binary package is compatible with most recent linux distributions running on Intel 32 bit CPUs. It needs testing on 64 bit CPUs. There have been reports of its working on some 64bit machines. </p>
<p>
<img width="50" height="50" style="border:1px red solid" src="${href.chrome('/dl/images/binary_logo.png')}" />
(Version: $version <a href="/wiki/Changelog">Changelog</a>)
</p>
<p>To install, copy paste the following command into a terminal and press Enter:
</p>
<pre class="wiki">sudo python -c "import urllib2; exec urllib2.urlopen('http://calibre.kovidgoyal.net/download_linux_binary_installer').read(); main()"</pre>
<p>
While you wait for the download to complete, please consider donating to support the development
of ${app}.</p>
<div>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
<input type="hidden" name="cmd" value="_s-xclick" />
<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!" />
<img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1" />
<input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----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-----END PKCS7-----" />
</form>
</div>
<h2>Note</h2>
<div class="note">
<ul>
<li>This installer is very new and has only been tested on a couple of systems, so if you encounter
problems, please report them.</li>
<li>You shoud have help2man and xdg-utils installed on your system.</li>
</ul>
</div>
</div>
</body>
</html>

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

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@ __docformat__ = 'restructuredtext en'
''' '''
Manage application-wide preferences. Manage application-wide preferences.
''' '''
import os, re, cPickle, textwrap import os, re, cPickle, textwrap, traceback
from copy import deepcopy from copy import deepcopy
from functools import partial from functools import partial
from optparse import OptionParser as _OptionParser from optparse import OptionParser as _OptionParser
@ -314,7 +314,12 @@ class OptionSet(object):
if not isinstance(src, unicode): if not isinstance(src, unicode):
src = src.decode('utf-8') src = src.decode('utf-8')
if src is not None: if src is not None:
exec src in options try:
exec src in options
except:
print 'Failed to parse options string:'
print repr(src)
traceback.print_exc()
opts = OptionValues() opts = OptionValues()
for pref in self.preferences: for pref in self.preferences:
val = options.get(pref.name, pref.default) val = options.get(pref.name, pref.default)
@ -539,7 +544,7 @@ def _prefs():
help=_('Path to directory in which your library of books is stored')) help=_('Path to directory in which your library of books is stored'))
c.add_opt('language', default=None, c.add_opt('language', default=None,
help=_('The language in which to display the user interface')) help=_('The language in which to display the user interface'))
c.add_opt('output_format', default='LRF', c.add_opt('output_format', default='EPUB',
help=_('The default output format for ebook conversions.')) help=_('The default output format for ebook conversions.'))
c.add_opt('read_file_metadata', default=True, c.add_opt('read_file_metadata', default=True,
help=_('Read metadata from files')) help=_('Read metadata from files'))

View File

@ -28,7 +28,7 @@ recipe_modules = ['recipe_' + r for r in (
'la_tercera', 'el_mercurio_chile', 'la_cuarta', 'lanacion_chile', 'la_segunda', 'la_tercera', 'el_mercurio_chile', 'la_cuarta', 'lanacion_chile', 'la_segunda',
'jb_online', 'estadao', 'o_globo', 'vijesti', 'elmundo', 'the_oz', 'jb_online', 'estadao', 'o_globo', 'vijesti', 'elmundo', 'the_oz',
'honoluluadvertiser', 'starbulletin', 'exiled', 'indy_star', 'dna', 'honoluluadvertiser', 'starbulletin', 'exiled', 'indy_star', 'dna',
'pobjeda', 'pobjeda', 'chicago_breaking_news', 'glasgow_herald',
)] )]
import re, imp, inspect, time, os import re, imp, inspect, time, os

View File

@ -1,50 +1,60 @@
#!/usr/bin/env python #!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en'
__license__ = 'GPL v3'
__copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
''' '''
arstechnica.com arstechnica.com
''' '''
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
class ArsTechnica(BasicNewsRecipe): class ArsTechnica2(BasicNewsRecipe):
title = 'Ars Technica' title = u'Ars Technica'
description = 'The art of technology' language = _('English')
oldest_article = 7 __author__ = 'Darko Miletic'
language = _('English') description = 'The art of technology'
no_stylesheets = True publisher = 'Ars Technica'
__author__ = 'Michael Warner' category = 'news, IT, technology'
language = _('English')
oldest_article = 2
max_articles_per_feed = 100 max_articles_per_feed = 100
extra_css = """ no_stylesheets = True
body { encoding = 'utf8'
font: normal 19px/180% Times, serif; remove_javascript = True
} use_embedded_content = False
html2lrf_options = [
'--comment', description
, '--category', category
, '--publisher', publisher
]
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
keep_only_tags = [dict(name='div', attrs={'id':['news-item-info','news-item']})]
h1, h2, h3, h4 {
font: bold 28px/100% Verdana, Arial, Helvetica, sans-serif;
margin-top: 19px
}
"""
remove_tags = [ remove_tags = [
dict(id="Masthead"), dict(name=['object','link','embed'])
dict(id="Banner"), ,dict(name='div', attrs={'class':'related-stories'})
dict(id="Nav"), ]
dict(name='div', attrs={'class':'ContentHeader'}),
dict(name='img'),
dict(name='div', attrs={'class':'Inset RelatedStories'}), feeds = [
dict(name='div', attrs={'class':'Tags'}), (u'Infinite Loop (Apple content)' , u'http://feeds.arstechnica.com/arstechnica/apple/' )
dict(name='div', attrs={'class':'PostOptions flat'}), ,(u'Opposable Thumbs (Gaming content)' , u'http://feeds.arstechnica.com/arstechnica/gaming/' )
dict(name='div', attrs={'class':'ContentFooter'}), ,(u'Gear and Gadgets' , u'http://feeds.arstechnica.com/arstechnica/gadgets/' )
dict(id="Sidebar"), ,(u'Chipster (Hardware content)' , u'http://feeds.arstechnica.com/arstechnica/hardware/' )
dict(id="LatestPosts"), ,(u'Uptime (IT content)' , u'http://feeds.arstechnica.com/arstechnica/business/' )
dict(id="Footer")] ,(u'Open Ended (Open Source content)' , u'http://feeds.arstechnica.com/arstechnica/open-source/')
feeds = [(u'News and Features', u'http://feeds.arstechnica.com/arstechnica/BAaf'), ,(u'One Microsoft Way' , u'http://feeds.arstechnica.com/arstechnica/microsoft/' )
(u'Nobel Intent (Science)', u'http://arstechnica.com/journals/science.rssx'), ,(u'Nobel Intent (Science content)' , u'http://feeds.arstechnica.com/arstechnica/science/' )
(u'Infinite Loop (Apple)', u'http://arstechnica.com/journals/apple.rssx'), ,(u'Law & Disorder (Tech policy content)' , u'http://feeds.arstechnica.com/arstechnica/tech-policy/')
(u'M-Dollar (Microsoft)', u'http://arstechnica.com/journals/microsoft.rssx'), ]
(u'Open Ended (Linux)', u'http://arstechnica.com/journals/linux.rssx'),
(u'Opposable Thumbs (Games)', u'http://arstechnica.com/journals/thumbs.rssx'), def preprocess_html(self, soup):
(u'Kit (Hardware)', u'http://arstechnica.com/journals/hardware.rssx'), ftag = soup.find('div', attrs={'class':'news-item-byline'})
(u'Journals', u'http://arstechnica.com/journals.rssx')] if ftag:
ftag.insert(4,'<br /><br />')
for item in soup.findAll(style=True):
del item['style']
return soup

View File

@ -1,13 +1,12 @@
#!/usr/bin/env python #!/usr/bin/env python
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>' __copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
''' '''
b92.net b92.net
''' '''
import re import re
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
class B92(BasicNewsRecipe): class B92(BasicNewsRecipe):
@ -22,19 +21,22 @@ class B92(BasicNewsRecipe):
no_stylesheets = True no_stylesheets = True
use_embedded_content = False use_embedded_content = False
cover_url = 'http://static.b92.net/images/fp/logo.gif' cover_url = 'http://static.b92.net/images/fp/logo.gif'
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "monospace1";src:url(res:///opt/sony/ebook/FONT/tt0419m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: left; font-family: serif1, serif} .article_date{font-family: monospace1, monospace} .article_description{font-family: sans1, sans-serif} .navbar{font-family: monospace1, monospace}' language = _('Serbian')
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: serif1, serif} .article_description{font-family: sans1, sans-serif}'
html2lrf_options = [
'--comment' , description
, '--category' , category
, '--publisher', publisher
, '--ignore-tables'
]
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
keep_only_tags = [ dict(name='div', attrs={'class':'sama_vest'}) ] keep_only_tags = [ dict(name='div', attrs={'class':'sama_vest'}) ]
html2lrf_options = [
'--comment', description
, '--category', category
, '--publisher', publisher
]
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')] preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
feeds = [ feeds = [
(u'Vesti', u'http://www.b92.net/info/rss/vesti.xml') (u'Vesti', u'http://www.b92.net/info/rss/vesti.xml')
,(u'Biz' , u'http://www.b92.net/info/rss/biz.xml' ) ,(u'Biz' , u'http://www.b92.net/info/rss/biz.xml' )
@ -54,9 +56,10 @@ class B92(BasicNewsRecipe):
return nurl return nurl
def preprocess_html(self, soup): def preprocess_html(self, soup):
soup.html['xml:lang'] = 'sr-Latn' lng = 'sr-Latn-RS'
soup.html['lang'] = 'sr-Latn' soup.html['xml:lang'] = lng
mtag = '<meta http-equiv="Content-Language" content="sr-Latn"/>' soup.html['lang'] = lng
mtag = '<meta http-equiv="Content-Language" content="sr-Latn-RS"/>'
soup.head.insert(0,mtag) soup.head.insert(0,mtag)
for item in soup.findAll(style=True): for item in soup.findAll(style=True):
del item['style'] del item['style']
@ -64,4 +67,3 @@ class B92(BasicNewsRecipe):
del item['align'] del item['align']
item.insert(0,'<br /><br />') item.insert(0,'<br /><br />')
return soup return soup
language = _('Serbian')

View File

@ -1,13 +1,12 @@
#!/usr/bin/env python #!/usr/bin/env python
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>' __copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
''' '''
blic.rs blic.rs
''' '''
import re import re
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
class Blic(BasicNewsRecipe): class Blic(BasicNewsRecipe):
@ -21,15 +20,17 @@ class Blic(BasicNewsRecipe):
remove_javascript = True remove_javascript = True
no_stylesheets = True no_stylesheets = True
use_embedded_content = False use_embedded_content = False
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "monospace1";src:url(res:///opt/sony/ebook/FONT/tt0419m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: left; font-family: serif1, serif} .article_date{font-family: monospace1, monospace} .article_description{font-family: sans1, sans-serif} .navbar{font-family: monospace1, monospace}' language = _('Serbian')
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: serif1, serif} .article_description{font-family: sans1, sans-serif}'
html2lrf_options = [ html2lrf_options = [
'--comment', description '--comment' , description
, '--category', category , '--category' , category
, '--publisher', publisher , '--publisher', publisher
, '--ignore-tables'
] ]
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"' html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')] preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
@ -44,10 +45,9 @@ class Blic(BasicNewsRecipe):
return u'http://www.blic.rs/_print.php?' + rest_url return u'http://www.blic.rs/_print.php?' + rest_url
def preprocess_html(self, soup): def preprocess_html(self, soup):
mtag = '<meta http-equiv="Content-Language" content="sr-Latn"/>' mtag = '<meta http-equiv="Content-Language" content="sr-Latn-RS"/>'
soup.head.insert(0,mtag) soup.head.insert(0,mtag)
for item in soup.findAll(style=True): for item in soup.findAll(style=True):
del item['style'] del item['style']
return soup return soup
language = _('Serbian')

View File

@ -0,0 +1,45 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>'
'''
chicagobreakingnews.com
'''
from calibre.web.feeds.news import BasicNewsRecipe
class ChicagoBreakingNews(BasicNewsRecipe):
title = 'Chicago Breaking News'
__author__ = 'Darko Miletic'
description = 'Breaking News from Chicago'
oldest_article = 1
max_articles_per_feed = 100
no_stylesheets = True
use_embedded_content = True
publisher = 'Chicago Breaking News'
category = 'news, politics, USA, Chicago'
encoding = 'utf8'
language = _('English')
html2lrf_options = [
'--comment', description
, '--category', category
, '--publisher', publisher
]
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
feeds = [(u'Breaking news', u'http://feeds2.feedburner.com/ChicagoBreakingNews/')]
def preprocess_html(self, soup):
links = soup.findAll('a')
for item in soup.findAll('a'):
if item['href'].find('http://feedads.googleadservices.com') > -1:
item.extract()
for item in soup.findAll(style=True):
del item['style']
for item in soup.findAll(color=True):
del item['color']
for item in soup.findAll(size=True):
del item['size']
return soup

View File

@ -1,12 +1,11 @@
#!/usr/bin/env python #!/usr/bin/env python
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>' __copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
''' '''
danas.rs danas.rs
''' '''
import re import re
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
class Danas(BasicNewsRecipe): class Danas(BasicNewsRecipe):
@ -20,15 +19,17 @@ class Danas(BasicNewsRecipe):
no_stylesheets = False no_stylesheets = False
remove_javascript = True remove_javascript = True
use_embedded_content = False use_embedded_content = False
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "monospace1";src:url(res:///opt/sony/ebook/FONT/tt0419m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: left; font-family: serif1, serif} .article_date{font-family: monospace1, monospace} .article_description{font-family: sans1, sans-serif} .navbar{font-family: monospace1, monospace}' language = _('Serbian')
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: serif1, serif} .article_description{font-family: sans1, sans-serif}'
html2lrf_options = [ html2lrf_options = [
'--comment', description '--comment' , description
, '--category', category , '--category' , category
, '--publisher', publisher , '--publisher', publisher
, '--ignore-tables'
] ]
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"' html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')] preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
@ -43,9 +44,8 @@ class Danas(BasicNewsRecipe):
feeds = [ (u'Vesti', u'http://www.danas.rs/rss/rss.asp')] feeds = [ (u'Vesti', u'http://www.danas.rs/rss/rss.asp')]
def preprocess_html(self, soup): def preprocess_html(self, soup):
mtag = '<meta http-equiv="Content-Language" content="sr-Latn"/>' mtag = '<meta http-equiv="Content-Language" content="sr-Latn-RS"/>'
soup.head.insert(0,mtag) soup.head.insert(0,mtag)
for item in soup.findAll(style=True): for item in soup.findAll(style=True):
del item['style'] del item['style']
return soup return soup
language = _('Serbian')

View File

@ -5,7 +5,6 @@ __copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
''' '''
elargentino.com elargentino.com
''' '''
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
class ElArgentino(BasicNewsRecipe): class ElArgentino(BasicNewsRecipe):
@ -21,6 +20,7 @@ class ElArgentino(BasicNewsRecipe):
use_embedded_content = False use_embedded_content = False
encoding = 'utf8' encoding = 'utf8'
cover_url = 'http://www.elargentino.com/TemplateWeb/MediosFooter/tapa_elargentino.png' cover_url = 'http://www.elargentino.com/TemplateWeb/MediosFooter/tapa_elargentino.png'
language = _('Spanish')
html2lrf_options = [ html2lrf_options = [
'--comment', description '--comment', description
@ -59,5 +59,3 @@ class ElArgentino(BasicNewsRecipe):
for item in soup.findAll(style=True): for item in soup.findAll(style=True):
del item['style'] del item['style']
return soup return soup
language = _('Spanish')

View File

@ -0,0 +1,34 @@
import re
from calibre.web.feeds.news import BasicNewsRecipe
class GlasgowHerald(BasicNewsRecipe):
title = u'Glasgow Herald'
oldest_article = 1
max_articles_per_feed = 100
no_stylesheets = True
language = _('English')
__author__ = 'McCande'
preprocess_regexps = [ (re.compile(i[0], re.IGNORECASE | re.DOTALL), i[1]) for i in
[
(r'<center><h3>', lambda match : '<h3>'),
(r'Click here to comment on this story...', lambda match : ''),
(r'<h3>Related links</h3>.*?</head>', lambda match : '</head>'),
]
]
feeds = [
(u'News', u'http://www.theherald.co.uk/news/news/rss.xml'),
(u'Politics', u'http://www.theherald.co.uk/politics/news/rss.xml'),
(u'Features', u'http://www.theherald.co.uk/features/features/rss.xml'),
(u'Business', u'http://www.theherald.co.uk/business/news/rss.xml')]
def print_version(self, url):
(beginning,end)=url.split(".var.")
num=end[0:7]
main="http://www.theherald.co.uk/misc/print.php?artid="+num
return main

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>' __copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
''' '''
granma.cubaweb.cu granma.cubaweb.cu
''' '''
@ -21,19 +21,22 @@ class Granma(BasicNewsRecipe):
use_embedded_content = False use_embedded_content = False
encoding = 'cp1252' encoding = 'cp1252'
cover_url = 'http://www.granma.cubaweb.cu/imagenes/granweb229d.jpg' cover_url = 'http://www.granma.cubaweb.cu/imagenes/granweb229d.jpg'
language = _('Spanish')
remove_javascript = True remove_javascript = True
html2lrf_options = [ html2lrf_options = [
'--comment', description '--comment' , description
, '--category', category , '--category' , category
, '--publisher', publisher , '--publisher', publisher
, '--ignore-tables' , '--ignore-tables'
] ]
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"' html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
keep_only_tags = [dict(name='table', attrs={'height':'466'})] keep_only_tags = [dict(name='table', attrs={'height':'466'})]
remove_tags = [dict(name=['embed','link','object'])]
feeds = [(u'Noticias', u'http://www.granma.cubaweb.cu/noticias.xml' )] feeds = [(u'Noticias', u'http://www.granma.cubaweb.cu/noticias.xml' )]
@ -49,4 +52,3 @@ class Granma(BasicNewsRecipe):
del item['style'] del item['style']
return soup return soup
language = _('Spanish')

View File

@ -14,21 +14,28 @@ class Infobae(BasicNewsRecipe):
description = 'Informacion Libre las 24 horas' description = 'Informacion Libre las 24 horas'
publisher = 'Infobae.com' publisher = 'Infobae.com'
category = 'news, politics, Argentina' category = 'news, politics, Argentina'
oldest_article = 2 oldest_article = 1
max_articles_per_feed = 100 max_articles_per_feed = 100
no_stylesheets = True no_stylesheets = True
use_embedded_content = False use_embedded_content = False
language = _('Spanish')
encoding = 'iso-8859-1' encoding = 'iso-8859-1'
cover_url = 'http://www.infobae.com/imgs/header/header.gif' cover_url = 'http://www.infobae.com/imgs/header/header.gif'
remove_javascript = True remove_javascript = True
html2lrf_options = [ html2lrf_options = [
'--comment', description '--comment' , description
, '--category', category , '--category' , category
, '--publisher', publisher , '--publisher', publisher
, '--ignore-tables'
] ]
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"' html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
remove_tags = [
dict(name=['embed','link','object'])
,dict(name='a', attrs={'onclick':'javascript:window.print()'})
]
feeds = [ feeds = [
(u'Noticias' , u'http://www.infobae.com/adjuntos/html/RSS/hoy.xml' ) (u'Noticias' , u'http://www.infobae.com/adjuntos/html/RSS/hoy.xml' )
@ -48,5 +55,3 @@ class Infobae(BasicNewsRecipe):
for item in soup.findAll(style=True): for item in soup.findAll(style=True):
del item['style'] del item['style']
return soup return soup
language = _('Spanish')

View File

@ -1,13 +1,12 @@
#!/usr/bin/env python #!/usr/bin/env python
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>' __copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
''' '''
jutarnji.hr jutarnji.hr
''' '''
import re import re
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
class Jutarnji(BasicNewsRecipe): class Jutarnji(BasicNewsRecipe):
@ -16,32 +15,32 @@ class Jutarnji(BasicNewsRecipe):
description = u'Hrvatski portal' description = u'Hrvatski portal'
publisher = 'Jutarnji.hr' publisher = 'Jutarnji.hr'
category = 'news, politics, Croatia' category = 'news, politics, Croatia'
oldest_article = 2 oldest_article = 1
max_articles_per_feed = 100 max_articles_per_feed = 100
simultaneous_downloads = 1 simultaneous_downloads = 2
delay = 1 delay = 1
language = _('Croatian') language = _('Croatian')
no_stylesheets = True no_stylesheets = True
use_embedded_content = False use_embedded_content = False
remove_javascript = True remove_javascript = True
encoding = 'cp1250' encoding = 'cp1250'
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "monospace1";src:url(res:///opt/sony/ebook/FONT/tt0419m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: left; font-family: serif1, serif} .article_date{font-family: monospace1, monospace} .article_description{font-family: sans1, sans-serif} .navbar{font-family: monospace1, monospace}' extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: justify; font-family: serif1, serif} .article_description{font-family: sans1, sans-serif}'
html2lrf_options = [ html2lrf_options = [
'--comment', description '--comment' , description
, '--category', category , '--category' , category
, '--publisher', publisher , '--publisher', publisher
, '--ignore-tables'
] ]
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"' html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')] preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
remove_tags = [ remove_tags = [
dict(name='embed') dict(name=['embed','hr','link','object'])
,dict(name='a', attrs={'class':'a11'}) ,dict(name='a', attrs={'class':'a11'})
,dict(name='hr')
] ]
feeds = [ feeds = [
@ -60,9 +59,7 @@ class Jutarnji(BasicNewsRecipe):
return 'http://www.jutarnji.hr/ispis_clanka.jl?artid=' + rrest return 'http://www.jutarnji.hr/ispis_clanka.jl?artid=' + rrest
def preprocess_html(self, soup): def preprocess_html(self, soup):
mtag = '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">' mtag = '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">\n<meta http-equiv="Content-Language" content="hr-HR"/>'
soup.head.insert(0,mtag)
mtag = '<meta http-equiv="Content-Language" content="hr"/>'
soup.head.insert(0,mtag) soup.head.insert(0,mtag)
for item in soup.findAll(style=True): for item in soup.findAll(style=True):
del item['style'] del item['style']

View File

@ -1,12 +1,12 @@
#!/usr/bin/env python #!/usr/bin/env python
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>' __copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
''' '''
juventudrebelde.cu juventudrebelde.cu
''' '''
from calibre import strftime
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
class Juventudrebelde(BasicNewsRecipe): class Juventudrebelde(BasicNewsRecipe):
@ -20,17 +20,18 @@ class Juventudrebelde(BasicNewsRecipe):
no_stylesheets = True no_stylesheets = True
use_embedded_content = False use_embedded_content = False
encoding = 'cp1252' encoding = 'cp1252'
language = _('Spanish')
cover_url = strftime('http://www.juventudrebelde.cu/UserFiles/File/impreso/iportada-%Y-%m-%d.jpg') cover_url = strftime('http://www.juventudrebelde.cu/UserFiles/File/impreso/iportada-%Y-%m-%d.jpg')
remove_javascript = True remove_javascript = True
html2lrf_options = [ html2lrf_options = [
'--comment', description '--comment' , description
, '--category', category , '--category' , category
, '--publisher', publisher , '--publisher', publisher
, '--ignore-tables' , '--ignore-tables'
] ]
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"' html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
keep_only_tags = [dict(name='div', attrs={'id':'noticia'})] keep_only_tags = [dict(name='div', attrs={'id':'noticia'})]
@ -51,4 +52,3 @@ class Juventudrebelde(BasicNewsRecipe):
del item['style'] del item['style']
return soup return soup
language = _('Spanish')

View File

@ -1,13 +1,12 @@
#!/usr/bin/env python #!/usr/bin/env python
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>' __copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
''' '''
nin.co.yu nin.co.yu
''' '''
import re, urllib import re, urllib
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
class Nin(BasicNewsRecipe): class Nin(BasicNewsRecipe):
@ -27,15 +26,17 @@ class Nin(BasicNewsRecipe):
LOGIN = PREFIX + '/?logout=true' LOGIN = PREFIX + '/?logout=true'
remove_javascript = True remove_javascript = True
use_embedded_content = False use_embedded_content = False
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "monospace1";src:url(res:///opt/sony/ebook/FONT/tt0419m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: left; font-family: serif1, serif} .article_date{font-family: monospace1, monospace} .article_description{font-family: sans1, sans-serif} .navbar{font-family: monospace1, monospace}' language = _('Serbian')
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: justify; font-family: serif1, serif} .article_description{font-family: sans1, sans-serif}'
html2lrf_options = [ html2lrf_options = [
'--comment', description '--comment' , description
, '--category', category , '--category' , category
, '--publisher', publisher , '--publisher', publisher
, '--ignore-tables'
] ]
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"' html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')] preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
@ -69,5 +70,3 @@ class Nin(BasicNewsRecipe):
for item in soup.findAll(style=True): for item in soup.findAll(style=True):
del item['style'] del item['style']
return soup return soup
language = _('Serbian')

View File

@ -1,13 +1,12 @@
#!/usr/bin/env python #!/usr/bin/env python
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>' __copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
''' '''
novosti.rs novosti.rs
''' '''
import re import re
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
class Novosti(BasicNewsRecipe): class Novosti(BasicNewsRecipe):
@ -22,15 +21,17 @@ class Novosti(BasicNewsRecipe):
use_embedded_content = False use_embedded_content = False
encoding = 'utf8' encoding = 'utf8'
remove_javascript = True remove_javascript = True
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "monospace1";src:url(res:///opt/sony/ebook/FONT/tt0419m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: left; font-family: serif1, serif} .article_date{font-family: monospace1, monospace} .article_description{font-family: sans1, sans-serif} .navbar{font-family: monospace1, monospace}' language = _('Serbian')
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: serif1, serif} .article_description{font-family: sans1, sans-serif}'
html2lrf_options = [ html2lrf_options = [
'--comment', description '--comment' , description
, '--category', category , '--category' , category
, '--publisher', publisher , '--publisher', publisher
, '--ignore-tables'
] ]
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"' html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')] preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
@ -40,10 +41,8 @@ class Novosti(BasicNewsRecipe):
feeds = [(u'Vesti', u'http://www.novosti.rs/php/vesti/rss.php')] feeds = [(u'Vesti', u'http://www.novosti.rs/php/vesti/rss.php')]
def preprocess_html(self, soup): def preprocess_html(self, soup):
mtag = '<meta http-equiv="Content-Language" content="sr-Latn"/>' mtag = '<meta http-equiv="Content-Language" content="sr-Latn-RS"/>'
soup.head.insert(0,mtag) soup.head.insert(0,mtag)
for item in soup.findAll(style=True): for item in soup.findAll(style=True):
del item['style'] del item['style']
return soup return soup
language = _('Serbian')

View File

@ -1,13 +1,12 @@
#!/usr/bin/env python #!/usr/bin/env python
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>' __copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
''' '''
nspm.rs nspm.rs
''' '''
import re import re
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
class Nspm(BasicNewsRecipe): class Nspm(BasicNewsRecipe):
@ -16,26 +15,30 @@ class Nspm(BasicNewsRecipe):
description = 'Casopis za politicku teoriju i drustvena istrazivanja' description = 'Casopis za politicku teoriju i drustvena istrazivanja'
publisher = 'NSPM' publisher = 'NSPM'
category = 'news, politics, Serbia' category = 'news, politics, Serbia'
oldest_article = 7 oldest_article = 2
max_articles_per_feed = 100 max_articles_per_feed = 100
no_stylesheets = True no_stylesheets = True
use_embedded_content = False use_embedded_content = False
INDEX = 'http://www.nspm.rs/?alphabet=l' INDEX = 'http://www.nspm.rs/?alphabet=l'
encoding = 'utf8' encoding = 'utf8'
remove_javascript = True remove_javascript = True
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "monospace1";src:url(res:///opt/sony/ebook/FONT/tt0419m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: left; font-family: serif1, serif} .article_date{font-family: monospace1, monospace} .article_description{font-family: sans1, sans-serif} .navbar{font-family: monospace1, monospace}' language = _('Serbian')
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: justify; font-family: serif1, serif} .article_description{font-family: sans1, sans-serif}'
html2lrf_options = [ html2lrf_options = [
'--comment', description '--comment' , description
, '--category', category , '--category' , category
, '--publisher', publisher , '--publisher', publisher
, '--ignore-tables' , '--ignore-tables'
] ]
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"' html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')] preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
remove_tags = [dict(name='a')] remove_tags = [
dict(name=['a','img','link','object','embed'])
,dict(name='td', attrs={'class':'buttonheading'})
]
def get_browser(self): def get_browser(self):
br = BasicNewsRecipe.get_browser() br = BasicNewsRecipe.get_browser()
@ -48,13 +51,12 @@ class Nspm(BasicNewsRecipe):
return url.replace('.html','/stampa.html') return url.replace('.html','/stampa.html')
def preprocess_html(self, soup): def preprocess_html(self, soup):
soup.html['xml:lang'] = 'sr-Latn-RS' lng = 'sr-Latn-RS'
soup.html['lang'] = 'sr-Latn-RS' soup.html['xml:lang'] = lng
soup.html['lang'] = lng
ftag = soup.find('meta',attrs={'http-equiv':'Content-Language'}) ftag = soup.find('meta',attrs={'http-equiv':'Content-Language'})
if ftag: if ftag:
ftag['content'] = 'sr-Latn-RS' ftag['content'] = lng
for item in soup.findAll(style=True): for item in soup.findAll(style=True):
del item['style'] del item['style']
return soup return soup
language = _('Serbian')

View File

@ -1,13 +1,12 @@
#!/usr/bin/env python #!/usr/bin/env python
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>' __copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
''' '''
pescanik.net pescanik.net
''' '''
import re import re
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
class Pescanik(BasicNewsRecipe): class Pescanik(BasicNewsRecipe):
@ -16,30 +15,32 @@ class Pescanik(BasicNewsRecipe):
description = 'Pescanik' description = 'Pescanik'
publisher = 'Pescanik' publisher = 'Pescanik'
category = 'news, politics, Serbia' category = 'news, politics, Serbia'
oldest_article = 7 oldest_article = 5
max_articles_per_feed = 100 max_articles_per_feed = 100
no_stylesheets = True no_stylesheets = True
use_embedded_content = False use_embedded_content = False
remove_javascript = True remove_javascript = True
encoding = 'utf8' encoding = 'utf8'
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "monospace1";src:url(res:///opt/sony/ebook/FONT/tt0419m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: left; font-family: serif1, serif} .article_date{font-family: monospace1, monospace} .article_description{font-family: sans1, sans-serif} .navbar{font-family: monospace1, monospace}' cover_url = "http://pescanik.net/templates/ja_teline/images/logo.png"
language = _('Serbian')
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: serif1, serif} .article_description{font-family: sans1, sans-serif}'
html2lrf_options = [ html2lrf_options = [
'--comment', description '--comment' , description
, '--category', category , '--category' , category
, '--publisher', publisher , '--publisher', publisher
, '--ignore-tables'
] ]
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"' html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
cover_url = "http://pescanik.net/templates/ja_teline/images/logo.png"
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')] preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
remove_tags = [ remove_tags = [
dict(name='td' , attrs={'class':'buttonheading'}) dict(name='td' , attrs={'class':'buttonheading'})
,dict(name='span', attrs={'class':'article_seperator'}) ,dict(name='span', attrs={'class':'article_seperator'})
,dict(name=['object','link']) ,dict(name=['object','link','img','h4','ul'])
] ]
feeds = [(u'Pescanik Online', u'http://pescanik.net/index.php?option=com_rd_rss&id=12')] feeds = [(u'Pescanik Online', u'http://pescanik.net/index.php?option=com_rd_rss&id=12')]
@ -54,5 +55,3 @@ class Pescanik(BasicNewsRecipe):
for item in soup.findAll(style=True): for item in soup.findAll(style=True):
del item['style'] del item['style']
return soup return soup
language = _('Serbian')

View File

@ -6,7 +6,6 @@ __copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
politika.rs politika.rs
''' '''
import re import re
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
class Politika(BasicNewsRecipe): class Politika(BasicNewsRecipe):
@ -16,13 +15,13 @@ class Politika(BasicNewsRecipe):
publisher = 'Politika novine i Magazini d.o.o' publisher = 'Politika novine i Magazini d.o.o'
category = 'news, politics, Serbia' category = 'news, politics, Serbia'
oldest_article = 2 oldest_article = 2
language = _('Serbian')
max_articles_per_feed = 100 max_articles_per_feed = 100
no_stylesheets = True no_stylesheets = True
use_embedded_content = False use_embedded_content = False
remove_javascript = True remove_javascript = True
encoding = 'utf8' encoding = 'utf8'
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "monospace1";src:url(res:///opt/sony/ebook/FONT/tt0419m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: left; font-family: serif1, serif} .article_date{font-family: monospace1, monospace} .article_description{font-family: sans1, sans-serif} .navbar{font-family: monospace1, monospace}' language = _('Serbian')
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: serif1, serif} .article_description{font-family: sans1, sans-serif}'
html2lrf_options = [ html2lrf_options = [
'--comment', description '--comment', description
@ -61,6 +60,6 @@ class Politika(BasicNewsRecipe):
for item in soup.findAll(style=True): for item in soup.findAll(style=True):
del item['style'] del item['style']
ftag = soup.find('div',attrs={'class':'content_center_border'}) ftag = soup.find('div',attrs={'class':'content_center_border'})
if ftag: if ftag.has_key('align'):
ftag['align'] = 'left' del ftag['align']
return soup return soup

View File

@ -4,11 +4,10 @@ __license__ = 'GPL v3'
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>' __copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>'
''' '''
vijesti.cg.yu vijesti.me
''' '''
import re import re
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
class Vijesti(BasicNewsRecipe): class Vijesti(BasicNewsRecipe):
@ -22,10 +21,11 @@ class Vijesti(BasicNewsRecipe):
no_stylesheets = True no_stylesheets = True
remove_javascript = True remove_javascript = True
encoding = 'cp1250' encoding = 'cp1250'
cover_url = 'http://www.vijesti.cg.yu/img/logo.gif' cover_url = 'http://www.vijesti.me/img/logo.gif'
remove_javascript = True remove_javascript = True
use_embedded_content = False use_embedded_content = False
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "monospace1";src:url(res:///opt/sony/ebook/FONT/tt0419m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: left; font-family: serif1, serif} .article_date{font-family: monospace1, monospace} .article_description{font-family: sans1, sans-serif} .navbar{font-family: monospace1, monospace}' language = _('Serbian')
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: justify; font-family: serif1, serif} .article_description{font-family: sans1, sans-serif}'
html2lrf_options = [ html2lrf_options = [
'--comment', description '--comment', description
@ -39,12 +39,9 @@ class Vijesti(BasicNewsRecipe):
keep_only_tags = [dict(name='div', attrs={'id':'mainnews'})] keep_only_tags = [dict(name='div', attrs={'id':'mainnews'})]
remove_tags = [ remove_tags = [dict(name=['object','link','embed'])]
dict(name='div', attrs={'align':'right'})
,dict(name=['object','link'])
]
feeds = [(u'Sve vijesti', u'http://www.vijesti.cg.yu/rss.php' )] feeds = [(u'Sve vijesti', u'http://www.vijesti.me/rss.php' )]
def preprocess_html(self, soup): def preprocess_html(self, soup):
soup.html['xml:lang'] = 'sr-Latn-ME' soup.html['xml:lang'] = 'sr-Latn-ME'
@ -56,5 +53,3 @@ class Vijesti(BasicNewsRecipe):
del item['align'] del item['align']
item.insert(0,'<br /><br />') item.insert(0,'<br /><br />')
return soup return soup
language = _('Serbian')

View File

@ -1,14 +1,13 @@
#!/usr/bin/env python #!/usr/bin/env python
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>' __copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
''' '''
vreme.com vreme.com
''' '''
import re import re
from calibre import strftime from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
class Vreme(BasicNewsRecipe): class Vreme(BasicNewsRecipe):
@ -24,15 +23,17 @@ class Vreme(BasicNewsRecipe):
LOGIN = 'http://www.vreme.com/account/index.php' LOGIN = 'http://www.vreme.com/account/index.php'
remove_javascript = True remove_javascript = True
use_embedded_content = False use_embedded_content = False
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "monospace1";src:url(res:///opt/sony/ebook/FONT/tt0419m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: left; font-family: serif1, serif} .article_date{font-family: monospace1, monospace} .article_description{font-family: sans1, sans-serif} .navbar{font-family: monospace1, monospace}' language = _('Serbian')
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: serif1, serif} .article_description{font-family: sans1, sans-serif}'
html2lrf_options = [ html2lrf_options = [
'--comment', description '--comment' , description
, '--category', category , '--category' , category
, '--publisher', publisher , '--publisher', publisher
, '--ignore-tables'
] ]
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"' html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')] preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
@ -87,7 +88,12 @@ class Vreme(BasicNewsRecipe):
del soup.body['text' ] del soup.body['text' ]
del soup.body['bgcolor'] del soup.body['bgcolor']
del soup.body['onload' ] del soup.body['onload' ]
mtag = '<meta http-equiv="Content-Language" content="sr-Latn"/>' for item in soup.findAll('table'):
if item.has_key('width'):
del item['width']
if item.has_key('height'):
del item['height']
mtag = '<meta http-equiv="Content-Language" content="sr-Latn-RS"/>'
soup.head.insert(0,mtag) soup.head.insert(0,mtag)
tbl = soup.body.table tbl = soup.body.table
tbbb = soup.find('td') tbbb = soup.find('td')
@ -104,5 +110,3 @@ class Vreme(BasicNewsRecipe):
if cover_item: if cover_item:
cover_url = self.INDEX + cover_item['src'] cover_url = self.INDEX + cover_item['src']
return cover_url return cover_url
language = _('Serbian')

View File

@ -8,7 +8,7 @@ Fetch a webpage and its links recursively. The webpages are saved to disk in
UTF-8 encoding with any charset declarations removed. UTF-8 encoding with any charset declarations removed.
''' '''
import sys, socket, os, urlparse, logging, re, time, copy, urllib2, threading, traceback import sys, socket, os, urlparse, logging, re, time, copy, urllib2, threading, traceback
from urllib import url2pathname from urllib import url2pathname, quote
from threading import RLock from threading import RLock
from httplib import responses from httplib import responses
from PIL import Image from PIL import Image
@ -179,6 +179,8 @@ class RecursiveFetcher(object, LoggingInterface):
delta = time.time() - self.last_fetch_at delta = time.time() - self.last_fetch_at
if delta < self.delay: if delta < self.delay:
time.sleep(delta) time.sleep(delta)
if re.search(r'\s+', url) is not None:
url = quote(url)
with self.browser_lock: with self.browser_lock:
try: try:
with closing(self.browser.open(url)) as f: with closing(self.browser.open(url)) as f:

View File

@ -58,7 +58,7 @@ class Checker(object):
"specific sections. You must explicitly pass " "specific sections. You must explicitly pass "
"application config via " "application config via "
"cherrypy.tree.mount(..., config=app_config)") "cherrypy.tree.mount(..., config=app_config)")
warnings.warn(msg) warnings.warn(msg[:5])
return return
def check_static_paths(self): def check_static_paths(self):