Merge from trunk

This commit is contained in:
Charles Haley 2011-11-27 13:10:00 +01:00
commit 32b144c1bd
24 changed files with 384 additions and 126 deletions

View File

@ -19,6 +19,63 @@
# new recipes: # new recipes:
# - title: # - title:
- version: 0.8.28
date: 2011-11-25
new features:
- title: "Get Books: Add litres.ru store"
- title: "Change the algorithm that generates title sort strings to strip leading articles from both english and the current language set for the calibre user interface. In addition, in the edit metadata dialog, calibre will use the book's language when calculating the sort string. This behavior can be adjusted via Preferences->Tweaks."
tickets: [886763]
- title: "Driver for Cybook Odyssey."
tickets: [893457]
- title: "Irex driver: Put books into the top level directory instead of into /ebooks or /Books."
tickets: [883616]
bug fixes:
- title: "Have downloaded periodicals recognized when transferred via USB to the Kindle Fire"
- title: "MOBI Output: Fix underline and strikethrough properties declared on parents not being rendered on child tags."
tickets: [894245]
- title: "Template language: Fix regression that broke ordering of items when formatting a list"
- title: "Conversion pipeline: When removing obsolete <font> tags convert them to <div> instead of <span> if they contain block level tags."
tickets: [892525]
- title: "When downloading metadata, fix the case normalization of double-barelled author names."
tickets: [893257]
- title: "Template language: Fix regression that broke using general program mode in save to disk templates"
- title: "calibredb: Fix use of ranges when specifying ids for the remove command"
- title: "Apple driver: Add ids for iPhone 4S. More robust against iTunes automation errors when adding artwork."
tickets: [892468]
- title: "Fix encoding of comments incorrectly detected when downloading metadata from ozon.ru"
- title: "Fix calibre not getting list of books on the Kindle Fire"
improved recipes:
- El Mundo
- BBC
- NIN Online
- ABC Australia
- Salon.com
- Expansion (Spanish)
- The Week
- Heise Online
new recipes:
- title: Give me something to read and Let's get Critical
author: Barty
- title: Worldcrunch
author: Krittika Goyal
- version: 0.8.27 - version: 0.8.27
date: 2011-11-18 date: 2011-11-18

View File

@ -10,49 +10,39 @@ http://www.buffalonews.com/RSS/
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
class AdvancedUserRecipe1298680852(BasicNewsRecipe): class BuffaloNews(BasicNewsRecipe):
title = u'Buffalo News' title = u'Buffalo News'
oldest_article = 2 oldest_article = 2
language = 'en' language = 'en'
__author__ = 'ChappyOnIce' __author__ = 'ChappyOnIce, Krittika Goyal'
max_articles_per_feed = 20 max_articles_per_feed = 20
encoding = 'utf-8' encoding = 'utf-8'
masthead_url = 'http://www.buffalonews.com/buffalonews/skins/buffalonews/images/masthead/the_buffalo_news_logo.png' masthead_url = 'http://www.buffalonews.com/buffalonews/skins/buffalonews/images/masthead/the_buffalo_news_logo.png'
remove_javascript = True auto_cleanup = True
extra_css = 'body {text-align: justify;}\n \ remove_empty_feeds = True
p {text-indent: 20px;}'
keep_only_tags = [ feeds = [
dict(name='div', attrs={'class':['main-content-left']}) (u'City of Buffalo', u'http://www.buffalonews.com/city/communities/buffalo/?widget=rssfeed&view=feed&contentId=77944'),
] (u'Southern Erie County', u'http://www.buffalonews.com/city/communities/southern-erie/?widget=rssfeed&view=feed&contentId=77944'),
(u'Eastern Erie County', u'http://www.buffalonews.com/city/communities/eastern-erie/?widget=rssfeed&view=feed&contentId=77944'),
remove_tags = [ (u'Southern Tier', u'http://www.buffalonews.com/city/communities/southern-tier/?widget=rssfeed&view=feed&contentId=77944'),
dict(name='div', attrs={'id':['commentCount']}), (u'Niagara County', u'http://www.buffalonews.com/city/communities/niagara-county/?widget=rssfeed&view=feed&contentId=77944'),
dict(name='div', attrs={'class':['story-list-links']}) (u'Business', u'http://www.buffalonews.com/business/?widget=rssfeed&view=feed&contentId=77944'),
] (u'MoneySmart', u'http://www.buffalonews.com/business/moneysmart/?widget=rssfeed&view=feed&contentId=77944'),
(u'Bills & NFL', u'http://www.buffalonews.com/sports/bills-nfl/?widget=rssfeed&view=feed&contentId=77944'),
remove_tags_after = dict(name='div', attrs={'class':['body storyContent']}) (u'Sabres & NHL', u'http://www.buffalonews.com/sports/sabres-nhl/?widget=rssfeed&view=feed&contentId=77944'),
(u'Bob DiCesare', u'http://www.buffalonews.com/sports/columns/bob-dicesare/?widget=rssfeed&view=feed&contentId=77944'),
feeds = [(u'City of Buffalo', u'http://www.buffalonews.com/city/communities/buffalo/?widget=rssfeed&view=feed&contentId=77944'), (u'Bucky Gleason', u'http://www.buffalonews.com/sports/columns/bucky-gleason/?widget=rssfeed&view=feed&contentId=77944'),
(u'Southern Erie County', u'http://www.buffalonews.com/city/communities/southern-erie/?widget=rssfeed&view=feed&contentId=77944'), (u'Mark Gaughan', u'http://www.buffalonews.com/sports/bills-nfl/inside-the-nfl/?widget=rssfeed&view=feed&contentId=77944'),
(u'Eastern Erie County', u'http://www.buffalonews.com/city/communities/eastern-erie/?widget=rssfeed&view=feed&contentId=77944'), (u'Mike Harrington', u'http://www.buffalonews.com/sports/columns/mike-harrington/?widget=rssfeed&view=feed&contentId=77944'),
(u'Southern Tier', u'http://www.buffalonews.com/city/communities/southern-tier/?widget=rssfeed&view=feed&contentId=77944'), (u'Jerry Sullivan', u'http://www.buffalonews.com/sports/columns/jerry-sullivan/?widget=rssfeed&view=feed&contentId=77944'),
(u'Niagara County', u'http://www.buffalonews.com/city/communities/niagara-county/?widget=rssfeed&view=feed&contentId=77944'), (u'Other Sports Columns', u'http://www.buffalonews.com/sports/columns/other-sports-columns/?widget=rssfeed&view=feed&contentId=77944'),
(u'Business', u'http://www.buffalonews.com/business/?widget=rssfeed&view=feed&contentId=77944'), (u'Life', u'http://www.buffalonews.com/life/?widget=rssfeed&view=feed&contentId=77944'),
(u'MoneySmart', u'http://www.buffalonews.com/business/moneysmart/?widget=rssfeed&view=feed&contentId=77944'), (u'Bruce Andriatch', u'http://www.buffalonews.com/city/columns/bruce-andriatch/?widget=rssfeed&view=feed&contentId=77944'),
(u'Bills & NFL', u'http://www.buffalonews.com/sports/bills-nfl/?widget=rssfeed&view=feed&contentId=77944'), (u'Donn Esmonde', u'http://www.buffalonews.com/city/columns/donn-esmonde/?widget=rssfeed&view=feed&contentId=77944'),
(u'Sabres & NHL', u'http://www.buffalonews.com/sports/sabres-nhl/?widget=rssfeed&view=feed&contentId=77944'), (u'Rod Watson', u'http://www.buffalonews.com/city/columns/rod-watson/?widget=rssfeed&view=feed&contentId=77944'),
(u'Bob DiCesare', u'http://www.buffalonews.com/sports/columns/bob-dicesare/?widget=rssfeed&view=feed&contentId=77944'), (u'Entertainment', u'http://www.buffalonews.com/entertainment/?widget=rssfeed&view=feed&contentId=77944'),
(u'Bucky Gleason', u'http://www.buffalonews.com/sports/columns/bucky-gleason/?widget=rssfeed&view=feed&contentId=77944'), (u'Off Main Street', u'http://www.buffalonews.com/city/columns/off-main-street/?widget=rssfeed&view=feed&contentId=77944'),
(u'Mark Gaughan', u'http://www.buffalonews.com/sports/bills-nfl/inside-the-nfl/?widget=rssfeed&view=feed&contentId=77944'), (u'Editorials', u'http://www.buffalonews.com/editorial-page/buffalo-news-editorials/?widget=rssfeed&view=feed&contentId=77944')
(u'Mike Harrington', u'http://www.buffalonews.com/sports/columns/mike-harrington/?widget=rssfeed&view=feed&contentId=77944'),
(u'Jerry Sullivan', u'http://www.buffalonews.com/sports/columns/jerry-sullivan/?widget=rssfeed&view=feed&contentId=77944'),
(u'Other Sports Columns', u'http://www.buffalonews.com/sports/columns/other-sports-columns/?widget=rssfeed&view=feed&contentId=77944'),
(u'Life', u'http://www.buffalonews.com/life/?widget=rssfeed&view=feed&contentId=77944'),
(u'Bruce Andriatch', u'http://www.buffalonews.com/city/columns/bruce-andriatch/?widget=rssfeed&view=feed&contentId=77944'),
(u'Donn Esmonde', u'http://www.buffalonews.com/city/columns/donn-esmonde/?widget=rssfeed&view=feed&contentId=77944'),
(u'Rod Watson', u'http://www.buffalonews.com/city/columns/rod-watson/?widget=rssfeed&view=feed&contentId=77944'),
(u'Entertainment', u'http://www.buffalonews.com/entertainment/?widget=rssfeed&view=feed&contentId=77944'),
(u'Off Main Street', u'http://www.buffalonews.com/city/columns/off-main-street/?widget=rssfeed&view=feed&contentId=77944'),
(u'Editorials', u'http://www.buffalonews.com/editorial-page/buffalo-news-editorials/?widget=rssfeed&view=feed&contentId=77944')
] ]

View File

@ -0,0 +1,51 @@
import re
from calibre.web.feeds.news import BasicNewsRecipe
#from calibre import __appname__
from calibre.utils.magick import Image
class AdvancedUserRecipe1306097511(BasicNewsRecipe):
title = u'Cosmopolitan UK'
description = 'Fashion, beauty and Gossip for women from COSMOPOLITAN -UK'
__author__ = 'Dave Asbury'
# greyscale code by Starson
cover_url = 'http://www.cosmopolitan.magazine.co.uk/files/4613/2085/8988/Cosmo_Cover3.jpg'
no_stylesheets = True
oldest_article = 7
max_articles_per_feed = 20
remove_empty_feeds = True
remove_javascript = True
preprocess_regexps = [
(re.compile(r'<!-- Begin tmpl module_competition_offer -->.*?<!-- End tmpl module_competition_offer-->', re.IGNORECASE | re.DOTALL), lambda match: '')]
language = 'en_GB'
masthead_url = 'http://www.cosmopolitan.co.uk/cm/cosmopolitanuk/site_images/header/cosmouk_logo_home.gif'
keep_only_tags = [
dict(attrs={'class' : ['dateAuthor', 'publishDate']}),
dict(name='div',attrs ={'id' : ['main_content']})
]
remove_tags = [
dict(name='div',attrs={'class' : ['blogInfo','viral_toolbar','comment_number','prevEntry nav']}),
dict(name='div',attrs={'class' : 'blog_module_about_the_authors'}),
dict(attrs={'id': ['breadcrumbs','comment','related_links_list','right_rail','content_sec_fb_more','content_sec_mostpopularstories','content-sec_fb_frame_viewfb_bot']}),
dict(attrs={'class' : ['read_liked_that_header','fb_back_next_area']})
]
feeds = [
(u'Love & Sex', u'http://www.cosmopolitan.co.uk/love-sex/rss/'), (u'Men', u'http://cosmopolitan.co.uk/men/rss/'), (u'Fashion', u'http://cosmopolitan.co.uk/fashion/rss/'), (u'Hair & Beauty', u'http://cosmopolitan.co.uk/beauty-hair/rss/'), (u'LifeStyle', u'http://cosmopolitan.co.uk/lifestyle/rss/'), (u'Cosmo On Campus', u'http://cosmopolitan.co.uk/campus/rss/'), (u'Celebrity Gossip', u'http://cosmopolitan.co.uk/celebrity-gossip/rss/')]
def postprocess_html(self, soup, first):
#process all the images
for tag in soup.findAll(lambda tag: tag.name.lower()=='img' and tag.has_key('src')):
iurl = tag['src']
img = Image()
img.open(iurl)
if img < 0:
raise RuntimeError('Out of memory')
img.type = "GrayscaleType"
img.save(iurl)
return soup

View File

@ -4,7 +4,8 @@ __copyright__ = '2009-2011, Darko Miletic <darko.miletic at gmail.com>'
''' '''
elmundo.es elmundo.es
''' '''
import re
import time
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
class ElMundo(BasicNewsRecipe): class ElMundo(BasicNewsRecipe):
@ -18,12 +19,15 @@ class ElMundo(BasicNewsRecipe):
no_stylesheets = True no_stylesheets = True
use_embedded_content = False use_embedded_content = False
encoding = 'iso8859_15' encoding = 'iso8859_15'
remove_javascript = True
remove_empty_feeds = True
language = 'es' language = 'es'
masthead_url = 'http://estaticos03.elmundo.es/elmundo/iconos/v4.x/v4.01/bg_h1.png' masthead_url = 'http://estaticos03.elmundo.es/elmundo/iconos/v4.x/v4.01/bg_h1.png'
publication_type = 'newspaper' publication_type = 'newspaper'
extra_css = """ extra_css = """
body{font-family: Arial,Helvetica,sans-serif} body{font-family: Arial,Helvetica,sans-serif}
.metadata_noticia{font-size: small} .metadata_noticia{font-size: small}
.pestana_GDP{font-size: small; font-weight:bold}
h1,h2,h3,h4,h5,h6,.subtitulo {color: #3F5974} h1,h2,h3,h4,h5,h6,.subtitulo {color: #3F5974}
.hora{color: red} .hora{color: red}
.update{color: gray} .update{color: gray}
@ -41,22 +45,43 @@ class ElMundo(BasicNewsRecipe):
remove_tags_after = dict(name='div' , attrs={'id':['desarrollo_noticia','tamano']}) remove_tags_after = dict(name='div' , attrs={'id':['desarrollo_noticia','tamano']})
remove_attributes = ['lang','border'] remove_attributes = ['lang','border']
remove_tags = [ remove_tags = [
dict(name='div', attrs={'class':['herramientas','publicidad_google']}) dict(name='div', attrs={'class':['herramientas','publicidad_google','comenta','col col-2b','apoyos','no-te-pierdas']})
,dict(name='div', attrs={'id':'modulo_multimedia' }) ,dict(name='div', attrs={'class':['publicidad publicidad_cuerpo_noticia','comentarios_nav','mensaje_privado','interact']})
,dict(name='div', attrs={'class':['num_comentarios estirar']})
,dict(name='span', attrs={'class':['links_comentar']})
,dict(name='div', attrs={'id':['comentar']})
,dict(name='ul', attrs={'class':'herramientas' }) ,dict(name='ul', attrs={'class':'herramientas' })
,dict(name=['object','link','embed','iframe','base','meta']) ,dict(name=['object','link','embed','iframe','base','meta'])
] ]
feeds = [ feeds = [
(u'Portada' , u'http://estaticos.elmundo.es/elmundo/rss/portada.xml' ) (u'Portada' , u'http://estaticos.elmundo.es/elmundo/rss/portada.xml' )
,(u'Deportes' , u'http://estaticos.elmundo.es/elmundodeporte/rss/portada.xml') ,(u'Deportes' , u'http://estaticos.elmundo.es/elmundodeporte/rss/portada.xml')
,(u'Economia' , u'http://estaticos.elmundo.es/elmundo/rss/economia.xml' ) ,(u'Econom\xeda' , u'http://estaticos.elmundo.es/elmundo/rss/economia.xml' )
,(u'Espana' , u'http://estaticos.elmundo.es/elmundo/rss/espana.xml' ) ,(u'Espa\xf1a' , u'http://estaticos.elmundo.es/elmundo/rss/espana.xml' )
,(u'Internacional' , u'http://estaticos.elmundo.es/elmundo/rss/internacional.xml' ) ,(u'Internacional' , u'http://estaticos.elmundo.es/elmundo/rss/internacional.xml' )
,(u'Cultura' , u'http://estaticos.elmundo.es/elmundo/rss/cultura.xml' ) ,(u'Cultura' , u'http://estaticos.elmundo.es/elmundo/rss/cultura.xml' )
,(u'Ciencia/Ecologia', u'http://estaticos.elmundo.es/elmundo/rss/ciencia.xml' ) ,(u'Ciencia/Ecolog\xeda', u'http://estaticos.elmundo.es/elmundo/rss/ciencia.xml' )
,(u'Comunicacion' , u'http://estaticos.elmundo.es/elmundo/rss/comunicacion.xml' ) ,(u'Comunicaci\xf3n' , u'http://estaticos.elmundo.es/elmundo/rss/comunicacion.xml' )
,(u'Television' , u'http://estaticos.elmundo.es/elmundo/rss/television.xml' ) ,(u'Televisi\xf3n' , u'http://estaticos.elmundo.es/elmundo/rss/television.xml' )
,(u'Salud' , u'http://estaticos.elmundo.es/elmundosalud/rss/portada.xml' )
,(u'Solidaridad' , u'http://estaticos.elmundo.es/elmundo/rss/solidaridad.xml' )
,(u'Su vivienda' , u'http://estaticos.elmundo.es/elmundo/rss/suvivienda.xml' )
,(u'Motor' , u'http://estaticos.elmundo.es/elmundomotor/rss/portada.xml' )
,(u'Madrid' , u'http://estaticos.elmundo.es/elmundo/rss/madrid.xml' )
,(u'Barcelona' , u'http://estaticos.elmundo.es/elmundo/rss/barcelona.xml' )
,(u'Pa\xeds Vasco' , u'http://estaticos.elmundo.es/elmundo/rss/paisvasco.xml' )
,(u'Baleares' , u'http://estaticos.elmundo.es/elmundo/rss/baleares.xml' )
,(u'Castilla y Le\xf3n' , u'http://estaticos.elmundo.es/elmundo/rss/castillayleon.xml' )
,(u'Valladolid' , u'http://estaticos.elmundo.es/elmundo/rss/valladolid.xml' )
,(u'Valencia' , u'http://estaticos.elmundo.es/elmundo/rss/valencia.xml' )
,(u'Alicante' , u'http://estaticos.elmundo.es/elmundo/rss/alicante.xml' )
,(u'Castell\xf3n' , u'http://estaticos.elmundo.es/elmundo/rss/castellon.xml' )
,(u'Andaluc\xeda' , u'http://estaticos.elmundo.es/elmundo/rss/andalucia.xml' )
,(u'Sevilla' , u'http://estaticos.elmundo.es/elmundo/rss/andalucia_sevilla.xml' )
,(u'M\xe1laga' , u'http://estaticos.elmundo.es/elmundo/rss/andalucia_malaga.xml' )
] ]
def preprocess_html(self, soup): def preprocess_html(self, soup):
@ -67,3 +92,34 @@ class ElMundo(BasicNewsRecipe):
def get_article_url(self, article): def get_article_url(self, article):
return article.get('guid', None) return article.get('guid', None)
preprocess_regexps = [
# Para presentar la imagen de los videos incrustados
(re.compile(r'var imagen', re.DOTALL|re.IGNORECASE), lambda match: '--></script><img src'),
(re.compile(r'.jpg";', re.DOTALL|re.IGNORECASE), lambda match: '.jpg">'),
(re.compile(r'var video=', re.DOTALL|re.IGNORECASE), lambda match: '<script language="Javascript" type="text/javascript"><!--'),
# Para que no salga la numeración de comentarios: 1, 2, 3 ...
(re.compile(r'<ol>\n<li style="z-index:', re.DOTALL|re.IGNORECASE), lambda match: '<ul><li style="z-index:'),
(re.compile(r'</ol>\n<div class="num_comentarios estirar">', re.DOTALL|re.IGNORECASE), lambda match: '</ul><div class="num_comentarios estirar">'),
]
# Obtener la imagen de portada
def get_cover_url(self):
cover = None
st = time.localtime()
year = str(st.tm_year)
month = "%.2d" % st.tm_mon
day = "%.2d" % st.tm_mday
#http://img.kiosko.net/2011/11/19/es/elmundo.750.jpg
cover='http://img.kiosko.net/'+ year + '/' + month + '/' + day +'/es/elmundo.750.jpg'
br = BasicNewsRecipe.get_browser()
try:
br.open(cover)
except:
self.log("\nPortada no disponible")
cover ='http://estaticos03.elmundo.es/elmundo/iconos/v4.x/v4.01/bg_h1.png'
return cover

View File

@ -9,6 +9,7 @@ www.guardian.co.uk
from calibre import strftime from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
from datetime import date from datetime import date
from calibre.ebooks.BeautifulSoup import BeautifulSoup, Tag
class Guardian(BasicNewsRecipe): class Guardian(BasicNewsRecipe):
@ -16,16 +17,19 @@ class Guardian(BasicNewsRecipe):
if date.today().weekday() == 6: if date.today().weekday() == 6:
base_url = "http://www.guardian.co.uk/theobserver" base_url = "http://www.guardian.co.uk/theobserver"
cover_pic = 'Observer digital edition' cover_pic = 'Observer digital edition'
masthead_url = 'http://static.guim.co.uk/sys-images/Guardian/Pix/site_furniture/2010/10/19/1287478087992/The-Observer-001.gif'
else: else:
base_url = "http://www.guardian.co.uk/theguardian" base_url = "http://www.guardian.co.uk/theguardian"
cover_pic = 'Guardian digital edition' cover_pic = 'Guardian digital edition'
masthead_url = 'http://static.guim.co.uk/static/f76b43f9dcfd761f0ecf7099a127b603b2922118/common/images/logos/the-guardian/titlepiece.gif'
__author__ = 'Seabound and Sujata Raman' __author__ = 'Seabound and Sujata Raman'
language = 'en_GB' language = 'en_GB'
oldest_article = 7 oldest_article = 7
max_articles_per_feed = 100 max_articles_per_feed = 100
remove_javascript = True remove_javascript = True
encoding = 'utf-8'
# List of section titles to ignore # List of section titles to ignore
# For example: ['Sport'] # For example: ['Sport']
@ -41,6 +45,16 @@ class Guardian(BasicNewsRecipe):
dict(name='div', attrs={'class':["guardian-tickets promo-component",]}), dict(name='div', attrs={'class':["guardian-tickets promo-component",]}),
dict(name='ul', attrs={'class':["pagination"]}), dict(name='ul', attrs={'class':["pagination"]}),
dict(name='ul', attrs={'id':["content-actions"]}), dict(name='ul', attrs={'id':["content-actions"]}),
# article history link
dict(name='a', attrs={'class':["rollover history-link"]}),
# "a version of this article ..." speil
dict(name='div' , attrs = { 'class' : ['section']}),
# "about this article" js dialog
dict(name='div', attrs={'class':["share-top",]}),
# author picture
dict(name='img', attrs={'class':["contributor-pic-small"]}),
# embedded videos/captions
dict(name='span',attrs={'class' : ['inline embed embed-media']}),
#dict(name='img'), #dict(name='img'),
] ]
use_embedded_content = False use_embedded_content = False
@ -67,6 +81,13 @@ class Guardian(BasicNewsRecipe):
def preprocess_html(self, soup): def preprocess_html(self, soup):
# multiple html sections in soup, useful stuff in the first
html = soup.find('html')
soup2 = BeautifulSoup()
soup2.insert(0,html)
soup = soup2
for item in soup.findAll(style=True): for item in soup.findAll(style=True):
del item['style'] del item['style']
@ -74,7 +95,18 @@ class Guardian(BasicNewsRecipe):
del item['face'] del item['face']
for tag in soup.findAll(name=['ul','li']): for tag in soup.findAll(name=['ul','li']):
tag.name = 'div' tag.name = 'div'
# removes number next to rating stars
items_to_remove = []
rating_container = soup.find('div', attrs = {'class': ['rating-container']})
if rating_container:
for item in rating_container:
if isinstance(item, Tag) and str(item.name) == 'span':
items_to_remove.append(item)
for item in items_to_remove:
item.extract()
return soup return soup
def find_sections(self): def find_sections(self):

View File

@ -39,7 +39,9 @@ class TheIndependentNew(BasicNewsRecipe):
encoding = 'utf-8' encoding = 'utf-8'
remove_tags =[ remove_tags =[
dict(attrs={'id' : ['RelatedArtTag','renderBiography']}), dict(attrs={'id' : ['RelatedArtTag','renderBiography']}),
dict(attrs={'class' : ['autoplay','openBiogPopup']}) dict(attrs={'class' : ['autoplay','openBiogPopup']}),
dict(name='img',attrs={'alt' : ['Get Adobe Flash player']}),
dict(attrs={'style' : re.compile('.*')}),
] ]
keep_only_tags =[dict(attrs={'id':'main'})] keep_only_tags =[dict(attrs={'id':'main'})]
@ -113,6 +115,7 @@ class TheIndependentNew(BasicNewsRecipe):
return None return None
items_to_extract = [] items_to_extract = []
slideshow_elements = []
for item in soup.findAll(attrs={'class' : re.compile("widget.*")}): for item in soup.findAll(attrs={'class' : re.compile("widget.*")}):
remove = True remove = True
@ -131,6 +134,7 @@ class TheIndependentNew(BasicNewsRecipe):
if (pattern.search(item['class'])) is not None: if (pattern.search(item['class'])) is not None:
if self._FETCH_IMAGES: if self._FETCH_IMAGES:
remove = False remove = False
slideshow_elements.append(item)
else: else:
remove = True remove = True
@ -148,28 +152,29 @@ class TheIndependentNew(BasicNewsRecipe):
items_to_extract = [] items_to_extract = []
if self._FETCH_IMAGES: if self._FETCH_IMAGES:
for item in soup.findAll('a',attrs={'href' : re.compile('.*')}): for element in slideshow_elements:
if item.img is not None: for item in element.findAll('a',attrs={'href' : re.compile('.*')}):
#use full size image if item.img is not None:
img = item.findNext('img') #use full size image
img = item.findNext('img')
img['src'] = item['href'] img['src'] = item['href']
#insert caption if available #insert caption if available
if img['title'] is not None and (len(img['title']) > 1): if img.get('title') and (len(img['title']) > 1):
tag = Tag(soup,'h3') tag = Tag(soup,'h3')
text = NavigableString(img['title']) text = NavigableString(img['title'])
tag.insert(0,text) tag.insert(0,text)
#picture before text #picture before text
img.extract() img.extract()
item.insert(0,img) item.insert(0,img)
item.insert(1,tag) item.insert(1,tag)
# remove link # remove link
item.name = "div" item.name = "div"
item["class"]='image' item["class"]='image'
del item["href"] del item["href"]
#remove empty subtitles #remove empty subtitles
@ -283,7 +288,7 @@ class TheIndependentNew(BasicNewsRecipe):
items_to_extract = [] items_to_extract = []
for item in soup.findAll('div', attrs={'class' : 'image'}): for item in soup.findAll('div', attrs={'class' : 'image'}):
img = item.findNext('img') img = item.findNext('img')
if img is not None and img['src'] is not None: if img and img.get('src'):
# broken images still point to remote url # broken images still point to remote url
pattern = re.compile('http://www.independent.co.uk.*') pattern = re.compile('http://www.independent.co.uk.*')
if pattern.match(img["src"]) is not None: if pattern.match(img["src"]) is not None:

View File

@ -219,7 +219,7 @@ per_language_title_sort_articles = {
r'Una\s+', r'Unos\s+', r'Unas\s+'), r'Una\s+', r'Unos\s+', r'Unas\s+'),
# French # French
'fra' : (r'Le\s+', r'La\s+', r"L'", r'Les\s+', r'Un\s+', r'Une\s+', 'fra' : (r'Le\s+', r'La\s+', r"L'", r'Les\s+', r'Un\s+', r'Une\s+',
r'Des\s+'), r'Des\s+', r'De\s+La\s+', r'De\s+', r"D'"),
# Italian # Italian
'ita' : (r'Lo\s+', r'Il\s+', r"L'", r'La\s+', r'Gli\s+', r'I\s+', 'ita' : (r'Lo\s+', r'Il\s+', r"L'", r'La\s+', r'Gli\s+', r'I\s+',
r'Le\s+', ), r'Le\s+', ),
@ -230,9 +230,11 @@ per_language_title_sort_articles = {
'ron' : (r'Un\s+', r'O\s+', r'Nişte\s+', ), 'ron' : (r'Un\s+', r'O\s+', r'Nişte\s+', ),
# German # German
'deu' : (r'Der\s+', r'Die\s+', r'Das\s+', r'Den\s+', r'Ein\s+', 'deu' : (r'Der\s+', r'Die\s+', r'Das\s+', r'Den\s+', r'Ein\s+',
r'Eine\s+', r'Einen\s+', ), r'Eine\s+', r'Einen\s+', r'Dem\s+', ),
# Dutch # Dutch
'nld' : (r'De\s+', r'Het\s+', r'Een\s+', ), 'nld' : (r'De\s+', r'Het\s+', r'Een\s+', r"'n\s+", r"'s\s+", r'Ene\s+',
r'Ener\s+', r'Enes\s+', r'Den\s+', r'Der\s+', r'Des\s+',
r"'t\s+"),
# Swedish # Swedish
'swe' : (r'En\s+', r'Ett\s+', r'Det\s+', r'Den\s+', r'De\s+', ), 'swe' : (r'En\s+', r'Ett\s+', r'Det\s+', r'Den\s+', r'De\s+', ),
# Turkish # Turkish
@ -242,6 +244,8 @@ per_language_title_sort_articles = {
# Greek # Greek
'ell' : (r'O\s+', r'I\s+', r'To\s+', r'Ta\s+', r'Tus\s+', r'Tis\s+', 'ell' : (r'O\s+', r'I\s+', r'To\s+', r'Ta\s+', r'Tus\s+', r'Tis\s+',
r"'Enas\s+", r"'Mia\s+", r"'Ena\s+", r"'Enan\s+", ), r"'Enas\s+", r"'Mia\s+", r"'Ena\s+", r"'Enan\s+", ),
# Hungarian
'hun' : (r'A\s+', 'Az\s+', 'Egy\s+',),
} }
default_language_for_title_sort = None default_language_for_title_sort = None
title_sort_articles=r'^(A|The|An)\s+' title_sort_articles=r'^(A|The|An)\s+'

View File

@ -21,7 +21,7 @@ __all__ = [
'linux32', 'linux64', 'linux', 'linux_freeze', 'linux32', 'linux64', 'linux', 'linux_freeze',
'osx32_freeze', 'osx', 'rsync', 'push', 'osx32_freeze', 'osx', 'rsync', 'push',
'win32_freeze', 'win32', 'win', 'win32_freeze', 'win32', 'win',
'stage1', 'stage2', 'stage3', 'stage4', 'publish' 'stage1', 'stage2', 'stage3', 'stage4', 'stage5', 'publish'
] ]
@ -54,13 +54,14 @@ resources = Resources()
kakasi = Kakasi() kakasi = Kakasi()
from setup.publish import Manual, TagRelease, Stage1, Stage2, \ from setup.publish import Manual, TagRelease, Stage1, Stage2, \
Stage3, Stage4, Publish Stage3, Stage4, Stage5, Publish
manual = Manual() manual = Manual()
tag_release = TagRelease() tag_release = TagRelease()
stage1 = Stage1() stage1 = Stage1()
stage2 = Stage2() stage2 = Stage2()
stage3 = Stage3() stage3 = Stage3()
stage4 = Stage4() stage4 = Stage4()
stage5 = Stage5()
publish = Publish() publish = Publish()
from setup.upload import UploadUserManual, UploadInstallers, UploadDemo, \ from setup.upload import UploadUserManual, UploadInstallers, UploadDemo, \

View File

@ -17949,7 +17949,7 @@ msgid "Ndoola"
msgstr "" msgstr ""
#. name for nds #. name for nds
msgid "Saxon; Low" msgid "German; Low"
msgstr "" msgstr ""
#. name for ndt #. name for ndt

View File

@ -22836,7 +22836,7 @@ Source: <http://www.sil.org/iso639-3/>
part2_code="nds" part2_code="nds"
scope="I" scope="I"
type="L" type="L"
name="Saxon; Low" /> name="German; Low" />
<iso_639_3_entry <iso_639_3_entry
id="ndt" id="ndt"
scope="I" scope="I"

View File

@ -37,19 +37,20 @@ class Stage2(Command):
if os.path.exists(build): if os.path.exists(build):
shutil.rmtree(build) shutil.rmtree(build)
class Stage3(Command): class Stage3(Command):
description = 'Stage 3 of the publish process' description = 'Stage 3 of the publish process'
sub_commands = ['upload_user_manual', 'upload_demo', 'sdist', sub_commands = ['upload_user_manual', 'upload_demo', 'sdist']
'upload_to_sourceforge', 'upload_to_google_code',
'tag_release', 'upload_to_server',
]
class Stage4(Command): class Stage4(Command):
description = 'Stage 4 of the publish process' description = 'Stage 4 of the publish process'
sub_commands = ['upload_to_sourceforge', 'upload_to_google_code']
class Stage5(Command):
description = 'Stage 5 of the publish process'
sub_commands = ['tag_release', 'upload_to_server']
def run(self, opts): def run(self, opts):
subprocess.check_call('rm -rf build/* dist/*', shell=True) subprocess.check_call('rm -rf build/* dist/*', shell=True)
@ -57,7 +58,7 @@ class Stage4(Command):
class Publish(Command): class Publish(Command):
description = 'Publish a new calibre release' description = 'Publish a new calibre release'
sub_commands = ['stage1', 'stage2', 'stage3', 'stage4'] sub_commands = ['stage1', 'stage2', 'stage3', 'stage4', 'stage5', ]
class Manual(Command): class Manual(Command):

View File

@ -141,8 +141,17 @@ class UploadToGoogleCode(Command): # {{{
'dmg':'OSX','bz2':'Linux','gz':'All'}[ext] 'dmg':'OSX','bz2':'Linux','gz':'All'}[ext]
desc = installer_description(fname) desc = installer_description(fname)
start = time.time() start = time.time()
path = self.upload(os.path.abspath(fname), desc, for i in range(5):
labels=[typ, op, 'Featured']) try:
path = self.upload(os.path.abspath(fname), desc,
labels=[typ, op, 'Featured'])
except:
import traceback
traceback.print_exc()
print ('\nUpload failed, trying again in 30 secs')
time.sleep(30)
else:
break
self.info('Uploaded to:', path, 'in', int(time.time() - start), self.info('Uploaded to:', path, 'in', int(time.time() - start),
'seconds') 'seconds')
return path return path
@ -312,9 +321,16 @@ class UploadToSourceForge(Command): # {{{
if not os.path.exists(x): continue if not os.path.exists(x): continue
start = time.time() start = time.time()
self.info('Uploading', x) self.info('Uploading', x)
check_call(['rsync', '-z', '--progress', '-e', 'ssh -x', x, for i in range(5):
'%s,%s@frs.sourceforge.net:%s'%(self.USERNAME, self.PROJECT, try:
self.rdir+'/')]) check_call(['rsync', '-z', '--progress', '-e', 'ssh -x', x,
'%s,%s@frs.sourceforge.net:%s'%(self.USERNAME, self.PROJECT,
self.rdir+'/')])
except:
print ('\nUpload failed, trying again in 30 seconds')
time.sleep(30)
else:
break
print 'Uploaded in', int(time.time() - start), 'seconds' print 'Uploaded in', int(time.time() - start), 'seconds'
print ('\n') print ('\n')

View File

@ -4,7 +4,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__ = u'calibre' __appname__ = u'calibre'
numeric_version = (0, 8, 27) numeric_version = (0, 8, 28)
__version__ = u'.'.join(map(unicode, numeric_version)) __version__ = u'.'.join(map(unicode, numeric_version))
__author__ = u"Kovid Goyal <kovid@kovidgoyal.net>" __author__ = u"Kovid Goyal <kovid@kovidgoyal.net>"

View File

@ -449,7 +449,7 @@ class CatalogPlugin(Plugin): # {{{
['author_sort','authors','comments','cover','formats', ['author_sort','authors','comments','cover','formats',
'id','isbn','ondevice','pubdate','publisher','rating', 'id','isbn','ondevice','pubdate','publisher','rating',
'series_index','series','size','tags','timestamp', 'series_index','series','size','tags','timestamp',
'title_sort','title','uuid']) 'title_sort','title','uuid','languages'])
all_custom_fields = set(db.custom_field_keys()) all_custom_fields = set(db.custom_field_keys())
all_fields = all_std_fields.union(all_custom_fields) all_fields = all_std_fields.union(all_custom_fields)

View File

@ -109,12 +109,16 @@ def get_title_sort_pat(lang=None):
q = canonicalize_lang(q) if q else q q = canonicalize_lang(q) if q else q
data = tweaks['per_language_title_sort_articles'] data = tweaks['per_language_title_sort_articles']
ans = data.get(q, None) ans = data.get(q, None)
if ans is None: try:
ans = data['eng'] ans = frozenset(ans) if ans else frozenset(data['eng'])
ans = frozenset(ans + data['eng']) except:
ans = frozenset((r'A\s+', r'The\s+', r'An\s+'))
ans = '|'.join(ans) ans = '|'.join(ans)
ans = '^(%s)'%ans ans = '^(%s)'%ans
ans = re.compile(ans, re.IGNORECASE) try:
ans = re.compile(ans, re.IGNORECASE)
except:
ans = re.compile(r'^(A|The|An)\s+', re.IGNORECASE)
_title_pats[lang] = ans _title_pats[lang] = ans
return ans return ans

View File

@ -0,0 +1,11 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'

View File

@ -1409,8 +1409,8 @@ void PictureFlow::dataChanged() { d->dataChanged(); }
void PictureFlow::emitcurrentChanged(int index) { emit currentChanged(index); } void PictureFlow::emitcurrentChanged(int index) { emit currentChanged(index); }
int FlowImages::count() { return 0; } int FlowImages::count() { return 0; }
QImage FlowImages::image(int index) { index=0; return QImage(); } QImage FlowImages::image(int index) { Q_UNUSED(index); return QImage(); }
QString FlowImages::caption(int index) {index=0; return QString(); } QString FlowImages::caption(int index) { Q_UNUSED(index); return QString(); }
QString FlowImages::subtitle(int index) {index=0; return QString(); } QString FlowImages::subtitle(int index) { Q_UNUSED(index); return QString(); }
// }}} // }}}

View File

@ -42,9 +42,8 @@ class EbookpointStore(BasicStoreConfig, StorePlugin):
d.set_tags(self.config.get('tags', '')) d.set_tags(self.config.get('tags', ''))
d.exec_() d.exec_()
def search(self, query, max_results=10, timeout=60): def search(self, query, max_results=25, timeout=60):
url = 'http://ebookpoint.pl/search.scgi?szukaj=' + urllib.quote(query) + '&serwisyall=0&x=0&y=0' url = 'http://ebookpoint.pl/search.scgi?szukaj=' + urllib.quote_plus(query.decode('utf-8').encode('iso-8859-2')) + '&serwisyall=0&x=0&y=0'
ebook_string = 'eBook.'
br = browser() br = browser()
@ -60,19 +59,19 @@ class EbookpointStore(BasicStoreConfig, StorePlugin):
continue continue
cover_url = ''.join(data.xpath('.//a[@class="cover"]/img/@src')) cover_url = ''.join(data.xpath('.//a[@class="cover"]/img/@src'))
title = ''.join(data.xpath('.//h3/a/text()')) title = ''.join(data.xpath('.//h3/a/@title'))
title = re.sub(ebook_string, '', title) title = re.sub('eBook.', '', title)
author = ''.join(data.xpath('.//p[@class="author"]/text()')) author = ''.join(data.xpath('.//p[@class="author"]/text()'))
price = ''.join(data.xpath('.//p[@class="price"]/ins/text()')) price = ''.join(data.xpath('.//p[@class="price"]/ins/text()'))
with closing(br.open(id.strip(), timeout=timeout)) as nf: with closing(br.open(id.strip(), timeout=timeout)) as nf:
idata = html.fromstring(nf.read()) idata = html.fromstring(nf.read())
formats = ', '.join(idata.xpath('//div[@class="col-left"]/h2[contains(., "' + ebook_string + '")]/@class')) formats = ', '.join(idata.xpath('//dd[@class="radio-line"]/label/text()'))
counter -= 1 counter -= 1
s = SearchResult() s = SearchResult()
s.cover_url = 'http://ebookpoint.pl' + cover_url s.cover_url = 'http://ebookpoint.pl' + re.sub('72x9', '65x8',cover_url)
s.title = title.strip() s.title = title.strip()
s.author = author.strip() s.author = author.strip()
s.price = re.sub(r'\.',',',price) s.price = re.sub(r'\.',',',price)

View File

@ -15,7 +15,7 @@ from calibre.utils.config import tweaks, prefs
from calibre.utils.date import parse_date, now, UNDEFINED_DATE, clean_date_for_sort from calibre.utils.date import parse_date, now, UNDEFINED_DATE, clean_date_for_sort
from calibre.utils.search_query_parser import SearchQueryParser from calibre.utils.search_query_parser import SearchQueryParser
from calibre.utils.pyparsing import ParseException from calibre.utils.pyparsing import ParseException
from calibre.utils.localization import canonicalize_lang, lang_map from calibre.utils.localization import canonicalize_lang, lang_map, get_udc
from calibre.ebooks.metadata import title_sort, author_to_author_sort from calibre.ebooks.metadata import title_sort, author_to_author_sort
from calibre.ebooks.metadata.opf2 import metadata_to_opf from calibre.ebooks.metadata.opf2 import metadata_to_opf
from calibre import prints from calibre import prints
@ -217,6 +217,7 @@ class ResultCache(SearchQueryParser): # {{{
self.FIELD_MAP = FIELD_MAP self.FIELD_MAP = FIELD_MAP
self.db_prefs = db_prefs self.db_prefs = db_prefs
self.composites = {} self.composites = {}
self.udc = get_udc()
for key in field_metadata: for key in field_metadata:
if field_metadata[key]['datatype'] == 'composite': if field_metadata[key]['datatype'] == 'composite':
self.composites[field_metadata[key]['rec_index']] = key self.composites[field_metadata[key]['rec_index']] = key
@ -261,6 +262,15 @@ class ResultCache(SearchQueryParser): # {{{
# Search functions {{{ # Search functions {{{
def ascii_name(self, name):
try:
ans = self.udc.decode(name)
if ans == name:
ans = False
except:
ans = False
return ans
def universal_set(self): def universal_set(self):
return set([i[0] for i in self._data if i is not None]) return set([i[0] for i in self._data if i is not None])
@ -734,6 +744,8 @@ class ResultCache(SearchQueryParser): # {{{
else: else:
q = query q = query
au_loc = self.FIELD_MAP['authors']
for id_ in candidates: for id_ in candidates:
item = self._data[id_] item = self._data[id_]
if item is None: continue if item is None: continue
@ -776,6 +788,9 @@ class ResultCache(SearchQueryParser): # {{{
if loc not in exclude_fields: # time for text matching if loc not in exclude_fields: # time for text matching
if is_multiple_cols[loc] is not None: if is_multiple_cols[loc] is not None:
vals = [v.strip() for v in item[loc].split(is_multiple_cols[loc])] vals = [v.strip() for v in item[loc].split(is_multiple_cols[loc])]
if loc == au_loc:
vals += filter(None, map(self.ascii_name,
vals))
else: else:
vals = [item[loc]] ### make into list to make _match happy vals = [item[loc]] ### make into list to make _match happy
if _match(q, vals, matchkind): if _match(q, vals, matchkind):

View File

@ -29,7 +29,8 @@ from calibre.utils.zipfile import ZipFile
FIELDS = ['all', 'title', 'title_sort', 'author_sort', 'authors', 'comments', FIELDS = ['all', 'title', 'title_sort', 'author_sort', 'authors', 'comments',
'cover', 'formats','id', 'isbn', 'ondevice', 'pubdate', 'publisher', 'cover', 'formats','id', 'isbn', 'ondevice', 'pubdate', 'publisher',
'rating', 'series_index', 'series', 'size', 'tags', 'timestamp', 'uuid'] 'rating', 'series_index', 'series', 'size', 'tags', 'timestamp',
'uuid', 'languages']
#Allowed fields for template #Allowed fields for template
TEMPLATE_ALLOWED_FIELDS = [ 'author_sort', 'authors', 'id', 'isbn', 'pubdate', 'title_sort', TEMPLATE_ALLOWED_FIELDS = [ 'author_sort', 'authors', 'id', 'isbn', 'pubdate', 'title_sort',
@ -601,7 +602,7 @@ class BIBTEX(CatalogPlugin): # {{{
bibtexc, db, citation_bibtex, addfiles_bibtex)) bibtexc, db, citation_bibtex, addfiles_bibtex))
# }}} # }}}
class EPUB_MOBI(CatalogPlugin): class EPUB_MOBI(CatalogPlugin): # {{{
'ePub catalog generator' 'ePub catalog generator'
Option = namedtuple('Option', 'option, default, dest, action, help') Option = namedtuple('Option', 'option, default, dest, action, help')
@ -5177,3 +5178,4 @@ Author '{0}':
# returns to gui2.actions.catalog:catalog_generated() # returns to gui2.actions.catalog:catalog_generated()
return catalog.error return catalog.error
# }}}

View File

@ -342,7 +342,8 @@ def remove_option_parser():
Remove the books identified by ids from the database. ids should be a comma separated \ Remove the books identified by ids from the database. ids should be a comma separated \
list of id numbers (you can get id numbers by using the list command). For example, \ list of id numbers (you can get id numbers by using the list command). For example, \
23,34,57-85 23,34,57-85 (when specifying a range, the last number in the range is not
included).
''')) '''))
def command_remove(args, dbpath): def command_remove(args, dbpath):

View File

@ -13,7 +13,7 @@ import threading, random
from itertools import repeat from itertools import repeat
from math import ceil from math import ceil
from calibre import prints from calibre import prints, force_unicode
from calibre.ebooks.metadata import (title_sort, author_to_author_sort, from calibre.ebooks.metadata import (title_sort, author_to_author_sort,
string_to_authors, authors_to_string, get_title_sort_pat) string_to_authors, authors_to_string, get_title_sort_pat)
from calibre.ebooks.metadata.opf2 import metadata_to_opf from calibre.ebooks.metadata.opf2 import metadata_to_opf
@ -33,7 +33,7 @@ from calibre import isbytestring
from calibre.utils.filenames import ascii_filename from calibre.utils.filenames import ascii_filename
from calibre.utils.date import utcnow, now as nowf, utcfromtimestamp from calibre.utils.date import utcnow, now as nowf, utcfromtimestamp
from calibre.utils.config import prefs, tweaks, from_json, to_json from calibre.utils.config import prefs, tweaks, from_json, to_json
from calibre.utils.icu import sort_key, strcmp from calibre.utils.icu import sort_key, strcmp, lower
from calibre.utils.search_query_parser import saved_searches, set_saved_searches from calibre.utils.search_query_parser import saved_searches, set_saved_searches
from calibre.ebooks import BOOK_EXTENSIONS, check_ebook_format from calibre.ebooks import BOOK_EXTENSIONS, check_ebook_format
from calibre.utils.magick.draw import save_cover_data_to from calibre.utils.magick.draw import save_cover_data_to
@ -1003,6 +1003,19 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
return bool(self.conn.get('SELECT id FROM books where title=?', (title,), all=False)) return bool(self.conn.get('SELECT id FROM books where title=?', (title,), all=False))
return False return False
def books_with_same_title(self, mi, all_matches=True):
title = mi.title
ans = set()
if title:
title = lower(force_unicode(title))
for book_id in self.all_ids():
x = self.title(book_id, index_is_id=True)
if lower(x) == title:
ans.add(book_id)
if not all_matches:
break
return ans
def find_identical_books(self, mi): def find_identical_books(self, mi):
fuzzy_title_patterns = [(re.compile(pat, re.IGNORECASE) if fuzzy_title_patterns = [(re.compile(pat, re.IGNORECASE) if
isinstance(pat, basestring) else pat, repl) for pat, repl in isinstance(pat, basestring) else pat, repl) for pat, repl in
@ -3365,7 +3378,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
prefix = self.library_path prefix = self.library_path
FIELDS = set(['title', 'sort', 'authors', 'author_sort', 'publisher', 'rating', FIELDS = set(['title', 'sort', 'authors', 'author_sort', 'publisher', 'rating',
'timestamp', 'size', 'tags', 'comments', 'series', 'series_index', 'timestamp', 'size', 'tags', 'comments', 'series', 'series_index',
'uuid', 'pubdate', 'last_modified', 'identifiers']) 'uuid', 'pubdate', 'last_modified', 'identifiers', 'languages'])
for x in self.custom_column_num_map: for x in self.custom_column_num_map:
FIELDS.add(x) FIELDS.add(x)
data = [] data = []

View File

@ -351,7 +351,7 @@ You can build advanced search queries easily using the :guilabel:`Advanced Searc
clicking the button |sbi|. clicking the button |sbi|.
Available fields for searching are: ``tag, title, author, publisher, series, series_index, rating, cover, Available fields for searching are: ``tag, title, author, publisher, series, series_index, rating, cover,
comments, format, identifiers, date, pubdate, search, size`` and custom columns. If a device is plugged in, the ``ondevice`` field becomes available. To find the search name (actually called the `lookup name`) for a custom column, hover your mouse over the column header in the library view. comments, format, identifiers, date, pubdate, search, size`` and custom columns. If a device is plugged in, the ``ondevice`` field becomes available, when searching the calibre library view. To find the search name (actually called the `lookup name`) for a custom column, hover your mouse over the column header in the library view.
The syntax for searching for dates is:: The syntax for searching for dates is::

View File

@ -4,9 +4,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: calibre 0.8.27\n" "Project-Id-Version: calibre 0.8.28\n"
"POT-Creation-Date: 2011-11-23 13:00+IST\n" "POT-Creation-Date: 2011-11-25 09:00+IST\n"
"PO-Revision-Date: 2011-11-23 13:00+IST\n" "PO-Revision-Date: 2011-11-25 09:00+IST\n"
"Last-Translator: Automatically generated\n" "Last-Translator: Automatically generated\n"
"Language-Team: LANGUAGE\n" "Language-Team: LANGUAGE\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@ -24,8 +24,8 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/db/cache.py:105 #: /home/kovid/work/calibre/src/calibre/db/cache.py:105
#: /home/kovid/work/calibre/src/calibre/db/cache.py:108 #: /home/kovid/work/calibre/src/calibre/db/cache.py:108
#: /home/kovid/work/calibre/src/calibre/db/cache.py:119 #: /home/kovid/work/calibre/src/calibre/db/cache.py:119
#: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:265
#: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:266 #: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:266
#: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:267
#: /home/kovid/work/calibre/src/calibre/devices/hanvon/driver.py:99 #: /home/kovid/work/calibre/src/calibre/devices/hanvon/driver.py:99
#: /home/kovid/work/calibre/src/calibre/devices/hanvon/driver.py:100 #: /home/kovid/work/calibre/src/calibre/devices/hanvon/driver.py:100
#: /home/kovid/work/calibre/src/calibre/devices/jetbook/driver.py:74 #: /home/kovid/work/calibre/src/calibre/devices/jetbook/driver.py:74
@ -889,15 +889,15 @@ msgstr ""
msgid "Communicate with Android phones." msgid "Communicate with Android phones."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:148 #: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:149
msgid "Comma separated list of directories to send e-books to on the device. The first one that exists will be used" msgid "Comma separated list of directories to send e-books to on the device. The first one that exists will be used"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:205 #: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:206
msgid "Communicate with S60 phones." msgid "Communicate with S60 phones."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:224 #: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:225
msgid "Communicate with WebOS tablets." msgid "Communicate with WebOS tablets."
msgstr "" msgstr ""
@ -16284,23 +16284,23 @@ msgstr ""
msgid "list_union(list1, list2, separator) -- return a list made by merging the items in list1 and list2, removing duplicate items using a case-insensitive compare. If items differ in case, the one in list1 is used. The items in list1 and list2 are separated by separator, as are the items in the returned list." msgid "list_union(list1, list2, separator) -- return a list made by merging the items in list1 and list2, removing duplicate items using a case-insensitive compare. If items differ in case, the one in list1 is used. The items in list1 and list2 are separated by separator, as are the items in the returned list."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:936 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:935
msgid "list_difference(list1, list2, separator) -- return a list made by removing from list1 any item found in list2, using a case-insensitive compare. The items in list1 and list2 are separated by separator, as are the items in the returned list." msgid "list_difference(list1, list2, separator) -- return a list made by removing from list1 any item found in list2, using a case-insensitive compare. The items in list1 and list2 are separated by separator, as are the items in the returned list."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:957 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:956
msgid "list_intersection(list1, list2, separator) -- return a list made by removing from list1 any item not found in list2, using a case-insensitive compare. The items in list1 and list2 are separated by separator, as are the items in the returned list." msgid "list_intersection(list1, list2, separator) -- return a list made by removing from list1 any item not found in list2, using a case-insensitive compare. The items in list1 and list2 are separated by separator, as are the items in the returned list."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:978 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:977
msgid "list_sort(list, direction, separator) -- return list sorted using a case-insensitive sort. If direction is zero, the list is sorted ascending, otherwise descending. The list items are separated by separator, as are the items in the returned list." msgid "list_sort(list, direction, separator) -- return list sorted using a case-insensitive sort. If direction is zero, the list is sorted ascending, otherwise descending. The list items are separated by separator, as are the items in the returned list."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:993 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:992
msgid "list_equals(list1, sep1, list2, sep2, yes_val, no_val) -- return yes_val if list1 and list2 contain the same items, otherwise return no_val. The items are determined by splitting each list using the appropriate separator character (sep1 or sep2). The order of items in the lists is not relevant. The compare is case insensitive." msgid "list_equals(list1, sep1, list2, sep2, yes_val, no_val) -- return yes_val if list1 and list2 contain the same items, otherwise return no_val. The items are determined by splitting each list using the appropriate separator character (sep1 or sep2). The order of items in the lists is not relevant. The compare is case insensitive."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:1011 #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:1010
msgid "list_re(src_list, separator, search_re, opt_replace) -- Construct a list by first separating src_list into items using the separator character. For each item in the list, check if it matches search_re. If it does, then add it to the list to be returned. If opt_replace is not the empty string, then apply the replacement before adding the item to the returned list." msgid "list_re(src_list, separator, search_re, opt_replace) -- Construct a list by first separating src_list into items using the separator character. For each item in the list, check if it matches search_re. If it does, then add it to the list to be returned. If opt_replace is not the empty string, then apply the replacement before adding the item to the returned list."
msgstr "" msgstr ""