mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Sync to trunk.
This commit is contained in:
commit
0c8fdbd647
@ -352,7 +352,7 @@ License: other
|
||||
Liberation Fonts
|
||||
-----------------
|
||||
calibre includes a copy of the liberation fonts, available from
|
||||
https://calibre.kovidgoyal.net/downloads/liberation-fonts
|
||||
https://calibre-ebook.com/downloads/liberation-fonts
|
||||
|
||||
BSD License (for all the BSD licensed code indicated above)
|
||||
-----------------------------------------------------------
|
||||
|
172
Changelog.yaml
Normal file
172
Changelog.yaml
Normal file
@ -0,0 +1,172 @@
|
||||
# Each release can have new features and bug fixes. Each of which
|
||||
# must have a title and can optionally have linked tickets and a description.
|
||||
# In addition they can have a type field which defaults to minor, but should be major
|
||||
# for important features/bug fixes.
|
||||
# Also, each release can have new and improved recipes.
|
||||
|
||||
- version: 0.6.25
|
||||
date: 2009-11-30
|
||||
|
||||
new features:
|
||||
- title: Add option to swap title and author in the Bulk metadata dialog
|
||||
tickets: [3885]
|
||||
|
||||
- title: Make the metadata download plugins customizable
|
||||
|
||||
- title: Various improvements to the conversion of PDB/PML books with an all new state machine based parser
|
||||
|
||||
- title: Driver for upgraded SONY PRS 500
|
||||
|
||||
- title: Full support for PocketBook 360 with SD card
|
||||
|
||||
- title: "ODT Input: Reflow positioned images"
|
||||
tickets: [4060]
|
||||
|
||||
- title: Allow custom new recipes to reverse article order in feeds
|
||||
tickets: [4095]
|
||||
|
||||
- title: "Conversion pipeline: Add option to control the inserted paragraph indent when using the remove blank line between paragraphs option"
|
||||
|
||||
- title: When reading metadata from PDf files, look for the ISBN in the file text.
|
||||
tickets: [3013]
|
||||
|
||||
- title: Periodically check for updates to calibre instead of just at startup
|
||||
tickets: [4040]
|
||||
|
||||
bug fixes:
|
||||
- title: Reorganize Dutch language news sources into Belgium and Netherlands categories
|
||||
tickets: [4098]
|
||||
|
||||
- title: Fix bad markup in some New York Times articles causing download to fail
|
||||
tickets: [4032]
|
||||
|
||||
- title: Fix recipe for Glasgow Herald
|
||||
|
||||
- title: Fixed recipe for The Australian
|
||||
|
||||
- title: Add PDF to list of supported formats for the Kindle 2
|
||||
|
||||
|
||||
new recipes:
|
||||
- title: The Economist (no subscription required)
|
||||
author: Kovid Goyal
|
||||
|
||||
- title: Sports Illustrated1
|
||||
author: kwetal
|
||||
|
||||
- title: Levante
|
||||
author: kwetal
|
||||
|
||||
- title: ncrnext
|
||||
author: kwetal
|
||||
|
||||
improved recipes:
|
||||
- The Philadelphia Inquirer
|
||||
- Harpers
|
||||
- Our Daily Bread
|
||||
- Sydney Morning Herald
|
||||
|
||||
|
||||
- version: 0.6.24
|
||||
date: 2009-11-16
|
||||
|
||||
new features:
|
||||
- title: Add option to swap title and author in the Bulk metadata dialog
|
||||
tickets: [3885]
|
||||
|
||||
- title: Add option to download only social metadata
|
||||
tickets: [4015]
|
||||
|
||||
- title: Update bundled odfpy library to 0.9.2 for improved conversion of ODT files.
|
||||
|
||||
- title: Output resolved conversion options in conversion log, for easier debugging.
|
||||
|
||||
- title: Add option to Bulk conversion dialog to not use per-book settings from a previous conversion
|
||||
|
||||
|
||||
bug fixes:
|
||||
- title: "Device drivers: Ignore files on the device when there is a file system/file name encoding error"
|
||||
description: >
|
||||
Sometimes, the presence of files on the e-book device that have special characters in the file name
|
||||
would cause calibre to throw an error when scanning the device for books. Now, calibre will simply
|
||||
ignore the files whose names it cannot decode.
|
||||
|
||||
- title: Fix various bugs in the downloading of social metadata in bulk
|
||||
tickets: [4028, 4022]
|
||||
|
||||
- title: Do not URL encode paths to files in the XML output of calibredb list
|
||||
description: Stanza on the iPhone could not handle URL encoded paths
|
||||
|
||||
- title: Fix rendering of stars in rating column in the library view
|
||||
tickets: [3944]
|
||||
|
||||
- title: Fix PML parsing changes introduced in 0.6.22 as they break PDB eReader input badly.
|
||||
|
||||
- title: "Conversion pipeline: Respect UTF-8/32 BOM mark when decoding files in addition to UTF-16 BOM."
|
||||
tickets: [4025]
|
||||
|
||||
- title: Restore all sections to Guardian newspaper download
|
||||
|
||||
- title: "Social metadata download: If the user specifies that they dont want social metadata, don't get tags from the basic metadata sources either"
|
||||
|
||||
|
||||
new recipes:
|
||||
- title: The Havard Business Review
|
||||
author: Kovid Goyal
|
||||
|
||||
- title: Fokke en Sukke
|
||||
author: kwetal
|
||||
|
||||
improved recipes:
|
||||
- The Philadelphia Inquirer
|
||||
|
||||
- version: 0.6.22
|
||||
date: 2009-11-13
|
||||
|
||||
new features:
|
||||
- title: Support downloading of social metadata (ratings/tags/reviews etc.)
|
||||
description: >
|
||||
calibre is now able to download social metadata like tags/rating/reviews etc.,
|
||||
in addition to normal metadata and covers. Currently it uses Amazon as the only
|
||||
source for social metadata, but the download system supports plugins for the
|
||||
addition of more sources in the future.
|
||||
type: major
|
||||
tickets: [2860]
|
||||
|
||||
- title: Convert metadata download system to plugins, with builtin plugins for isbndb.com, Google Books and Amazon
|
||||
|
||||
- title: PML metadata reader
|
||||
|
||||
- title: "PML Input: Fix handling of images and various other improvements"
|
||||
|
||||
bug fixes:
|
||||
- title: Fix NYT Top stories, Barrons, New Scientist and Irish Times recipes
|
||||
tickets: [4009, 3964, 3972, 3987]
|
||||
|
||||
- title: "FB2 Output: Handle large paragraphs"
|
||||
tickets: [3941]
|
||||
|
||||
- title: "Bulk metadata download: Don't fail on downloading all remaining covers if there is an error downloading a single cover in the list"
|
||||
|
||||
- title: Populate site_customization for Input plugins
|
||||
tickets: [3957]
|
||||
|
||||
- title: Fix news download scheduler raising an error for scheduled custom recipe that is subsequently deleted
|
||||
tickets: [4010]
|
||||
|
||||
|
||||
|
||||
new recipes:
|
||||
- title: NPR
|
||||
author: onyxrev
|
||||
|
||||
- title: Welt Online
|
||||
author: Oliver Niesner
|
||||
|
||||
- title: An Druma Mor
|
||||
author: "David O'Callaghan"
|
||||
|
||||
improved recipes:
|
||||
- Critica Digital
|
||||
- Infobae
|
||||
- Spiegel International
|
4
README
4
README
@ -4,10 +4,10 @@ devices. It can go out to the internet and fetch metadata for your books. \
|
||||
It can download newspapers and convert them into e-books for convenient \
|
||||
reading. It is cross platform, running on Linux, Windows and OS X.
|
||||
|
||||
For screenshots: https://calibre.kovidgoyal.net/wiki/Screenshots
|
||||
For screenshots: https://calibre-ebook.com/demo
|
||||
|
||||
For installation/usage instructions please see
|
||||
http://calibre.kovidgoyal.net
|
||||
http://calibre-ebook.com
|
||||
|
||||
For source code access:
|
||||
bzr branch lp:calibre
|
||||
|
@ -7,11 +7,11 @@
|
||||
<script type="text/javascript" src="/static/date.js" charset="utf-8"></script>
|
||||
<script type="text/javascript" src="/static/jquery.js" charset="utf-8"></script>
|
||||
<script type="text/javascript" src="/static/gui.js" charset="utf-8"></script>
|
||||
<link rel="icon" href="http://calibre.kovidgoyal.net/chrome/site/favicon.ico" type="image/x-icon" />
|
||||
<link rel="icon" href="http://calibre-ebook.com/favicon.ico" type="image/x-icon" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="banner">
|
||||
<a style="border: 0pt" href="http://calibre.kovidgoyal.net" alt="calibre" title="calibre"><img style="border:0pt" src="/static/calibre.png" alt="calibre" /></a>
|
||||
<a style="border: 0pt" href="http://calibre-ebook.com" alt="calibre" title="calibre"><img style="border:0pt" src="/static/calibre.png" alt="calibre" /></a>
|
||||
</div>
|
||||
|
||||
<div id="search_box">
|
||||
|
@ -9,7 +9,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
|
||||
class DeStandaard(BasicNewsRecipe):
|
||||
title = u'De Standaard'
|
||||
__author__ = u'Darko Miletic'
|
||||
language = 'nl'
|
||||
language = 'nl_BE'
|
||||
|
||||
description = u'News from Belgium'
|
||||
oldest_article = 7
|
||||
|
@ -19,7 +19,7 @@ class DeGentenaarOnline(BasicNewsRecipe):
|
||||
no_stylesheets = True
|
||||
use_embedded_content = False
|
||||
encoding = 'utf-8'
|
||||
language = 'nl'
|
||||
language = 'nl_BE'
|
||||
|
||||
lang = 'nl-BE'
|
||||
direction = 'ltr'
|
||||
|
@ -13,7 +13,7 @@ class DeMorganBe(BasicNewsRecipe):
|
||||
__author__ = u'Darko Miletic'
|
||||
description = u'News from Belgium'
|
||||
oldest_article = 7
|
||||
language = 'nl'
|
||||
language = 'nl_BE'
|
||||
|
||||
max_articles_per_feed = 100
|
||||
no_stylesheets = True
|
||||
|
68
resources/recipes/economist_free.recipe
Normal file
68
resources/recipes/economist_free.recipe
Normal file
@ -0,0 +1,68 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
import time
|
||||
from datetime import datetime
|
||||
from lxml import html
|
||||
|
||||
class Economist(BasicNewsRecipe):
|
||||
|
||||
title = 'The Economist (free)'
|
||||
language = 'en'
|
||||
|
||||
__author__ = "Kovid Goyal"
|
||||
description = ('Global news and current affairs from a European perspective.'
|
||||
' Much slower than the subscription based version.')
|
||||
|
||||
oldest_article = 6.5
|
||||
cover_url = 'http://www.economist.com/images/covers/currentcovereu_large.jpg'
|
||||
remove_tags = [dict(name=['script', 'noscript', 'title'])]
|
||||
remove_tags_before = dict(name=lambda tag: tag.name=='title' and tag.parent.name=='body')
|
||||
|
||||
def parse_index(self):
|
||||
from calibre.web.feeds.feedparser import parse
|
||||
raw = self.index_to_soup(
|
||||
'http://feeds.feedburner.com/economist/full_print_edition',
|
||||
raw=True)
|
||||
entries = parse(raw).entries
|
||||
feeds = {}
|
||||
for i, item in enumerate(entries):
|
||||
from calibre.web.feeds import Article
|
||||
published = time.gmtime(item.get('timestamp', time.time()))
|
||||
title = item.get('title', _('Untitled article'))
|
||||
link = item.get('link', None)
|
||||
description = item.get('description', '')
|
||||
author = item.get('author', '')
|
||||
|
||||
try:
|
||||
feedtitle, link = self.process_eco_feed_article(link)
|
||||
self.log('Found print version for article:', title)
|
||||
except:
|
||||
self.log.exception('Failed to process article:', title)
|
||||
continue
|
||||
|
||||
a = Article(i, title, link, author, description, published, '')
|
||||
delta = datetime.utcnow() - a.utctime
|
||||
if delta.days*24*3600 + delta.seconds > 24*3600*self.oldest_article:
|
||||
self.log.debug('Skipping article %s (%s) from feed %s as it is too old.'%(title, a.localtime.strftime('%a, %d %b, %Y %H:%M'), title))
|
||||
continue
|
||||
|
||||
|
||||
article = dict(title=a.title, description=a.text_summary,
|
||||
date=time.strftime(self.timefmt, a.date), author=a.author, url=a.url)
|
||||
if feedtitle not in feeds:
|
||||
feeds[feedtitle] = []
|
||||
feeds[feedtitle].append(article)
|
||||
return [(t, a) for t, a in feeds.items()]
|
||||
|
||||
def process_eco_feed_article(self, url):
|
||||
ret = self.browser.open(url)
|
||||
raw = ret.read()
|
||||
url = self.browser.geturl().replace('displaystory', 'PrinterFriendly').strip()
|
||||
root = html.fromstring(raw)
|
||||
matches = root.xpath('//*[@class = "article-section"]')
|
||||
feedtitle = 'Miscellaneous'
|
||||
if matches:
|
||||
feedtitle = html.tostring(matches[0], method='text',
|
||||
encoding=unicode)
|
||||
return feedtitle, url
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
import re
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
@ -9,27 +8,22 @@ class GlasgowHerald(BasicNewsRecipe):
|
||||
no_stylesheets = True
|
||||
language = 'en_GB'
|
||||
|
||||
__author__ = 'McCande'
|
||||
__author__ = 'Kovid Goyal'
|
||||
|
||||
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>'),
|
||||
keep_only_tags = [dict(attrs={'class':'article'})]
|
||||
remove_tags = [
|
||||
dict(id=['pic-nav']),
|
||||
dict(attrs={'class':['comments-top']})
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
|
||||
|
||||
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')]
|
||||
(u'News', u'http://www.heraldscotland.com/cmlink/1.758'),
|
||||
(u'Sport', u'http://www.heraldscotland.com/cmlink/1.761'),
|
||||
(u'Business', u'http://www.heraldscotland.com/cmlink/1.763'),
|
||||
(u'Life & Style', u'http://www.heraldscotland.com/cmlink/1.770'),
|
||||
(u'Arts & Entertainment',
|
||||
u'http://www.heraldscotland.com/cmlink/1.768',),
|
||||
(u'Columnists', u'http://www.heraldscotland.com/cmlink/1.658574')]
|
||||
|
||||
|
||||
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
|
||||
|
@ -19,7 +19,7 @@ class GazetvanAntwerpen(BasicNewsRecipe):
|
||||
no_stylesheets = True
|
||||
use_embedded_content = False
|
||||
encoding = 'utf-8'
|
||||
language = 'nl'
|
||||
language = 'nl_BE'
|
||||
|
||||
lang = 'nl-BE'
|
||||
direction = 'ltr'
|
||||
|
@ -29,6 +29,12 @@ class Harpers(BasicNewsRecipe):
|
||||
|
||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\noverride_css=" p {text-indent: 0em; margin-top: 0em; margin-bottom: 0.5em} img {margin-top: 0em; margin-bottom: 0.4em}"'
|
||||
|
||||
extra_css = '''
|
||||
h1{ font-family:georgia ; color:#111111; font-size:large;}
|
||||
.box-of-helpful{ font-family:arial ; font-size:x-small;}
|
||||
p{font-family:georgia ;}
|
||||
.caption{font-family:Verdana,sans-serif;font-size:x-small;color:#666666;}
|
||||
'''
|
||||
|
||||
keep_only_tags = [ dict(name='div', attrs={'id':'cached'}) ]
|
||||
remove_tags = [
|
||||
@ -38,6 +44,17 @@ class Harpers(BasicNewsRecipe):
|
||||
|
||||
feeds = [(u"Harper's Magazine", u'http://www.harpers.org/rss/frontpage-rss20.xml')]
|
||||
|
||||
def get_cover_url(self):
|
||||
cover_url = None
|
||||
index = 'http://harpers.org/'
|
||||
soup = self.index_to_soup(index)
|
||||
link_item = soup.find(name = 'img',attrs= {'class':"cover"})
|
||||
print link_item
|
||||
if link_item:
|
||||
cover_url = 'http://harpers.org' + link_item['src']
|
||||
print cover_url
|
||||
return cover_url
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
mcharset = Tag(soup,'meta',[("http-equiv","Content-Type"),("content","text/html; charset=utf-8")])
|
||||
soup.head.insert(1,mcharset)
|
||||
@ -47,3 +64,5 @@ class Harpers(BasicNewsRecipe):
|
||||
del item['xmlns']
|
||||
return soup
|
||||
|
||||
|
||||
|
||||
|
@ -19,7 +19,7 @@ class HLN_be(BasicNewsRecipe):
|
||||
no_stylesheets = True
|
||||
use_embedded_content = False
|
||||
encoding = 'utf-8'
|
||||
language = 'nl'
|
||||
language = 'nl_BE'
|
||||
|
||||
lang = 'nl-BE'
|
||||
direction = 'ltr'
|
||||
|
@ -19,7 +19,7 @@ class HLN_be(BasicNewsRecipe):
|
||||
use_embedded_content = False
|
||||
no_stylesheets = True
|
||||
encoding = 'utf-8'
|
||||
language = 'nl'
|
||||
language = 'nl_BE'
|
||||
|
||||
|
||||
conversion_options = {
|
||||
|
@ -10,7 +10,7 @@ class IrishIndependent(BasicNewsRecipe):
|
||||
title = u'Irish Independent'
|
||||
description = 'Irish and World news from Irelands Bestselling Daily Broadsheet'
|
||||
__author__ = 'Neil Grogan'
|
||||
language = 'en_UK'
|
||||
language = 'en_GB'
|
||||
oldest_article = 7
|
||||
max_articles_per_feed = 100
|
||||
remove_tags_before = dict(id='article')
|
||||
|
68
resources/recipes/levante.recipe
Normal file
68
resources/recipes/levante.recipe
Normal file
@ -0,0 +1,68 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
from calibre.ebooks.BeautifulSoup import Tag
|
||||
|
||||
class LevanteRecipe(BasicNewsRecipe):
|
||||
__license__ = 'GPL v3'
|
||||
__author__ = 'kwetal'
|
||||
version = 1
|
||||
language = 'es'
|
||||
description = u'El Mercantil Valenciano'
|
||||
title = u'Levante'
|
||||
|
||||
oldest_article = 2
|
||||
max_articles_per_feed = 100
|
||||
encoding = 'latin1'
|
||||
no_stylesheets = True
|
||||
remove_javascript = True
|
||||
|
||||
# Feeds taken from http://www.levante-emv.com/servicios/rss/rss.jsp?pServicio=rss
|
||||
# Feed titles are without accented characters for now. Hope to resolve this in the future.
|
||||
feeds = []
|
||||
feeds.append((u'Portada Valencia', u'http://www.levante-emv.com/elementosInt/rss/1'))
|
||||
feeds.append((u'Portada Castello', u'http://www.levante-emv.com/elementosInt/rss/2'))
|
||||
feeds.append((u'Portada Alacant', u'http://www.levante-emv.com/elementosInt/rss/3'))
|
||||
feeds.append((u'Lo Mas Leido', u'http://www.levante-emv.com/elementosInt/rss/LoMas'))
|
||||
feeds.append((u'Seccion al minuto', u'http://www.levante-emv.com/elementosInt/rss/AlMinuto'))
|
||||
feeds.append((u'Comunidad Valenciana', u'http://www.levante-emv.com/elementosInt/rss/19'))
|
||||
feeds.append((u'Valencia', u'http://www.levante-emv.com/elementosInt/rss/16'))
|
||||
feeds.append((u'Castello', u'http://www.levante-emv.com/elementosInt/rss/4'))
|
||||
feeds.append((u'Alacant', u'http://www.levante-emv.com/elementosInt/rss/17'))
|
||||
feeds.append((u'Comarcas', u'http://www.levante-emv.com/elementosInt/rss/12'))
|
||||
feeds.append((u'Espana', u'http://www.levante-emv.com/elementosInt/rss/6'))
|
||||
feeds.append((u'Internacional', u'http://www.levante-emv.com/elementosInt/rss/7'))
|
||||
feeds.append((u'Opinion', u'http://www.levante-emv.com/elementosInt/rss/5'))
|
||||
feeds.append((u'Economia', u'http://www.levante-emv.com/elementosInt/rss/8'))
|
||||
feeds.append((u'Sociedad', u'http://www.levante-emv.com/elementosInt/rss/9'))
|
||||
feeds.append((u'Sucesos', u'http://www.levante-emv.com/elementosInt/rss/10'))
|
||||
feeds.append((u'Deportes', u'http://www.levante-emv.com/elementosInt/rss/11'))
|
||||
feeds.append((u'Motor', u'http://www.levante-emv.com/elementosInt/rss/31'))
|
||||
feeds.append((u'Panorama', u'http://www.levante-emv.com/elementosInt/rss/18'))
|
||||
feeds.append((u'Salud y Vida', u'http://www.levante-emv.com/elementosInt/rss/20'))
|
||||
feeds.append((u'Ciencia y Salud', u'http://www.levante-emv.com/elementosInt/rss/44'))
|
||||
feeds.append((u'Ciencia e Investigacion', u'http://www.levante-emv.com/elementosInt/rss/23'))
|
||||
feeds.append((u'Ensenanza', u'http://www.levante-emv.com/elementosInt/rss/22'))
|
||||
feeds.append((u'Fiestas y Tradiciones', u'http://www.levante-emv.com/elementosInt/rss/24'))
|
||||
feeds.append((u'Club Diario', u'http://www.levante-emv.com/elementosInt/rss/26'))
|
||||
feeds.append((u'Juntos', u'http://www.levante-emv.com/elementosInt/rss/33'))
|
||||
feeds.append((u'Integrados', u'http://www.levante-emv.com/elementosInt/rss/35'))
|
||||
feeds.append((u'Agenda', u'http://www.levante-emv.com/elementosInt/rss/36'))
|
||||
feeds.append((u'Cultura', u'http://www.levante-emv.com/elementosInt/rss/39'))
|
||||
feeds.append((u'Tecnologia', u'http://www.levante-emv.com/elementosInt/rss/40'))
|
||||
feeds.append((u'Gente', u'http://www.levante-emv.com/elementosInt/rss/41'))
|
||||
feeds.append((u'Television', u'http://www.levante-emv.com/elementosInt/rss/42'))
|
||||
feeds.append((u'Participa', u'http://www.levante-emv.com/elementosInt/rss/45'))
|
||||
|
||||
keep_only_tags = [dict(name='div', attrs={'class' : 'noticia_titular'}),
|
||||
dict(name='div', attrs={'class' : 'subtitulo'}),
|
||||
dict(name='div', attrs={'id' : 'noticia_texto', 'class' : 'noticia_texto'})]
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
# Nuke some real crappy html
|
||||
theirHead = soup.head
|
||||
theirHead.extract()
|
||||
myHead = Tag(soup, 'head')
|
||||
soup.insert(0, myHead)
|
||||
|
||||
return soup
|
||||
|
||||
|
@ -13,7 +13,6 @@
|
||||
##
|
||||
## Version 0.3-2008_2_28
|
||||
## Based on WIRED.py by David Chen, 2007, and newsweek.py, bbc.py, nytimes.py by Kovid Goyal
|
||||
## https://calibre.kovidgoyal.net/wiki/UserProfiles
|
||||
##
|
||||
## Usage:
|
||||
## >web2lrf --user-profile nasa.py
|
||||
|
114
resources/recipes/ncrnext.recipe
Normal file
114
resources/recipes/ncrnext.recipe
Normal file
@ -0,0 +1,114 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
from calibre.ebooks.BeautifulSoup import BeautifulSoup
|
||||
|
||||
class NrcNextRecipe(BasicNewsRecipe):
|
||||
__license__ = 'GPL v3'
|
||||
__author__ = 'kwetal'
|
||||
version = 1
|
||||
language = 'nl'
|
||||
description = u'Dutch newsblog from the Dutch daily newspaper nrcnext.'
|
||||
title = u'nrcnext'
|
||||
|
||||
no_stylesheets = True
|
||||
template_css = ''
|
||||
|
||||
# I want to do some special processing on the articles. I could not solve it with the 'extra_css' property . So we do it the hard way.
|
||||
keep_only_tags = [dict(name='div', attrs={'id' : 'main'})]
|
||||
# If that's overkill for you comment out the previous line and uncomment the next. Then get rid of the preprocess_html() method.
|
||||
#keep_only_tags = [dict(name='div', attrs={'class' : 'post'}), dict(name='div', attrs={'class' : 'vlag'}) ]
|
||||
|
||||
remove_tags = [dict(name = 'div', attrs = {'class' : 'meta'}),
|
||||
dict(name = 'div', attrs = {'class' : 'datumlabel'}),
|
||||
dict(name = 'ul', attrs = {'class' : 'cats single'}),
|
||||
dict(name = 'ul', attrs = {'class' : 'cats onderwerpen'}),
|
||||
dict(name = 'ul', attrs = {'class' : 'cats rubrieken'})]
|
||||
|
||||
use_embedded_content = False
|
||||
|
||||
def parse_index(self) :
|
||||
# Use the wesbite as an index. Their RSS feeds can be out of date.
|
||||
feeds = {}
|
||||
feeds[u'columnisten'] = u'http://www.nrcnext.nl/columnisten/'
|
||||
feeds[u'koken'] = u'http://www.nrcnext.nl/koken/'
|
||||
feeds[u'geld & werk'] = u'http://www.nrcnext.nl/geld-en-werk/'
|
||||
feeds[u'vandaag'] = u'http://www.nrcnext.nl'
|
||||
feeds[u'city life in afrika'] = u'http://www.nrcnext.nl/city-life-in-afrika/'
|
||||
answer = []
|
||||
articles = {}
|
||||
indices = []
|
||||
|
||||
for index, feed in feeds.items() :
|
||||
soup = self.index_to_soup(feed)
|
||||
|
||||
for post in soup.findAll(True, attrs={'class' : 'post'}) :
|
||||
# Find the links to the actual articles and rember the location they're pointing to and the title
|
||||
a = post.find('a', attrs={'rel' : 'bookmark'})
|
||||
href = a['href']
|
||||
title = a.renderContents()
|
||||
|
||||
if index == 'columnisten' :
|
||||
# In this feed/page articles can be written by more than one author. It is nice to see their names in the titles.
|
||||
flag = post.find('h2', attrs = {'class' : 'vlag'})
|
||||
author = flag.contents[0].renderContents()
|
||||
completeTitle = u''.join([author, u': ', title])
|
||||
else :
|
||||
completeTitle = title
|
||||
|
||||
# Add the article to a temporary list
|
||||
article = {'title' : completeTitle, 'date' : u'', 'url' : href, 'description' : '<p> </p>'}
|
||||
if not articles.has_key(index) :
|
||||
articles[index] = []
|
||||
articles[index].append(article)
|
||||
|
||||
# Add the index title to a temporary list
|
||||
indices.append(index)
|
||||
|
||||
# Now, sort the temporary list of feeds in the order they appear on the website
|
||||
indices = self.sort_index_by(indices, {u'columnisten' : 1, u'koken' : 3, u'geld & werk' : 2, u'vandaag' : 0, u'city life in afrika' : 4})
|
||||
# Apply this sort order to the actual list of feeds and articles
|
||||
answer = [(key, articles[key]) for key in indices if articles.has_key(key)]
|
||||
|
||||
return answer
|
||||
|
||||
def preprocess_html(self, soup) :
|
||||
# This method is called for every page, be it cartoon or TOC. We need to process each in their own way
|
||||
if soup.find('div', attrs = {'id' : 'main', 'class' : 'single'}) :
|
||||
# It's an article, find the interesting part
|
||||
tag = soup.find('div', attrs = {'class' : 'post'})
|
||||
if tag :
|
||||
# And replace any links with their text, so they don't show up underlined on my reader.
|
||||
for link in tag.findAll('a') :
|
||||
link.replaceWith(link.renderContents())
|
||||
|
||||
# Slows down my Sony reader; feel free to comment out
|
||||
for movie in tag.findAll('span', attrs = {'class' : 'vvqbox vvqvimeo'}) :
|
||||
movie.extract()
|
||||
for movie in tag.findAll('span', attrs = {'class' : 'vvqbox vvqyoutube'}) :
|
||||
movie.extract()
|
||||
|
||||
homeMadeSoup = BeautifulSoup('<html><head></head><body></body></html>')
|
||||
body = homeMadeSoup.find('body')
|
||||
body.append(tag)
|
||||
|
||||
return homeMadeSoup
|
||||
else :
|
||||
# This should never happen and other famous last words...
|
||||
return soup
|
||||
else :
|
||||
# It's a TOC, return the whole lot.
|
||||
return soup
|
||||
|
||||
def postproces_html(self, soup) :
|
||||
# Should not happen, but it does. Slows down my Sony eReader
|
||||
for img in soup.findAll('img') :
|
||||
if img['src'].startswith('http://') :
|
||||
img.extract()
|
||||
|
||||
# Happens for some movies which we are not able to view anyway
|
||||
for iframe in soup.findAll('iframe') :
|
||||
if iframe['src'].startswith('http://') :
|
||||
iframe.extract()
|
||||
|
||||
|
||||
|
||||
|
@ -14,7 +14,7 @@ class NYTimes(BasicNewsRecipe):
|
||||
|
||||
title = 'New York Times Top Stories'
|
||||
__author__ = 'GRiker'
|
||||
language = _('English')
|
||||
language = 'en'
|
||||
description = 'Top Stories from the New York Times'
|
||||
|
||||
# List of sections typically included in Top Stories. Use a keyword from the
|
||||
|
@ -22,7 +22,10 @@ class NYTimes(BasicNewsRecipe):
|
||||
remove_tags_before = dict(id='article')
|
||||
remove_tags_after = dict(id='article')
|
||||
remove_tags = [dict(attrs={'class':['articleTools', 'post-tools', 'side_tool', 'nextArticleLink clearfix']}),
|
||||
dict(id=['footer', 'toolsRight', 'articleInline', 'navigation', 'archive', 'side_search', 'blog_sidebar', 'side_tool', 'side_index']),
|
||||
dict(id=['footer', 'toolsRight', 'articleInline',
|
||||
'navigation', 'archive', 'side_search', 'blog_sidebar',
|
||||
'side_tool', 'side_index',
|
||||
'relatedArticles', 'relatedTopics', 'adxSponLink']),
|
||||
dict(name=['script', 'noscript', 'style'])]
|
||||
encoding = 'cp1252'
|
||||
no_stylesheets = True
|
||||
|
@ -21,7 +21,6 @@ class OurDailyBread(BasicNewsRecipe):
|
||||
use_embedded_content = False
|
||||
category = 'religion'
|
||||
encoding = 'utf-8'
|
||||
extra_css = ' #devoTitle{font-size: x-large; font-weight: bold} '
|
||||
|
||||
conversion_options = {
|
||||
'comments' : description
|
||||
@ -32,13 +31,13 @@ class OurDailyBread(BasicNewsRecipe):
|
||||
keep_only_tags = [dict(name='div', attrs={'class':['altbg','text']})]
|
||||
|
||||
remove_tags = [dict(name='div', attrs={'id':['ctl00_cphPrimary_pnlBookCover']}),
|
||||
dict(name='div', attrs={'class':['devotionalLinks']})
|
||||
]
|
||||
extra_css = '''
|
||||
.text{font-family:Arial,Helvetica,sans-serif;font-size:x-small;}
|
||||
.devotionalTitle{font-family:Arial,Helvetica,sans-serif; font-size:large; font-weight: bold;}
|
||||
.devotionalDate{font-family:Arial,Helvetica,sans-serif; font-size:xx-small;}
|
||||
.devotionalVerse{font-family:Arial,Helvetica,sans-serif; font-size:xx-small; }
|
||||
a{color:#000000;font-family:Arial,Helvetica,sans-serif; font-size:x-small;}
|
||||
'''
|
||||
|
||||
feeds = [(u'Our Daily Bread', u'http://www.rbc.org/rss.ashx?id=50398')]
|
||||
|
99
resources/recipes/sportsillustrated.recipe
Normal file
99
resources/recipes/sportsillustrated.recipe
Normal file
@ -0,0 +1,99 @@
|
||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
||||
from calibre.ebooks.BeautifulSoup import BeautifulSoup
|
||||
#from random import randint
|
||||
from urllib import quote
|
||||
|
||||
class SportsIllustratedRecipe(BasicNewsRecipe) :
|
||||
__author__ = 'kwetal'
|
||||
__copyright__ = 'kwetal'
|
||||
__license__ = 'GPL v3'
|
||||
language = 'en'
|
||||
description = 'Sports Illustrated'
|
||||
version = 1
|
||||
title = u'Sports Illustrated'
|
||||
|
||||
no_stylesheets = True
|
||||
remove_javascript = True
|
||||
#template_css = ''
|
||||
use_embedded_content = False
|
||||
|
||||
INDEX = 'http://sportsillustrated.cnn.com/'
|
||||
|
||||
def parse_index(self):
|
||||
answer = []
|
||||
soup = self.index_to_soup(self.INDEX)
|
||||
# Find the link to the current issue on the front page.
|
||||
cover = soup.find('img', attrs = {'alt' : 'Read All Articles', 'style' : 'vertical-align:bottom;'})
|
||||
if cover:
|
||||
currentIssue = cover.parent['href']
|
||||
if currentIssue:
|
||||
# Open the index of current issue
|
||||
index = self.index_to_soup(currentIssue)
|
||||
|
||||
# Find all articles.
|
||||
list = index.find('div', attrs = {'class' : 'siv_artList'})
|
||||
if list:
|
||||
articles = []
|
||||
# Get all the artcles ready for calibre.
|
||||
for headline in list.findAll('div', attrs = {'class' : 'headline'}):
|
||||
title = self.tag_to_string(headline.a) + '\n' + self.tag_to_string(headline.findNextSibling('div', attrs = {'class' : 'info'}))
|
||||
url = self.INDEX + headline.a['href']
|
||||
description = self.tag_to_string(headline.findNextSibling('a').div)
|
||||
article = {'title' : title, 'date' : u'', 'url' : url, 'description' : description}
|
||||
|
||||
articles.append(article)
|
||||
|
||||
# See if we can find a meaningfull title
|
||||
feedTitle = 'Current Issue'
|
||||
hasTitle = index.find('div', attrs = {'class' : 'siv_imageText_head'})
|
||||
if hasTitle :
|
||||
feedTitle = self.tag_to_string(hasTitle.h1)
|
||||
|
||||
answer.append([feedTitle, articles])
|
||||
|
||||
return answer
|
||||
|
||||
|
||||
def print_version(self, url) :
|
||||
# This is the url and the parameters that work to get the print version.
|
||||
printUrl = 'http://si.printthis.clickability.com/pt/printThis?clickMap=printThis'
|
||||
printUrl += '&fb=Y&partnerID=2356&url=' + quote(url)
|
||||
|
||||
return printUrl
|
||||
|
||||
# However the original javascript also uses the following parameters, but they can be left out:
|
||||
# title : can be some random string
|
||||
# random : some random number, but I think the number of digits is important
|
||||
# expire : no idea what value to use
|
||||
# All this comes from the Javascript function that redirects to the print version. It's called PT() and is defined in the file 48.js
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
header = soup.find('div', attrs = {'class' : 'siv_artheader'})
|
||||
if header:
|
||||
# It's an article, prepare a container for the content
|
||||
homeMadeSoup = BeautifulSoup('<html><head></head><body></body></html>')
|
||||
body = homeMadeSoup.find('body')
|
||||
|
||||
# Find the date, title and byline
|
||||
temp = header.find('td', attrs = {'class' : 'title'})
|
||||
if temp :
|
||||
date = temp.find('div', attrs = {'class' : 'date'})
|
||||
if date:
|
||||
body.append(date)
|
||||
if temp.h1:
|
||||
body.append(temp.h1)
|
||||
if temp.h2 :
|
||||
body.append(temp.h2)
|
||||
byline = temp.find('div', attrs = {'class' : 'byline'})
|
||||
if byline:
|
||||
body.append(byline)
|
||||
|
||||
# Find the content
|
||||
for para in soup.findAll('div', attrs = {'class' : 'siv_artpara'}) :
|
||||
body.append(para)
|
||||
|
||||
return homeMadeSoup
|
||||
else :
|
||||
# It's a TOC, just return the whole lot
|
||||
return soup
|
||||
|
60
resources/recipes/sportsillustrated_columnists.recipe
Normal file
60
resources/recipes/sportsillustrated_columnists.recipe
Normal file
@ -0,0 +1,60 @@
|
||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
||||
from calibre.ebooks.BeautifulSoup import BeautifulSoup
|
||||
#from random import randint
|
||||
from urllib import quote
|
||||
|
||||
class SportsIllustratedColumnistsRecipe(BasicNewsRecipe) :
|
||||
title = u'Sports Illustrated Columnists'
|
||||
__author__ = u'kwetal'
|
||||
__license__ = u'GPL v3'
|
||||
language = 'en'
|
||||
version = 2
|
||||
|
||||
oldest_article = 7
|
||||
max_articles_per_feed = 100
|
||||
no_stylesheets = True
|
||||
remove_javascript = True
|
||||
|
||||
feeds = []
|
||||
# RSS sources found at http://sportsillustrated.cnn.com/services/rss/
|
||||
feeds.append((u'Jon Heyman', u'http://rss.cnn.com/rss/si_jon_heyman.rss'))
|
||||
feeds.append((u'Austin Murphy', u'http://rss.cnn.com/rss/si_austin_murphy.rss'))
|
||||
feeds.append((u'Lars Anderson', u'http://rss.cnn.com/rss/si_lars_anderson.rss'))
|
||||
feeds.append((u'Melissa Segura', u'http://rss.cnn.com/rss/si_melissa_segura.rss'))
|
||||
feeds.append((u'Peter King', u'http://rss.cnn.com/rss/si_peter_king.rss'))
|
||||
feeds.append((u'Scott Wraight', u'http://rss.cnn.com/rss/si_scott_wraight.rss'))
|
||||
|
||||
def print_version(self, url) :
|
||||
# This is the url and the parameters that work to get the print version.
|
||||
printUrl = 'http://si.printthis.clickability.com/pt/printThis?clickMap=printThis'
|
||||
printUrl += '&fb=Y&partnerID=2356&url=' + quote(url)
|
||||
|
||||
return printUrl
|
||||
|
||||
# However the original javascript also uses the following parameters, but they can be left out:
|
||||
# title : can be some random string
|
||||
# random : some random number, but I think the number of digits is important
|
||||
# expire : no idea what value to use
|
||||
# All this comes from the Javascript function that redirects to the print version. It's called PT() and is defined in the file 48.js
|
||||
|
||||
def preprocess_html(self, soup) :
|
||||
temp = soup.find('div', attrs = {'class' : 'cnnstoryheadline'})
|
||||
if temp :
|
||||
# It's an article, make a valid content container
|
||||
homeMadeSoup = BeautifulSoup('<html><head></head><body></body></html>')
|
||||
body = homeMadeSoup.find('body')
|
||||
|
||||
headline = temp.find('h1')
|
||||
if headline :
|
||||
body.append(headline)
|
||||
|
||||
for td in soup.findAll('td', attrs = {'class' : 'cnnstorycontentarea'}) :
|
||||
for p in td.findAll('p') :
|
||||
body.append(p)
|
||||
|
||||
return homeMadeSoup
|
||||
else :
|
||||
# It's a TOC, just return the whole lot
|
||||
return soup
|
||||
|
||||
|
@ -27,12 +27,17 @@ class DailyTelegraph(BasicNewsRecipe):
|
||||
, '--publisher' , title
|
||||
]
|
||||
|
||||
keep_only_tags = [
|
||||
dict(name='h1', attrs={'class':'section-heading'})
|
||||
,dict(name='div', attrs={'id':'article'})
|
||||
]
|
||||
keep_only_tags = [dict(name='div', attrs={'id': 'story'})]
|
||||
|
||||
remove_tags = [dict(name=['object','link'])]
|
||||
#remove_tags = [dict(name=['object','link'])]
|
||||
remove_tags = [dict(name ='div', attrs = {'class': 'story-info'}),
|
||||
dict(name ='div', attrs = {'class': 'story-header-tools'}),
|
||||
dict(name ='div', attrs = {'class': 'story-sidebar'}),
|
||||
dict(name ='div', attrs = {'class': 'story-footer'}),
|
||||
dict(name ='div', attrs = {'id': 'comments'}),
|
||||
dict(name ='div', attrs = {'class': 'story-extras story-extras-2'}),
|
||||
dict(name ='div', attrs = {'class': 'group item-count-1 story-related'})
|
||||
]
|
||||
|
||||
extra_css = '''
|
||||
h1{font-family :Georgia,"Times New Roman",Times,serif; font-size:large; }
|
||||
@ -43,9 +48,7 @@ class DailyTelegraph(BasicNewsRecipe):
|
||||
.caption{font-family:Trebuchet MS,Trebuchet,Helvetica,sans-serif; font-size: xx-small;}
|
||||
'''
|
||||
|
||||
feeds = [
|
||||
(u'News', u'http://feeds.news.com.au/public/rss/2.0/aus_news_807.xml'),
|
||||
(u'World News', u'http://feeds.news.com.au/public/rss/2.0/aus_world_808.xml'),
|
||||
feeds = [(u'News', u'http://feeds.news.com.au/public/rss/2.0/aus_news_807.xml'),
|
||||
(u'Opinion', u'http://feeds.news.com.au/public/rss/2.0/aus_opinion_58.xml'),
|
||||
(u'Business', u'http://feeds.news.com.au/public/rss/2.0/aus_business_811.xml'),
|
||||
(u'Media', u'http://feeds.news.com.au/public/rss/2.0/aus_media_57.xml'),
|
||||
@ -60,15 +63,23 @@ class DailyTelegraph(BasicNewsRecipe):
|
||||
(u'Mining', u'http://feeds.news.com.au/public/rss/2.0/aus_business_mining_704.xml'),
|
||||
(u'Climate', u'http://feeds.news.com.au/public/rss/2.0/aus_climate_809.xml'),
|
||||
(u'Property', u'http://feeds.news.com.au/public/rss/2.0/aus_property_59.xml'),
|
||||
(u'US Election', u'http://feeds.news.com.au/public/rss/2.0/aus_uselection_687.xml')
|
||||
]
|
||||
(u'US Election', u'http://feeds.news.com.au/public/rss/2.0/aus_uselection_687.xml')]
|
||||
|
||||
def get_article_url(self, article):
|
||||
return article.id
|
||||
|
||||
#br = self.get_browser()
|
||||
#br.open(article.link).read()
|
||||
#print br.geturl()
|
||||
|
||||
#return br.geturl()
|
||||
|
||||
def get_cover_url(self):
|
||||
|
||||
href = 'http://www.theaustralian.news.com.au/'
|
||||
|
||||
soup = self.index_to_soup(href)
|
||||
img = soup.find('img',alt ="Digital editions of The Australian")
|
||||
img = soup.find('img',alt ="AUS HP promo digital2")
|
||||
print img
|
||||
if img :
|
||||
cover_url = img['src']
|
||||
|
@ -16,6 +16,7 @@ class Time(BasicNewsRecipe):
|
||||
encoding = 'utf-8'
|
||||
no_stylesheets = True
|
||||
language = 'en'
|
||||
remove_javascript = True
|
||||
|
||||
extra_css = ''' h1 {font-family:Arial,Sans-serif;}
|
||||
h2 {font-family:Arial,Sans-serif;}
|
||||
@ -32,13 +33,7 @@ class Time(BasicNewsRecipe):
|
||||
a:link{color:#CC0000;}
|
||||
'''
|
||||
|
||||
# remove_tags_before = dict(id="artHd")
|
||||
# remove_tags_after = {'class':"ltCol"}
|
||||
# remove_tags = [
|
||||
# {'class':['articleTools', 'enlarge', 'search','socialtools','blogtools','moretools','page','nextUp','next','subnav','RSS','line2','first','ybuzz','articlePagination','chiclets','imgcont','createListLink','rlinks','tabsWrap','pagination']},
|
||||
# {'id':['quigoArticle', 'contentTools', 'articleSideBar', 'header', 'navTop','articleTools','feedmodule','feedmodule3','promos','footer','linksFooter','timeArchive','belt','relatedStories','packages','Features']},
|
||||
# {'target':'_blank'},
|
||||
# ]
|
||||
|
||||
|
||||
keep_only_tags = [ dict(name ="div",attrs = {"id" :["article",]}) ,
|
||||
dict(name ="div",attrs = {"class" :["artHd","artTxt","photoBkt","vertPhoto","image","copy"]}) ,]
|
||||
@ -50,6 +45,8 @@ class Time(BasicNewsRecipe):
|
||||
recursions = 1
|
||||
match_regexps = [r'/[0-9,]+-(2|3|4|5|6|7|8|9)(,\d+){0,1}.html']
|
||||
|
||||
preprocess_regexps = [(re.compile(
|
||||
r'<meta .+/>'), lambda m:'')]
|
||||
|
||||
def parse_index(self):
|
||||
soup = self.index_to_soup('http://www.time.com/time/magazine')
|
||||
@ -75,7 +72,11 @@ class Time(BasicNewsRecipe):
|
||||
return feeds
|
||||
|
||||
def find_articles(self, seched):
|
||||
for a in seched.findNextSiblings('a', href=True, attrs={'class':'toc_hed'}):
|
||||
articles = []
|
||||
for a in seched.findNextSiblings( attrs={'class':['toc_hed','rule2']}):
|
||||
if a.name in "div":
|
||||
break
|
||||
else:
|
||||
yield {
|
||||
'title' : self.tag_to_string(a),
|
||||
'url' : 'http://www.time.com'+a['href'],
|
||||
@ -83,6 +84,8 @@ class Time(BasicNewsRecipe):
|
||||
'description' : self.article_description(a)
|
||||
}
|
||||
|
||||
|
||||
|
||||
def article_description(self, a):
|
||||
ans = []
|
||||
while True:
|
||||
|
@ -75,7 +75,13 @@ class Check(Command):
|
||||
raise SystemExit(1)
|
||||
cache[f] = mtime
|
||||
cPickle.dump(cache, open(self.CACHE, 'wb'), -1)
|
||||
|
||||
wn_path = os.path.expanduser('~/work/servers/src/calibre_servers/main')
|
||||
if os.path.exists(wn_path):
|
||||
sys.path.insert(0, wn_path)
|
||||
self.info('\tChecking Changelog...')
|
||||
import whats_new
|
||||
whats_new.test()
|
||||
sys.path.remove(wn_path)
|
||||
|
||||
def report_errors(self, errors):
|
||||
for err in errors:
|
||||
|
@ -14,7 +14,7 @@ __all__ = [
|
||||
'resources',
|
||||
'check',
|
||||
'sdist',
|
||||
'manual', 'tag_release', 'upload_rss',
|
||||
'manual', 'tag_release',
|
||||
'pypi_register', 'pypi_upload', 'upload_to_server',
|
||||
'upload_user_manual', 'upload_to_mobileread', 'upload_demo',
|
||||
'upload_to_sourceforge', 'upload_to_google_code',
|
||||
@ -49,11 +49,10 @@ check = Check()
|
||||
from setup.resources import Resources
|
||||
resources = Resources()
|
||||
|
||||
from setup.publish import Manual, TagRelease, UploadRss, Stage1, Stage2, \
|
||||
from setup.publish import Manual, TagRelease, Stage1, Stage2, \
|
||||
Stage3, Stage4, Publish
|
||||
manual = Manual()
|
||||
tag_release = TagRelease()
|
||||
upload_rss = UploadRss()
|
||||
stage1 = Stage1()
|
||||
stage2 = Stage2()
|
||||
stage3 = Stage3()
|
||||
|
@ -336,7 +336,7 @@ class Py2App(object):
|
||||
NSAppleScriptEnabled=False,
|
||||
NSHumanReadableCopyright='Copyright 2008, Kovid Goyal',
|
||||
CFBundleGetInfoString=('calibre, an E-book management '
|
||||
'application. Visit http://calibre.kovidgoyal.net for details.'),
|
||||
'application. Visit http://calibre-ebook.com for details.'),
|
||||
CFBundleIconFile='library.icns',
|
||||
LSMultipleInstancesProhibited=True,
|
||||
LSEnvironment=env
|
||||
|
@ -404,7 +404,7 @@ def main():
|
||||
'packages' : ['PIL', 'Authorization', 'lxml', 'dns'],
|
||||
'excludes' : ['IPython', 'PyQt4.uic.port_v3.proxy_base'],
|
||||
'plist' : { 'CFBundleGetInfoString' : '''calibre, an E-book management application.'''
|
||||
''' Visit http://calibre.kovidgoyal.net for details.''',
|
||||
''' Visit http://calibre-ebook.com for details.''',
|
||||
'CFBundleIdentifier':'net.kovidgoyal.calibre',
|
||||
'CFBundleShortVersionString':VERSION,
|
||||
'CFBundleVersion':APPNAME + ' ' + VERSION,
|
||||
|
@ -61,10 +61,10 @@
|
||||
WorkingDirectory="APPLICATIONROOTDIRECTORY" />
|
||||
<util:InternetShortcut Id="OnlineDocumentationShortcut"
|
||||
Name="User Manual" Type="url"
|
||||
Target="http://calibre.kovidgoyal.net/user_manual"/>
|
||||
Target="http://calibre-ebook.com/user_manual"/>
|
||||
<util:InternetShortcut Id="GetInvolvedS"
|
||||
Name="Get Involved" Type="url"
|
||||
Target="http://calibre.kovidgoyal.net/wiki/Development"/>
|
||||
Target="http://calibre-ebook.com/get-involved"/>
|
||||
|
||||
<RemoveFolder Id="ApplicationProgramsFolder" On="uninstall"/>
|
||||
<RegistryValue Root="HKCU" Key="Software\Microsoft\{app}" Name="start_menu_shortcuts_installed" Type="integer" Value="1" KeyPath="yes"/>
|
||||
|
@ -6,8 +6,7 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import sys, os, shutil, subprocess, re, time, glob
|
||||
from datetime import datetime
|
||||
import os, shutil, subprocess, glob
|
||||
|
||||
from setup import Command, __appname__, __version__
|
||||
|
||||
@ -43,7 +42,7 @@ class Stage2(Command):
|
||||
class Stage3(Command):
|
||||
|
||||
description = 'Stage 3 of the publish process'
|
||||
sub_commands = ['upload_rss', 'upload_user_manual', 'upload_demo', 'sdist',
|
||||
sub_commands = ['upload_user_manual', 'upload_demo', 'sdist',
|
||||
'upload_to_google_code', 'tag_release', 'upload_to_server',
|
||||
'upload_to_sourceforge', 'upload_to_mobileread',
|
||||
]
|
||||
@ -99,76 +98,4 @@ class TagRelease(Command):
|
||||
subprocess.check_call(('bzr tag '+__version__).split())
|
||||
subprocess.check_call('bzr commit --unchanged -m'.split() + ['IGN:Tag release'])
|
||||
|
||||
try:
|
||||
class UploadRss(Command):
|
||||
|
||||
description = 'Generate and upload a RSS feed of calibre releases'
|
||||
|
||||
from bzrlib import log as blog
|
||||
|
||||
class ChangelogFormatter(blog.LogFormatter):
|
||||
supports_tags = True
|
||||
supports_merge_revisions = False
|
||||
_show_advice = False
|
||||
|
||||
def __init__(self, num_of_versions=20):
|
||||
sys.path.insert(0, os.path.join(Command.SRC, 'calibre', 'utils'))
|
||||
from rss_gen import RSS2
|
||||
self.num_of_versions = num_of_versions
|
||||
self.rss = RSS2(
|
||||
title = 'calibre releases',
|
||||
link = 'http://calibre.kovidgoyal.net/wiki/Changelog',
|
||||
description = 'Latest release of calibre',
|
||||
lastBuildDate = datetime.utcnow()
|
||||
)
|
||||
self.current_entry = None
|
||||
|
||||
def log_revision(self, r):
|
||||
from rss_gen import RSSItem, Guid
|
||||
if len(self.rss.items) > self.num_of_versions-1:
|
||||
return
|
||||
msg = r.rev.message
|
||||
match = re.match(r'version\s+(\d+\.\d+.\d+)', msg)
|
||||
|
||||
if match:
|
||||
if self.current_entry is not None:
|
||||
mkup = '<div><ul>%s</ul></div>'
|
||||
self.current_entry.description = mkup%(''.join(
|
||||
self.current_entry.description))
|
||||
if match.group(1) == '0.5.14':
|
||||
self.current_entry.description = \
|
||||
'''<div>See <a href="http://calibre.kovidgoyal.net/new_in_6">New in
|
||||
6</a></div>'''
|
||||
self.rss.items.append(self.current_entry)
|
||||
timestamp = r.rev.timezone + r.rev.timestamp
|
||||
self.current_entry = RSSItem(
|
||||
title = 'calibre %s released'%match.group(1),
|
||||
link = 'http://calibre.kovidgoyal.net/download',
|
||||
guid = Guid(match.group(), False),
|
||||
pubDate = datetime(*time.gmtime(timestamp)[:6]),
|
||||
description = []
|
||||
)
|
||||
elif self.current_entry is not None:
|
||||
if re.search(r'[a-zA-Z]', msg) and len(msg.strip()) > 5:
|
||||
if 'translation' not in msg and not msg.startswith('IGN'):
|
||||
msg = msg.replace('<', '<').replace('>', '>')
|
||||
msg = re.sub('#(\d+)', r'<a href="http://calibre.kovidgoyal.net/ticket/\1">#\1</a>',
|
||||
msg)
|
||||
|
||||
self.current_entry.description.append(
|
||||
'<li>%s</li>'%msg.strip())
|
||||
|
||||
|
||||
def run(self, opts):
|
||||
from bzrlib import log, branch
|
||||
bzr_path = os.path.expanduser('~/work/calibre')
|
||||
b = branch.Branch.open(bzr_path)
|
||||
lf = UploadRss.ChangelogFormatter()
|
||||
self.info('\tGenerating bzr log...')
|
||||
log.show_log(b, lf)
|
||||
lf.rss.write_xml(open('/tmp/releases.xml', 'wb'))
|
||||
self.info('\tUploading RSS to server...')
|
||||
subprocess.check_call('scp /tmp/releases.xml divok:/var/www/calibre.kovidgoyal.net/htdocs/downloads'.split())
|
||||
except ImportError:
|
||||
class UploadRss(Command):
|
||||
description = 'You need bzr installed to use this command'
|
||||
|
@ -18,7 +18,7 @@ class Metadata(object):
|
||||
version = __version__
|
||||
author = 'Kovid Goyal'
|
||||
author_email = 'kovid@kovidgoyal.net'
|
||||
url = 'http://calibre.kovidgoyal.net'
|
||||
url = 'http://calibre-ebook.com'
|
||||
description = 'E-book management application.'
|
||||
long_description = open('README', 'rb').read()
|
||||
license = 'GPL'
|
||||
|
@ -12,10 +12,9 @@ from tempfile import NamedTemporaryFile
|
||||
|
||||
from setup import Command, __version__, installer_name, __appname__
|
||||
|
||||
PREFIX = "/var/www/calibre.kovidgoyal.net"
|
||||
PREFIX = "/var/www/calibre-ebook.com"
|
||||
DOWNLOADS = PREFIX+"/htdocs/downloads"
|
||||
BETAS = DOWNLOADS +'/betas'
|
||||
DOCS = PREFIX+"/htdocs/apidocs"
|
||||
USER_MANUAL = PREFIX+'/htdocs/user_manual'
|
||||
HTML2LRF = "calibre/ebooks/lrf/html/demo"
|
||||
TXT2LRF = "src/calibre/ebooks/lrf/txt/demo"
|
||||
@ -116,6 +115,9 @@ class UploadToGoogleCode(Command):
|
||||
def delete_old_files(self):
|
||||
self.info('Deleting old files from Google Code...')
|
||||
for fname in self.old_files:
|
||||
ext = fname.rpartition('.')[-1]
|
||||
if ext in ('flv', 'mp4', 'ogg', 'avi'):
|
||||
continue
|
||||
self.info('\tDeleting', fname)
|
||||
self.br.open('http://code.google.com/p/calibre-ebook/downloads/delete?name=%s'%fname)
|
||||
self.br.select_form(predicate=lambda x: 'delete.do' in x.action)
|
||||
@ -328,8 +330,6 @@ class UploadToServer(Command):
|
||||
shell=True)
|
||||
check_call('scp dist/calibre-*.tar.gz.asc divok:%s/signatures/'%DOWNLOADS,
|
||||
shell=True)
|
||||
check_call('ssh divok bzr update /var/www/calibre.kovidgoyal.net/calibre/',
|
||||
shell=True)
|
||||
check_call('ssh divok bzr update /usr/local/calibre',
|
||||
shell=True)
|
||||
check_call('''ssh divok echo %s \\> %s/latest_version'''\
|
||||
|
@ -433,9 +433,9 @@ plugins += [
|
||||
KINDLE,
|
||||
KINDLE2,
|
||||
KINDLE_DX,
|
||||
PRS500,
|
||||
PRS505,
|
||||
PRS700,
|
||||
PRS500,
|
||||
ANDROID,
|
||||
CYBOOK_OPUS,
|
||||
COOL_ER,
|
||||
|
@ -20,7 +20,7 @@ class ANDROID(USBMS):
|
||||
VENDOR_ID = [
|
||||
0x0bb4,
|
||||
]
|
||||
PRODUCT_ID = [0x0c02]
|
||||
PRODUCT_ID = [0x0c02, 0x0c01]
|
||||
BCD = [0x100]
|
||||
EBOOK_DIR_MAIN = 'wordplayer/calibretransfer'
|
||||
|
||||
|
@ -92,6 +92,7 @@ class POCKETBOOK360(EB600):
|
||||
|
||||
VENDOR_NAME = 'PHILIPS'
|
||||
WINDOWS_MAIN_MEM = 'MASS_STORGE'
|
||||
WINDOWS_CARD_A_MEM = 'MASS_STORAGE'
|
||||
|
||||
OSX_MAIN_MEM = 'Philips Mass Storge Media'
|
||||
OSX_CARD_A_MEM = 'Philips Mass Storge Media'
|
||||
|
@ -64,21 +64,17 @@ class KINDLE2(KINDLE):
|
||||
|
||||
name = 'Kindle 2 Device Interface'
|
||||
description = _('Communicate with the Kindle 2 eBook reader.')
|
||||
author = _('John Schember')
|
||||
supported_platforms = ['windows', 'osx', 'linux']
|
||||
|
||||
FORMATS = KINDLE.FORMATS + ['pdf']
|
||||
PRODUCT_ID = [0x0002]
|
||||
BCD = [0x0100]
|
||||
|
||||
|
||||
class KINDLE_DX(KINDLE):
|
||||
class KINDLE_DX(KINDLE2):
|
||||
|
||||
name = 'Kindle DX Device Interface'
|
||||
description = _('Communicate with the Kindle 2 eBook reader.')
|
||||
author = _('John Schember')
|
||||
supported_platforms = ['windows', 'osx', 'linux']
|
||||
description = _('Communicate with the Kindle DX eBook reader.')
|
||||
|
||||
FORMATS = ['azw', 'mobi', 'prc', 'azw1', 'tpz', 'pdf', 'txt']
|
||||
|
||||
PRODUCT_ID = [0x0003]
|
||||
BCD = [0x0100]
|
||||
|
@ -23,24 +23,24 @@ class PRS505(CLI, Device):
|
||||
|
||||
name = 'PRS-300/505 Device Interface'
|
||||
gui_name = 'SONY Pocket Edition'
|
||||
description = _('Communicate with the Sony PRS-300/505 eBook reader.')
|
||||
description = _('Communicate with the Sony PRS-300/505/500 eBook reader.')
|
||||
author = _('Kovid Goyal and John Schember')
|
||||
supported_platforms = ['windows', 'osx', 'linux']
|
||||
|
||||
FORMATS = ['epub', 'lrf', 'lrx', 'rtf', 'pdf', 'txt']
|
||||
|
||||
VENDOR_ID = [0x054c] #: SONY Vendor Id
|
||||
PRODUCT_ID = [0x031e] #: Product Id for the PRS 300 and 505
|
||||
BCD = [0x229, 0x1000]
|
||||
PRODUCT_ID = [0x031e] #: Product Id for the PRS 300/505/new 500
|
||||
BCD = [0x229, 0x1000, 0x22a]
|
||||
|
||||
VENDOR_NAME = 'SONY'
|
||||
WINDOWS_MAIN_MEM = re.compile('PRS-(505|300)')
|
||||
WINDOWS_CARD_A_MEM = re.compile(r'PRS-505/\S+:MS')
|
||||
WINDOWS_CARD_B_MEM = re.compile(r'PRS-505/\S+:SD')
|
||||
WINDOWS_MAIN_MEM = re.compile('PRS-(505|300|500)')
|
||||
WINDOWS_CARD_A_MEM = re.compile(r'PRS-(505|500)/\S+:MS')
|
||||
WINDOWS_CARD_B_MEM = re.compile(r'PRS-(505|500)/\S+:SD')
|
||||
|
||||
OSX_MAIN_MEM = re.compile(r'Sony PRS-(((505|300)/[^:]+)|(300)) Media')
|
||||
OSX_CARD_A_MEM = re.compile(r'Sony PRS-505/[^:]+:MS Media')
|
||||
OSX_CARD_B_MEM = re.compile(r'Sony PRS-505/[^:]+:SD Media')
|
||||
OSX_MAIN_MEM = re.compile(r'Sony PRS-(((505|300|500)/[^:]+)|(300)) Media')
|
||||
OSX_CARD_A_MEM = re.compile(r'Sony PRS-(505|500)/[^:]+:MS Media')
|
||||
OSX_CARD_B_MEM = re.compile(r'Sony PRS-(505|500)/[^:]+:SD Media')
|
||||
|
||||
MAIN_MEMORY_VOLUME_LABEL = 'Sony Reader Main Memory'
|
||||
STORAGE_CARD_VOLUME_LABEL = 'Sony Reader Storage Card'
|
||||
@ -198,3 +198,5 @@ class PRS505(CLI, Device):
|
||||
write_card_prefix(self._card_b_prefix, 2)
|
||||
|
||||
self.report_progress(1.0, _('Sending metadata to device...'))
|
||||
|
||||
|
||||
|
@ -40,7 +40,7 @@ To get help on them specify the input and output file and then use the -h \
|
||||
option.
|
||||
|
||||
For full documentation of the conversion system see
|
||||
''') + 'http://calibre.kovidgoyal.net/user_manual/conversion.html'
|
||||
''') + 'http://calibre-ebook.com/user_manual/conversion.html'
|
||||
|
||||
def print_help(parser, log):
|
||||
help = parser.format_help().encode(preferred_encoding, 'replace')
|
||||
|
@ -11,7 +11,7 @@
|
||||
</head>
|
||||
<h1>Demo of <span style='font-family:monospace'>html2lrf</span></h1>
|
||||
<p>
|
||||
This document contains a demonstration of the capabilities of <span style='font-family:monospace'>html2lrf</span>, the HTML to LRF converter from <em>calibre.</em> To obtain calibre visit<br/><span style='font:sans-serif'>http://calibre.kovidgoyal.net</span>
|
||||
This document contains a demonstration of the capabilities of <span style='font-family:monospace'>html2lrf</span>, the HTML to LRF converter from <em>calibre.</em> To obtain calibre visit<br/><span style='font:sans-serif'>http://calibre-ebook.com</span>
|
||||
</p>
|
||||
<br/>
|
||||
<h2 id="toc">Table of Contents</h2>
|
||||
|
@ -74,10 +74,18 @@ class ODTInput(InputFormatPlugin):
|
||||
# about them
|
||||
from calibre.ebooks.oeb.base import XPath, XHTML
|
||||
path = XPath('//h:p/h:div')
|
||||
path2 = XPath('//h:div[@style]/h:img[@style]')
|
||||
for item in oeb.spine:
|
||||
root = item.data
|
||||
if not hasattr(root, 'xpath'): continue
|
||||
for div in path(root):
|
||||
div.getparent().tag = XHTML('div')
|
||||
|
||||
# This construct doesn't render well in HTML
|
||||
for img in path2(root):
|
||||
div = img.getparent()
|
||||
if 'position:relative' in div.attrib['style'] and len(div) == 1 \
|
||||
and 'img' in div[0].tag:
|
||||
del div.attrib['style']
|
||||
|
||||
|
||||
|
@ -849,7 +849,8 @@ class Manifest(object):
|
||||
try:
|
||||
data = etree.fromstring(data)
|
||||
except:
|
||||
data=data.replace(':=', '=').replace(':>', '>')
|
||||
data = data.replace(':=', '=').replace(':>', '>')
|
||||
data = data.replace('<http:/>', '')
|
||||
try:
|
||||
data = etree.fromstring(data)
|
||||
except etree.XMLSyntaxError:
|
||||
|
@ -230,13 +230,13 @@ class PML_HTMLizer(object):
|
||||
elif code in self.BLOCK_STATES:
|
||||
text = self.process_code_block(code, stream, pre)
|
||||
else:
|
||||
text = self.process_code_simple(code)
|
||||
text = self.process_code_simple(code, stream)
|
||||
|
||||
self.state[code][0] = not self.state[code][0]
|
||||
|
||||
return text
|
||||
|
||||
def process_code_simple(self, code):
|
||||
def process_code_simple(self, code, stream):
|
||||
text = u''
|
||||
|
||||
if self.state[code][0]:
|
||||
|
@ -33,7 +33,7 @@
|
||||
<property name="text">
|
||||
<string><p>This wizard will help you choose an appropriate font size key for your needs. Just enter the base font size of the input document and then enter an input font size. The wizard will display what font size it will be mapped to, by the font rescaling algorithm. You can adjust the algorithm by adjusting the output base font size and font key below. When you find values suitable for you, click OK.</p>
|
||||
<p>By default, if the output base font size is zero and/or no font size key is specified, calibre will use the values from the current Output Profile. </p>
|
||||
<p>See the <a href="http://calibre.kovidgoyal.net/user_manual/conversion.html#font-size-rescaling">User Manual</a> for a discussion of how font size rescaling works.</p></string>
|
||||
<p>See the <a href="http://calibre-ebook.com/user_manual/conversion.html#font-size-rescaling">User Manual</a> for a discussion of how font size rescaling works.</p></string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
|
@ -127,7 +127,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string><p>For example, to match all h2 tags that have class="chapter", set tag to <i>h2</i>, attribute to <i>class</i> and value to <i>chapter</i>.</p><p>Leaving attribute blank will match any attribute and leaving value blank will match any value. Setting tag to * will match any tag.</p><p>To learn more advanced usage of XPath see the <a href="http://calibre.kovidgoyal.net/user_manual/xpath.html">XPath Tutorial</a>.</string>
|
||||
<string><p>For example, to match all h2 tags that have class="chapter", set tag to <i>h2</i>, attribute to <i>class</i> and value to <i>chapter</i>.</p><p>Leaving attribute blank will match any attribute and leaving value blank will match any value. Setting tag to * will match any tag.</p><p>To learn more advanced usage of XPath see the <a href="http://calibre-ebook.com/user_manual/xpath.html">XPath Tutorial</a>.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
|
@ -112,7 +112,7 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>See the <a href="http://calibre.kovidgoyal.net/user_manual/gui.html#the-search-interface">User Manual</a> for more help</string>
|
||||
<string>See the <a href="http://calibre-ebook.com/user_manual/gui.html#the-search-interface">User Manual</a> for more help</string>
|
||||
</property>
|
||||
<property name="openExternalLinks" >
|
||||
<bool>true</bool>
|
||||
|
@ -214,7 +214,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
||||
|
||||
####################### Vanity ########################
|
||||
self.vanity_template = _('<p>For help see the: <a href="%s">User Manual</a>'
|
||||
'<br>')%'http://calibre.kovidgoyal.net/user_manual'
|
||||
'<br>')%'http://calibre-ebook.com/user_manual'
|
||||
self.vanity_template += _('<b>%s</b>: %s by <b>Kovid Goyal '
|
||||
'%%(version)s</b><br>%%(device)s</p>')%(__appname__, __version__)
|
||||
self.latest_version = ' '
|
||||
@ -1721,12 +1721,13 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
||||
<title>Donate to support calibre</title>
|
||||
</head>
|
||||
<body style="background:white">
|
||||
<div><a href="http://calibre.kovidgoyal.net"><img style="border:0px" src="http://calibre.kovidgoyal.net/chrome/site/calibre_banner.png" alt="calibre" /></a></div>
|
||||
<div><a href="http://calibre-ebook.com"><img style="border:0px"
|
||||
src="file://%s" alt="calibre" /></a></div>
|
||||
<p>Calibre %s</p>
|
||||
%s
|
||||
</body>
|
||||
</html>
|
||||
'''%(MSG, BUTTON)
|
||||
'''%(P('content_server/calibre_banner.png').replace(os.sep, '/'), MSG, BUTTON)
|
||||
pt = PersistentTemporaryFile('_donate.htm')
|
||||
pt.write(HTML.encode('utf-8'))
|
||||
pt.close()
|
||||
@ -1812,7 +1813,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
||||
|
||||
def update_found(self, version):
|
||||
os = 'windows' if iswindows else 'osx' if isosx else 'linux'
|
||||
url = 'http://%s.kovidgoyal.net/download_%s'%(__appname__, os)
|
||||
url = 'http://calibre-ebook.com/download_%s'%os
|
||||
self.latest_version = '<br>' + _('<span style="color:red; font-weight:bold">'
|
||||
'Latest version: <a href="%s">%s</a></span>')%(url, version)
|
||||
self.vanity.setText(self.vanity_template%\
|
||||
@ -1823,10 +1824,10 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
||||
dynamic.get('update to version %s'%version, True):
|
||||
if question_dialog(self, _('Update available'),
|
||||
_('%s has been updated to version %s. '
|
||||
'See the <a href="http://calibre.kovidgoyal.net/wiki/'
|
||||
'Changelog">new features</a>. Visit the download pa'
|
||||
'See the <a href="http://calibre-ebook.com/whats-new'
|
||||
'">new features</a>. Visit the download pa'
|
||||
'ge?')%(__appname__, version)):
|
||||
url = 'http://calibre.kovidgoyal.net/download_'+\
|
||||
url = 'http://calibre-ebook.com/download_'+\
|
||||
('windows' if iswindows else 'osx' if isosx else 'linux')
|
||||
QDesktopServices.openUrl(QUrl(url))
|
||||
dynamic.set('update to version %s'%version, False)
|
||||
|
@ -46,7 +46,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string><h2>Demo videos</h2>Videos demonstrating the various features of calibre are available <a href="http://calibre.kovidgoyal.net/downloads/videos/">online</a>.</string>
|
||||
<string><h2>Demo videos</h2>Videos demonstrating the various features of calibre are available <a href="http://calibre-ebook.com/demo">online</a>.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
@ -75,7 +75,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string><h2>User Manual</h2>A User Manual is also available <a href="http://calibre.kovidgoyal.net/user_manual">online</a>.</string>
|
||||
<string><h2>User Manual</h2>A User Manual is also available <a href="http://calibre-ebook.com/user_manual">online</a>.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
|
@ -64,7 +64,7 @@ STANZA_TEMPLATE='''\
|
||||
<title>calibre Library</title>
|
||||
<author>
|
||||
<name>calibre</name>
|
||||
<uri>http://calibre.kovidgoyal.net</uri>
|
||||
<uri>http://calibre-ebook.com</uri>
|
||||
</author>
|
||||
<id>$id</id>
|
||||
<updated>${updated.strftime('%Y-%m-%dT%H:%M:%SZ')}</updated>
|
||||
|
@ -176,7 +176,7 @@ class LibraryServer(object):
|
||||
}
|
||||
|
||||
</style>
|
||||
<link rel="icon" href="http://calibre.kovidgoyal.net/chrome/site/favicon.ico" type="image/x-icon" />
|
||||
<link rel="icon" href="http://calibre-ebook.com/favicon.ico" type="image/x-icon" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="logo">
|
||||
@ -276,7 +276,7 @@ class LibraryServer(object):
|
||||
${Markup(next_link)}
|
||||
<author>
|
||||
<name>calibre</name>
|
||||
<uri>http://calibre.kovidgoyal.net</uri>
|
||||
<uri>http://calibre-ebook.com</uri>
|
||||
</author>
|
||||
<subtitle>
|
||||
${subtitle}
|
||||
@ -296,7 +296,7 @@ class LibraryServer(object):
|
||||
<link rel="search" title="Search" type="application/atom+xml" href="/stanza/?search={searchTerms}"/>
|
||||
<author>
|
||||
<name>calibre</name>
|
||||
<uri>http://calibre.kovidgoyal.net</uri>
|
||||
<uri>http://calibre-ebook.com</uri>
|
||||
</author>
|
||||
<subtitle>
|
||||
${subtitle}
|
||||
|
@ -120,7 +120,7 @@ html_copy_source = False
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'calibredoc'
|
||||
|
||||
html_use_opensearch = 'http://calibre.kovidgoyal.net/user_manual'
|
||||
html_use_opensearch = 'http://calibre-ebook.com/user_manual'
|
||||
|
||||
html_show_sphinx = False
|
||||
|
||||
|
@ -54,7 +54,7 @@ That's all. To add this code to |app| as a plugin, simply create a zip file with
|
||||
zip plugin.zip my_plugin.py
|
||||
|
||||
You can download the Hello World plugin from
|
||||
`helloworld_plugin.zip <http://calibre.kovidgoyal.net/downloads/helloworld_plugin.zip>`_.
|
||||
`helloworld_plugin.zip <http://calibre-ebook.com/downloads/helloworld_plugin.zip>`_.
|
||||
Now either use the configuration dialog in |app| GUI to add this zip file as a plugin, or
|
||||
use the command::
|
||||
|
||||
|
@ -65,7 +65,7 @@ this, make your changes, then run::
|
||||
bzr send -o my-changes
|
||||
|
||||
This will create a :file:`my-changes` file in the current directory,
|
||||
simply attach that to a ticket on the |app| `bug tracker <http://calibre.kovidgoyal.net/newticket>`_.
|
||||
simply attach that to a ticket on the |app| `bug tracker <http://bugs.calibre-ebook.com/newticket>`_.
|
||||
|
||||
If you plan to do a lot of development on |app|, then the best method is to create a
|
||||
`Launchpad <http://launchpad.net>`_ account. Once you have the account, you can use it to register
|
||||
|
@ -21,6 +21,7 @@ What formats does |app| support conversion to/from?
|
||||
It can convert every input format in the following list, to every output format.
|
||||
|
||||
*Input Formats:* CBZ, CBR, CBC, EPUB, FB2, HTML, LIT, LRF, MOBI, ODT, PDF, PRC**, PDB, PML, RB, RTF, TCR, TXT
|
||||
|
||||
*Output Formats:* EPUB, FB2, OEB, LIT, LRF, MOBI, PDB, PML, RB, PDF, TCR, TXT
|
||||
|
||||
** PRC is a generic format, |app| supports PRC files with TextRead and MOBIBook headers
|
||||
@ -68,8 +69,7 @@ There are two aspects to this problem:
|
||||
How do I use some of the advanced features of the conversion tools?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
You can get help on any individual feature of the converters by mousing over it in the GUI or running ``ebook-convert dummy.html .epub -h`` at a terminal. A good place to start is to look at the following demo files that demonstrate some of the advanced features:
|
||||
* `html-demo.zip <http://calibre.kovidgoyal.net/downloads/html-demo.zip>`_
|
||||
* `txt-demo.zip <http://calibre.kovidgoyal.net/downloads/txt-demo.zip>`_
|
||||
* `html-demo.zip <http://calibre-ebook.com/downloads/html-demo.zip>`_
|
||||
|
||||
|
||||
Device Integration
|
||||
@ -231,11 +231,11 @@ I want |app| to download news from my favorite news website.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
If you are reasonably proficient with computers, you can teach |app| to download news from any website of your choosing. To learn how to do this see :ref:`news`.
|
||||
|
||||
Otherwise, you can register a request for a particular news site by adding a comment `here <http://calibre.kovidgoyal.net/ticket/405>`_.
|
||||
Otherwise, you can register a request for a particular news site by adding a comment `here <http://bugs.calibre-ebook.com/ticket/405>`_.
|
||||
|
||||
Can I use web2lrf to download an arbitrary website?
|
||||
Can I use web2disk to download an arbitrary website?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
``web2lrf --url http://mywebsite.com default``
|
||||
``web2disk http://mywebsite.com``
|
||||
|
||||
Miscellaneous
|
||||
--------------
|
||||
@ -284,5 +284,5 @@ Most purchased EPUB books have `DRM <http://wiki.mobileread.com/wiki/DRM>`_. Thi
|
||||
I want some feature added to |app|. What can I do?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
You have two choices:
|
||||
1. Create a patch by hacking on |app| and send it to me for review and inclusion. See `Development <http://calibre.kovidgoyal.net/wiki/Development>`_.
|
||||
2. `Open a ticket <http://calibre.kovidgoyal.net/newticket>`_ (you have to register and login first) and hopefully I will find the time to implement your feature.
|
||||
1. Create a patch by hacking on |app| and send it to me for review and inclusion. See `Development <http://calibre-ebook.com/get-involved>`_.
|
||||
2. `Open a ticket <http://bugs.calibre-ebook.com/newticket>`_ (you have to register and login first) and hopefully I will find the time to implement your feature.
|
||||
|
@ -270,7 +270,9 @@ Once the download is complete, you can look at the downloaded :term:`HTML` by op
|
||||
...
|
||||
|
||||
|
||||
If you're satisfied with your recipe, consider attaching it to `the wiki <http://calibre.kovidgoyal.net/wiki/UserRecipes>`_, so that others can use it as well. If you feel there is enough demand to justify its inclusion into the set of built-in recipes, add a comment to the ticket http://calibre.kovidgoyal.net/ticket/405
|
||||
If you're satisfied with your recipe, and you feel there is enough demand to justify its inclusion into the set of built-in recipes, add a comment to the ticket http://bugs.calibre-ebook.com/ticket/405
|
||||
|
||||
Alternatively, you could just post your recipe in the calibre forum at http://www.mobileread.com/forums/forumdisplay.php?f=166 to share it with other calibre users.
|
||||
|
||||
|
||||
.. seealso::
|
||||
|
@ -1,7 +1,7 @@
|
||||
{% extends "!layout.html" %}
|
||||
{% block sidebarlogo %}
|
||||
<p class="logo">
|
||||
<a href="http://calibre.kovidgoyal.net"><img class="logo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/></a>
|
||||
<a href="http://calibre-ebook.com"><img class="logo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/></a>
|
||||
</p>
|
||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
|
||||
<input type="hidden" name="cmd" value="_s-xclick" />
|
||||
|
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
@ -51,7 +51,7 @@ def create_man_page(prog, parser):
|
||||
|
||||
lines += ['.SH SEE ALSO',
|
||||
'The User Manual is available at '
|
||||
'http://calibre.kovidgoyal.net/user_manual',
|
||||
'http://calibre-ebook.com/user_manual',
|
||||
'.PP', '.B Created by '+__author__]
|
||||
|
||||
lines = [x if isinstance(x, unicode) else unicode(x, 'utf-8', 'replace') for
|
||||
|
83
src/calibre/utils/libwmf.c
Normal file
83
src/calibre/utils/libwmf.c
Normal file
@ -0,0 +1,83 @@
|
||||
#include <libwmf/api.h>
|
||||
#include <libwmf/svg.h>
|
||||
|
||||
#define False 0
|
||||
#define True 1
|
||||
typedef int bool;
|
||||
|
||||
bool create_api(wmfAPI** API) {
|
||||
wmfAPI_Options options;
|
||||
wmf_error_t error;
|
||||
unsigned long flags;
|
||||
|
||||
flags = WMF_OPT_FUNCTION;
|
||||
flags |= WMF_OPT_IGNORE_NONFATAL;
|
||||
|
||||
options.function = wmf_svg_function;
|
||||
error = wmf_api_create (API, flags, &options);
|
||||
if (error != wmf_E_None) {
|
||||
wmf_api_destroy (*API);
|
||||
return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
bool load_image(wmfAPI *API, const char *path) {
|
||||
wmf_error_t error;
|
||||
|
||||
error = wmf_file_open(API, path);
|
||||
if (error != wmf_E_None) {
|
||||
wmf_api_destroy (API);
|
||||
return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
bool scan_image(wmfAPI *API, wmfD_Rect *bbox) {
|
||||
wmf_error_t error;
|
||||
|
||||
error = wmf_scan (API, 0, bbox);
|
||||
if (error != wmf_E_None) {
|
||||
wmf_api_destroy (API);
|
||||
return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
void get_image_size(wmfD_Rect *bbox, float *width, float *height) {
|
||||
*width = bbox->BR.x - bbox->TL.x;
|
||||
*height = bbox->BR.y - bbox->TL.y;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
wmfAPI *API = NULL;
|
||||
wmfD_Rect bbox;
|
||||
wmf_svg_t *ddata;
|
||||
float width, height;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: wmf file\n");
|
||||
return 1;
|
||||
}
|
||||
if (!create_api(&API)) {
|
||||
fprintf(stderr, "Failed to create WMF API\n");
|
||||
return 1;
|
||||
}
|
||||
ddata = WMF_SVG_GetData(API);
|
||||
|
||||
if (!load_image(API, argv[1])) {
|
||||
fprintf(stderr, "Failed to load image: %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
if (!scan_image(API, &bbox)) {
|
||||
fprintf(stderr, "Failed to scan image: %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
wmf_file_close(API);
|
||||
get_image_size(&bbox, &width, &height);
|
||||
printf("Image size: %f x %f\n", width, height);
|
||||
|
||||
return 0;
|
||||
}
|
@ -100,6 +100,8 @@ _extra_lang_codes = {
|
||||
'en_AU' : _('English (AU)'),
|
||||
'en_CA' : _('English (CA)'),
|
||||
'en_IN' : _('English (IND)'),
|
||||
'nl' : _('Dutch (NL)'),
|
||||
'nl_BE' : _('Dutch (BE)'),
|
||||
'und' : _('Unknown')
|
||||
}
|
||||
|
||||
|
@ -122,6 +122,9 @@ class BasicNewsRecipe(Recipe):
|
||||
#: websites that try to make it difficult to scrape content.
|
||||
articles_are_obfuscated = False
|
||||
|
||||
#: Reverse the order of articles in each feed
|
||||
reverse_article_order = False
|
||||
|
||||
#: Specify any extra :term:`CSS` that should be addded to downloaded :term:`HTML` files
|
||||
#: It will be inserted into `<style>` tags, just before the closing
|
||||
#: `</head>` tag thereby overriding all :term:`CSS` except that which is
|
||||
@ -728,6 +731,10 @@ class BasicNewsRecipe(Recipe):
|
||||
fi.write(html)
|
||||
|
||||
self.jobs = []
|
||||
|
||||
if self.reverse_article_order:
|
||||
feeds = [list(reversed(feed)) for feed in feeds]
|
||||
|
||||
for f, feed in enumerate(feeds):
|
||||
feed_dir = os.path.join(self.output_dir, 'feed_%d'%f)
|
||||
if not os.path.isdir(feed_dir):
|
||||
|
Loading…
x
Reference in New Issue
Block a user