KG updates

This commit is contained in:
GRiker 2010-11-09 11:33:38 -07:00
commit 9aa768b23f
35 changed files with 1241 additions and 238 deletions

View File

@ -4,7 +4,7 @@
<html> <html>
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>..:: calibre library ::.. {title}</title> <title>..:: calibre {library} ::.. {title}</title>
<meta http-equiv="X-UA-Compatible" content="IE=100" /> <meta http-equiv="X-UA-Compatible" content="IE=100" />
<link rel="icon" type="image/x-icon" href="http://calibre-ebook.com/favicon.ico" /> <link rel="icon" type="image/x-icon" href="http://calibre-ebook.com/favicon.ico" />
@ -41,7 +41,7 @@
<div class="area"> <div class="area">
<div class="bubble"> <div class="bubble">
<p><a href="{prefix}/browse" title="Return to top level" <p><a href="{prefix}/browse" title="Return to top level"
>&rarr;&nbsp;home&nbsp;&larr;</a></p> >&rarr;&nbsp;{home}&nbsp;&larr;</a></p>
</div> </div>
</div> </div>
<div id="nav-container">&nbsp; <div id="nav-container">&nbsp;
@ -80,7 +80,7 @@
<form name="search_form" action="{prefix}/browse/search" method="get" accept-charset="UTF-8"> <form name="search_form" action="{prefix}/browse/search" method="get" accept-charset="UTF-8">
<input value="{initial_search}" type="text" title="Search" name="query" <input value="{initial_search}" type="text" title="Search" name="query"
class="search_input" />&nbsp; class="search_input" />&nbsp;
<input type="submit" value="Search" title="Search" alt="Search" /> <input type="submit" value="{Search}" title="{Search}" alt="{Search}" />
</form> </form>
</div> </div>
<div>&nbsp;</div> <div>&nbsp;</div>

View File

@ -211,3 +211,9 @@ generate_cover_title_font = None
# Absolute path to a TTF font file to use as the font for the footer in the # Absolute path to a TTF font file to use as the font for the footer in the
# default cover # default cover
generate_cover_foot_font = None generate_cover_foot_font = None
# Behavior of doubleclick on the books list. Choices:
# open_viewer, do_nothing, edit_cell. Default: open_viewer.
# Example: doubleclick_on_library_view = 'do_nothing'
doubleclick_on_library_view = 'open_viewer'

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 861 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

View File

@ -0,0 +1,46 @@
__license__ = 'GPL v3'
__copyright__ = '2010, BlonG'
'''
avto-magazin.si
'''
from calibre.web.feeds.news import BasicNewsRecipe
class Dnevnik(BasicNewsRecipe):
title = u'Avto Magazin'
__author__ = u'BlonG'
description = u'Za avtomobilisti\xc4\x8dne frike, poznavalce in nedeljske \xc5\xa1oferje.'
oldest_article = 7
max_articles_per_feed = 20
labguage = 'sl'
no_stylesheets = True
use_embedded_content = False
conversion_options = {'linearize_tables' : True}
cover_url = 'https://sites.google.com/site/javno2010/home/avto_magazin_cover.jpg'
extra_css = '''
h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;}
h2{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;}
p{font-family:Arial,Helvetica,sans-serif;font-size:small;}
body{font-family:Helvetica,Arial,sans-serif;font-size:small;}
'''
keep_only_tags = [
dict(name='div', attrs={'id':'_iprom_inStream'}),
# dict(name='div', attrs={'class':'entry-content'}),
]
remove_tags = [
dict(name='div', attrs={'id':'voteConfirmation'}),
dict(name='div', attrs={'id':'InsideVote'}),
dict(name='div', attrs={'class':'Zone234'}),
dict(name='div', attrs={'class':'Comments'}),
dict(name='div', attrs={'class':'sorodneNovice'}),
dict(name='div', attrs={'id':'footer'}),
]
feeds = [
(u'Novice', u'http://www.avto-magazin.si/rss/')
]

View File

@ -25,7 +25,7 @@ class Danas(BasicNewsRecipe):
remove_empty_feeds = True remove_empty_feeds = True
extra_css = """ @font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} extra_css = """ @font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)}
@font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)}
.article_description,body,.lokacija{font-family: Tahoma,Arial,Helvetica,sans1,sans-serif} .article,.articledescription,body,.lokacija,.feed{font-family: Tahoma,Arial,Helvetica,sans1,sans-serif}
.nadNaslov,h1,.preamble{font-family: Georgia,"Times New Roman",Times,serif1,serif} .nadNaslov,h1,.preamble{font-family: Georgia,"Times New Roman",Times,serif1,serif}
.antrfileText{border-left: 2px solid #999999; .antrfileText{border-left: 2px solid #999999;
margin-left: 0.8em; margin-left: 0.8em;
@ -66,7 +66,7 @@ class Danas(BasicNewsRecipe):
keep_only_tags = [dict(name='div', attrs={'id':'left'})] keep_only_tags = [dict(name='div', attrs={'id':'left'})]
remove_tags = [ remove_tags = [
dict(name='div', attrs={'class':['width_1_4','metaClanka','baner']}) dict(name='div', attrs={'class':['width_1_4','metaClanka','baner','listaVesti','article_nav']})
,dict(name='div', attrs={'id':'comments'}) ,dict(name='div', attrs={'id':'comments'})
,dict(name=['object','link','iframe','meta']) ,dict(name=['object','link','iframe','meta'])
] ]

View File

@ -0,0 +1,42 @@
from calibre.web.feeds.news import BasicNewsRecipe
class DiarioSport(BasicNewsRecipe):
title = u'Diario Sport'
oldest_article = 2
max_articles_per_feed = 75
__author__ = 'Jefferson Frantz'
description = 'Todas las noticias del Barça y del mundo del deporte en general'
timefmt = ' [%d %b, %Y]'
language = 'es'
no_stylesheets = True
feeds = [(u'Sport', u'http://feeds.feedburner.com/sport/ultimahora')]
extra_css = '''
h2{font-family: serif; font-size: small; font-weight: bold; color: #000000; text-align: justify}
'''
keep_only_tags = [dict(name='div', attrs={'id':['noticiasMedio']})]
remove_tags = [
dict(name=['object','link','script','ul'])
,dict(name='div', attrs={'id':['scrAdSense','herramientas2','participacion','participacion2','bloque1resultados','bloque2resultados','cont_vinyetesAnt','tinta','noticiasSuperior','cintillopublicidad2']})
,dict(name='p', attrs={'class':['masinformacion','hora']})
,dict(name='a', attrs={'class':["'link'"]})
,dict(name='div', attrs={'class':['addthis_toolbox addthis_default_style','firma','pretitularnoticia']})
,dict(name='form', attrs={'id':['formularioDeBusquedaAvanzada']})
]
def preprocess_html(self, soup):
for item in soup.findAll(style=True):
del item['style']
return soup
def postprocess_html(self, soup, first_fetch):
img = soup.find('img',src='/img/videos/mascaravideo.png')
if not img is None:
img.extract()
return soup

View File

@ -0,0 +1,63 @@
__license__ = 'GPL v3'
__copyright__ = '2010, BlonG'
'''
dnevnik.si
'''
from calibre.web.feeds.news import BasicNewsRecipe
class Dnevnik(BasicNewsRecipe):
title = u'Dnevnik.si'
__author__ = u'BlonG'
description = u'''Dnevnik je \u010dasnik z ve\u010d kot polstoletno zgodovino.
Pod sloganom \xbb\u017divljenje ima besedo\xab na svojih straneh prina\u0161a
bralcem bogastvo informacij, komentarjev in kolumen in raznovrstnost
pogledov, zaznamovanih z odgovornostjo do posameznika in \u0161ir\u0161e
dru\u017ebe.'''
oldest_article = 3
max_articles_per_feed = 20
language = 'sl'
no_stylesheets = True
use_embedded_content = False
cover_url = 'https://sites.google.com/site/javno2010/home/dnevnik_cover.jpg'
extra_css = '''
h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;}
h2{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;}
p{font-family:Arial,Helvetica,sans-serif;font-size:small;}
body{font-family:Helvetica,Arial,sans-serif;font-size:small;}
'''
keep_only_tags = [
dict(name='div', attrs={'id':'_iprom_inStream'}),
dict(name='div', attrs={'class':'entry-content'}),
]
remove_tags = [
dict(name='div', attrs={'class':'fb_article_top'}),
dict(name='div', attrs={'class':'related'}),
dict(name='div', attrs={'class':'fb_article_foot'}),
dict(name='div', attrs={'class':'spreading'}),
dict(name='dl', attrs={'class':'ad'}),
dict(name='p', attrs={'class':'report'}),
dict(name='div', attrs={'class':'hfeed comments'}),
dict(name='dl', attrs={'id':'entryPanel'}),
dict(name='dl', attrs={'class':'infopush ip_wide'}),
dict(name='div', attrs={'class':'sidebar'}),
dict(name='dl', attrs={'class':'bottom'}),
dict(name='div', attrs={'id':'footer'}),
]
feeds = [
(u'Slovenija', u'http://www.dnevnik.si/rss/?articleType=1&articleSection=13')
,(u'Svet', u'http://www.dnevnik.si/rss/?articleType=1&articleSection=14')
,(u'EU', u'http://www.dnevnik.si/rss/?articleType=1&articleSection=116')
,(u'Poslovni dnevnik', u'http://www.dnevnik.si/rss/?articleType=1&articleSection=5')
,(u'Kronika', u'http://www.dnevnik.si/rss/?articleType=1&articleSection=15')
,(u'Kultura', u'http://www.dnevnik.si/rss/?articleType=1&articleSection=17')
,(u'Zdravje', u'http://www.dnevnik.si/rss/?articleType=1&articleSection=18')
,(u'Znanost in IT', u'http://www.dnevnik.si/rss/?articleType=1&articleSection=19')
,(u'(Ne)verjetno', u'http://www.dnevnik.si/rss/?articleType=1&articleSection=20')
,(u'E-strada', u'http://www.dnevnik.si/rss/?articleType=1&articleSection=21')
,(u'Svet vozil', u'http://www.dnevnik.si/rss/?articleType=1&articleSection=22')
]

View File

@ -0,0 +1,38 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2010, Brendan Sleight <bms.calibre at barwap.com>'
'''
hola.com
'''
from calibre.web.feeds.news import BasicNewsRecipe
class Hackaday(BasicNewsRecipe):
title = u'Hola'
__author__ = 'bmsleight'
description = 'diario de actualidad, moda y belleza.'
oldest_article = 10
max_articles_per_feed = 100
no_stylesheets = True
language = 'es'
use_embedded_content = False
keep_only_tags = [
dict(name='div', attrs={'id':'cuerpo'})
]
feeds = [
(u'Famosos' , u'http://www.hola.com/famosos/rss.xml' ),
(u'Realeza' , u'http://www.hola.com/realeza/rss.xml' ),
(u'Cine' , u'http://www.hola.com/cine/rss.xml' ),
(u'Música' , u'http://www.hola.com/musica/rss.xml' ),
(u'Moda y modelos' , u'http://www.hola.com/moda/portada/rss.xml' ),
(u'Belleza y salud', u'http://www.hola.com/belleza/portada/rss.xml' ),
(u'Niños' , u'http://www.hola.com/ninos/rss.xml' ),
(u'Todas las noticias', u'http://int2.hola.com/app/feeds/rss_hola.php'),
]
def get_article_url(self, article):
url = article.get('guid', None)
return url

View File

@ -0,0 +1,57 @@
__license__ = 'GPL v3'
__copyright__ = '2010, BlonG'
'''
www.rtvslo.si
'''
from calibre.web.feeds.news import BasicNewsRecipe
class MMCRTV(BasicNewsRecipe):
title = u'MMC RTV Slovenija'
__author__ = u'BlonG'
description = u"Prvi interaktivni multimedijski portal, MMC RTV Slovenija"
oldest_article = 3
max_articles_per_feed = 20
language = 'sl'
no_stylesheets = True
use_embedded_content = False
cover_url = 'https://sites.google.com/site/javno2010/home/rtv_slo_cover.jpg'
extra_css = '''
h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;}
h2{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;}
p{font-family:Arial,Helvetica,sans-serif;font-size:small;}
body{font-family:Helvetica,Arial,sans-serif;font-size:small;}
'''
def print_version(self, url):
split_url = url.split("/")
print_url = 'http://www.rtvslo.si/index.php?c_mod=news&op=print&id=' + split_url[-1]
return print_url
keep_only_tags = [
dict(name='div', attrs={'class':'title'}),
dict(name='div', attrs={'id':'newsbody'}),
dict(name='div', attrs={'id':'newsblocks'}),
]
# remove_tags=[
# 40 dict(name='div', attrs={'id':'newsblocks'}),
# ]
feeds = [
(u'Slovenija', u'http://www.rtvslo.si/feeds/01.xml'),
(u'Svet', u'http://www.rtvslo.si/feeds/02.xml'),
(u'Evropska unija', u'http://www.rtvslo.si/feeds/16.xml'),
(u'Gospodarstvo', u'http://www.rtvslo.si/feeds/04.xml'),
(u'\u010crna kronika', u'http://www.rtvslo.si/feeds/08.xml'),
(u'Okolje', u'http://www.rtvslo.si/feeds/12.xml'),
(u'Znanost in tehnologija', u'http://www.rtvslo.si/feeds/09.xml'),
(u'Zabava', u'http://www.rtvslo.si/feeds/06.xml'),
(u'Ture avanture', u'http://www.rtvslo.si/feeds/28.xml'),
]
# def preprocess_html(self, soup):
# newsblocks = soup.find('div',attrs = ['id':'newsblocks'])
# soup.find('div', attrs = {'id':'newsbody'}).insert(-1, newsblocks)
# return soup

View File

@ -0,0 +1,73 @@
from calibre.web.feeds.news import BasicNewsRecipe, LoginFailed
class SCPrintMagazine(BasicNewsRecipe):
title = u'SC Print Magazine'
__author__ = u'Tony Maro'
description = u'Last print version of the data security magazine'
INDEX = "http://www.scmagazineus.com/issuearchive/"
no_stylesheets = True
language = 'en'
keep_only_tags = [dict(id=['article','review'])]
remove_tags = [dict(id=['articlePrintTools','reviewBodyColumn'])]
LOG_IN = 'http://www.scmagazineus.com/login/'
tags = 'News,SC Magazine'
needs_subscription = True
def parse_index(self):
articles = []
issuelink = printsections = None
soup = self.index_to_soup(self.INDEX)
sectit = soup.find('div', attrs={'class':'issueArchiveItem'})
if sectit is not None:
linkt = sectit.find('a')
issuelink = linkt['href']
imgt = sectit.find('img')
self.cover_url = imgt['src']
if issuelink is not None:
issue = self.index_to_soup(issuelink)
if issue is not None:
printsections = issue.findAll('div',attrs={'class':'PrintSection'})
if printsections is not None:
for printsection in printsections:
onesection = []
sectiontitle = printsection.find('h3').contents[0]
articlesec = printsection.findAll('div',attrs={'class':'IssueArchiveFormat'})
if articlesec is not None:
''' got articles '''
for onearticle in articlesec:
''' process one article '''
arttitlet = onearticle.find('h3')
if arttitlet is not None:
mylink = arttitlet.find('a')
if mylink is not None:
if mylink.has_key('title'):
arttitle = mylink['title']
else:
arttitle = 'unknown'
if mylink.has_key('href'):
artlink = mylink['href']
artlink = artlink.replace("/article","/printarticle")
artlink = artlink.replace("/review","/printreview")
deck = onearticle.find('div',attrs={'class':'deck'})
if deck is not None:
deck = deck.contents[0]
onesection.append({'title':arttitle, 'url':artlink, 'description':deck,'date':''})
articles.append((sectiontitle, onesection))
return articles
def get_browser(self):
br = BasicNewsRecipe.get_browser(self)
br.open(self.LOG_IN)
br.select_form(name='aspnetForm')
br['ctl00$ctl00$cphAllPageContent$cphMainContent$SubscriberEasyLoginView1$txtEmail'] = self.username
br['ctl00$ctl00$cphAllPageContent$cphMainContent$SubscriberEasyLoginView1$txtPassword'] = self.password
raw = br.submit("ctl00$ctl00$cphAllPageContent$cphMainContent$SubscriberEasyLoginView1$btnLogin").read()
if 'Logout</a>' not in raw:
raise LoginFailed(
_('Failed to log in, check your username and password for'
' the calibre Periodicals service.'))
return br

View File

@ -0,0 +1,55 @@
# coding: utf-8
__license__ = 'GPL v3'
__copyright__ = '2010, BlonG'
'''
www.siol.si
'''
from calibre.web.feeds.news import BasicNewsRecipe
class Siol(BasicNewsRecipe):
title = u'Siol.net'
__author__ = u'BlonG'
description = "Multimedijski portal z aktualnimi vsebinami, intervjuji, komentarji iz Slovenije in sveta, sportal, trendi, avtomoto, blogos"
oldest_article = 3
language = 'sl'
max_articles_per_feed = 20
no_stylesheets = True
use_embedded_content = False
cover_url = 'https://sites.google.com/site/javno2010/home/siol_cover.jpg'
extra_css = '''
h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;}
h2{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;}
p{font-family:Arial,Helvetica,sans-serif;font-size:small;}
body{font-family:Helvetica,Arial,sans-serif;font-size:small;}
'''
html2lrf_options = ['--base-font-size', '10']
keep_only_tags = [
dict(name='div', attrs={'id':'idContent'}),
]
remove_tags = [
dict(name='span', attrs={'class':'com1'}),
dict(name='div', attrs={'class':'relation'}),
dict(name='p', attrs={'class':'path'}),
dict(name='div', attrs={'class':'clear_r'}),
dict(name='div', attrs={'id':'appendix'}),
dict(name='div', attrs={'id':'rail'}),
dict(name='div', attrs={'id':'div_comments'}),
dict(name='div', attrs={'class':'thumbs'}),
]
feeds = [
(u'Slovenija', u'http://www.siol.net/rss.aspx?path=Slovenija')
,(u'Lokalne novice', u'http://www.siol.net/rss.aspx?path=Slovenija/Lokalne_novice')
,(u'EU', u'http://www.siol.net/rss.aspx?path=EU')
,(u'Svet', u'http://www.siol.net/rss.aspx?path=Svet')
,(u'Gospodarstvo', u'http://www.siol.net/rss.aspx?path=Gospodarstvo')
,(u'Sportal', u'http://www.siol.net/rss.aspx?path=Sportal')
,(u'Trendi', u'http://www.siol.net/rss.aspx?path=Trendi')
,(u'Avtomoto', u'http://www.siol.net/rss.aspx?path=Avtomoto')
,(u'Tehnologija', u'http://www.siol.net/rss.aspx?path=Tehnologija')
,(u'TV / Film', u'http://www.siol.net/rss.aspx?path=TV')
]

View File

@ -0,0 +1,195 @@
#!/usr/bin/env python
u'''
Ведомости
'''
from calibre.web.feeds.feedparser import parse
from calibre.ebooks.BeautifulSoup import Tag
from calibre.web.feeds.news import BasicNewsRecipe
class VedomostiRecipe(BasicNewsRecipe):
title = u'Ведомости'
__author__ = 'Nikolai Kotchetkov'
publisher = 'vedomosti.ru'
category = 'press, Russia'
description = u'Ежедневная деловая газета'
oldest_article = 3
max_articles_per_feed = 100
masthead_url = u'http://motorro.com/imgdir/logos/ved_logo_black2_cropped.gif'
cover_url = u'http://motorro.com/imgdir/logos/ved_logo_black2_cropped.gif'
#Add feed names if you want them to be sorted (feeds of this list appear first)
sortOrder = [u'_default', u'Первая полоса', u'Власть и деньги']
encoding = 'cp1251'
language = 'ru'
no_stylesheets = True
remove_javascript = True
recursions = 0
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : language
}
keep_only_tags = [dict(name='td', attrs={'class' : ['second_content']})]
remove_tags_after = [dict(name='div', attrs={'class' : 'article_text'})]
remove_tags = [dict(name='div', attrs={'class' : ['sep', 'choice', 'articleRightTbl']})]
feeds = [u'http://www.vedomosti.ru/newspaper/out/rss.xml']
#base URL for relative links
base_url = u'http://www.vedomosti.ru'
extra_css = 'h1 {font-size: 1.5em; margin: 0em 0em 0em 0em; text-align: center;}'\
'h2 {font-size: 1.0em; margin: 0em 0em 0em 0em;}'\
'h3 {font-size: 0.8em; margin: 0em 0em 0em 0em;}'\
'.article_date {font-size: 0.5em; color: gray; font-family: monospace; text-align:right;}'\
'.article_authors {font-size: 0.5em; color: gray; font-family: monospace; text-align:right;}'\
'.article_img {width:100%; text-align: center; padding: 3px 3px 3px 3px;}'\
'.article_img_desc {width:100%; text-align: center; font-size: 0.5em; color: gray; font-family: monospace;}'\
'.article_desc {font-size: 1em; font-style:italic;}'
def parse_index(self):
try:
feedData = parse(self.feeds[0])
if not feedData:
raise NotImplementedError
self.log("parse_index: Feed loaded successfully.")
if feedData.feed.has_key('title'):
self.title = feedData.feed.title
self.log("parse_index: Title updated to: ", self.title)
if feedData.feed.has_key('description'):
self.description = feedData.feed.description
self.log("parse_index: Description updated to: ", self.description)
def get_virtual_feed_articles(feed):
if feeds.has_key(feed):
return feeds[feed][1]
self.log("Adding new feed: ", feed)
articles = []
feeds[feed] = (feed, articles)
return articles
feeds = {}
#Iterate feed items and distribute articles using tags
for item in feedData.entries:
link = item.get('link', '');
title = item.get('title', '');
if '' == link or '' == title:
continue
article = {'title':title, 'url':link, 'description':item.get('description', ''), 'date':item.get('date', ''), 'content':''};
if not item.has_key('tags'):
get_virtual_feed_articles('_default').append(article)
continue
for tag in item.tags:
addedToDefault = False
term = tag.get('term', '')
if '' == term:
if (not addedToDefault):
get_virtual_feed_articles('_default').append(article)
continue
get_virtual_feed_articles(term).append(article)
#Get feed list
#Select sorted feeds first of all
result = []
for feedName in self.sortOrder:
if (not feeds.has_key(feedName)): continue
result.append(feeds[feedName])
del feeds[feedName]
result = result + feeds.values()
return result
except Exception, err:
self.log(err)
raise NotImplementedError
def preprocess_html(self, soup):
return self.adeify_images(soup)
def postprocess_html(self, soup, first_fetch):
#self.log('Original: ', soup.prettify())
#Find article
contents = soup.find('div', {'class':['article_text']})
if not contents:
self.log('postprocess_html: article div not found!')
return soup
contents.extract()
#Find title
title = soup.find('h1')
if title:
contents.insert(0, title)
#Find article image
newstop = soup.find('div', {'class':['newstop']})
if newstop:
img = newstop.find('img')
if img:
imgDiv = Tag(soup, 'div')
imgDiv['class'] = 'article_img'
if img.has_key('width'):
del(img['width'])
if img.has_key('height'):
del(img['height'])
#find description
element = img.parent.nextSibling
img.extract()
imgDiv.insert(0, img)
while element:
if not isinstance(element, Tag):
continue
nextElement = element.nextSibling
if 'p' == element.name:
element.extract()
element['class'] = 'article_img_desc'
imgDiv.insert(len(imgDiv.contents), element)
element = nextElement
contents.insert(1, imgDiv)
#find article abstract
abstract = soup.find('p', {'class':['subhead']})
if abstract:
abstract['class'] = 'article_desc'
contents.insert(2, abstract)
#Find article authors
authorsDiv = soup.find('div', {'class':['autors']})
if authorsDiv:
authorsP = authorsDiv.find('p')
if authorsP:
authorsP['class'] = 'article_authors'
contents.insert(len(contents.contents), authorsP)
#Fix urls that use relative path
urls = contents.findAll('a');
if urls:
for url in urls:
if not url.has_key('href'):
continue
if '/' == url['href'][0]:
url['href'] = self.base_url + url['href']
body = soup.find('td', {'class':['second_content']})
if body:
body.replaceWith(contents)
self.log('Result: ', soup.prettify())
return soup

View File

@ -49,7 +49,6 @@ class Push(Command):
print '\n\nPushing to:', host, '\n' print '\n\nPushing to:', host, '\n'
threads.append(Thread(target=subprocess.check_call, args=(rcmd,))) threads.append(Thread(target=subprocess.check_call, args=(rcmd,)))
threads[-1].start() threads[-1].start()
subprocess.check_call(rcmd)
for thread in threads: for thread in threads:
thread.join() thread.join()

View File

@ -444,6 +444,9 @@ xml_entity_to_unicode = partial(entity_to_unicode, result_exceptions = {
def replace_entities(raw): def replace_entities(raw):
return _ent_pat.sub(entity_to_unicode, raw) return _ent_pat.sub(entity_to_unicode, raw)
def xml_replace_entities(raw):
return _ent_pat.sub(xml_entity_to_unicode, raw)
def prepare_string_for_xml(raw, attribute=False): def prepare_string_for_xml(raw, attribute=False):
raw = _ent_pat.sub(entity_to_unicode, raw) raw = _ent_pat.sub(entity_to_unicode, raw)
raw = raw.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;') raw = raw.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')

View File

@ -109,8 +109,9 @@ class OCFZipReader(OCFReader):
raise EPubException("not a ZIP .epub OCF container") raise EPubException("not a ZIP .epub OCF container")
self.root = root self.root = root
if self.root is None: if self.root is None:
if hasattr(stream, 'name'): name = getattr(stream, 'name', False)
self.root = os.path.abspath(os.path.dirname(stream.name)) if name:
self.root = os.path.abspath(os.path.dirname(name))
else: else:
self.root = os.getcwdu() self.root = os.getcwdu()
super(OCFZipReader, self).__init__() super(OCFZipReader, self).__init__()

View File

@ -133,7 +133,11 @@ class DetectStructure(object):
def elem_to_link(self, item, elem, counter): def elem_to_link(self, item, elem, counter):
text = xml2text(elem) text = xml2text(elem).strip()
if not text:
text = elem.get('title', '')
if not text:
text = elem.get('alt', '')
text = text[:100].strip() text = text[:100].strip()
id = elem.get('id', 'calibre_toc_%d'%counter) id = elem.get('id', 'calibre_toc_%d'%counter)
elem.set('id', id) elem.set('id', id)

View File

@ -213,11 +213,13 @@ class BookInfo(QWebView):
f = QFontInfo(QApplication.font(self.parent())).pixelSize() f = QFontInfo(QApplication.font(self.parent())).pixelSize()
p = unicode(QApplication.palette().color(QPalette.Normal, p = unicode(QApplication.palette().color(QPalette.Normal,
QPalette.Base).name()) QPalette.Base).name())
c = unicode(QApplication.palette().color(QPalette.Normal,
QPalette.Text).name())
templ = u'''\ templ = u'''\
<html> <html>
<head> <head>
<style type="text/css"> <style type="text/css">
body, td {background-color: %s; font-size: %dpx} body, td {background-color: %s; font-size: %dpx; color: %s }
a { text-decoration: none; color: blue } a { text-decoration: none; color: blue }
</style> </style>
</head> </head>
@ -225,7 +227,7 @@ class BookInfo(QWebView):
%%s %%s
</body> </body>
<html> <html>
'''%(p, f) '''%(p, f, c)
if self.vertical: if self.vertical:
if comments: if comments:
rows += u'<tr><td colspan="2">%s</td></tr>'%comments rows += u'<tr><td colspan="2">%s</td></tr>'%comments

File diff suppressed because one or more lines are too long

View File

@ -5,8 +5,8 @@ __docformat__ = 'restructuredtext en'
import textwrap, os, re import textwrap, os, re
from PyQt4.QtCore import QCoreApplication, SIGNAL, QModelIndex, QTimer, Qt from PyQt4.Qt import QCoreApplication, SIGNAL, QModelIndex, QTimer, Qt, \
from PyQt4.QtGui import QDialog, QPixmap, QGraphicsScene, QIcon QDialog, QPixmap, QGraphicsScene, QIcon, QSize
from calibre.gui2.dialogs.book_info_ui import Ui_BookInfo from calibre.gui2.dialogs.book_info_ui import Ui_BookInfo
from calibre.gui2 import dynamic, open_local_file from calibre.gui2 import dynamic, open_local_file
@ -20,6 +20,8 @@ class BookInfo(QDialog, Ui_BookInfo):
Ui_BookInfo.__init__(self) Ui_BookInfo.__init__(self)
self.setupUi(self) self.setupUi(self)
self.cover_pixmap = None self.cover_pixmap = None
self.comments.sizeHint = self.comments_size_hint
desktop = QCoreApplication.instance().desktop() desktop = QCoreApplication.instance().desktop()
screen_height = desktop.availableGeometry().height() - 100 screen_height = desktop.availableGeometry().height() - 100
self.resize(self.size().width(), screen_height) self.resize(self.size().width(), screen_height)
@ -37,12 +39,16 @@ class BookInfo(QDialog, Ui_BookInfo):
self.fit_cover.stateChanged.connect(self.toggle_cover_fit) self.fit_cover.stateChanged.connect(self.toggle_cover_fit)
self.cover.resizeEvent = self.cover_view_resized self.cover.resizeEvent = self.cover_view_resized
def comments_size_hint(self):
return QSize(350, 350)
def toggle_cover_fit(self, state): def toggle_cover_fit(self, state):
dynamic.set('book_info_dialog_fit_cover', self.fit_cover.isChecked()) dynamic.set('book_info_dialog_fit_cover', self.fit_cover.isChecked())
self.resize_cover() self.resize_cover()
def cover_view_resized(self, event): def cover_view_resized(self, event):
QTimer.singleShot(1, self.resize_cover) QTimer.singleShot(1, self.resize_cover)
def slave(self, current, previous): def slave(self, current, previous):
row = current.row() row = current.row()
self.refresh(row) self.refresh(row)

View File

@ -47,9 +47,15 @@
<property name="title"> <property name="title">
<string>Comments</string> <string>Comments</string>
</property> </property>
<layout class="QGridLayout"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item row="0" column="0"> <item>
<widget class="QWebView" name="comments"> <widget class="QWebView" name="comments">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>350</width> <width>350</width>

View File

@ -240,13 +240,13 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
self.writable_fields = [''] self.writable_fields = ['']
fm = self.db.field_metadata fm = self.db.field_metadata
for f in fm: for f in fm:
if (f in ['author_sort'] or ( if (f in ['author_sort'] or
fm[f]['datatype'] in ['text', 'series']) (fm[f]['datatype'] in ['text', 'series']
and fm[f].get('search_terms', None) and fm[f].get('search_terms', None)
and f not in ['formats', 'ondevice']): and f not in ['formats', 'ondevice', 'sort'])):
self.all_fields.append(f) self.all_fields.append(f)
self.writable_fields.append(f) self.writable_fields.append(f)
if fm[f]['datatype'] == 'composite': if f in ['sort'] or fm[f]['datatype'] == 'composite':
self.all_fields.append(f) self.all_fields.append(f)
self.all_fields.sort() self.all_fields.sort()
self.writable_fields.sort() self.writable_fields.sort()
@ -274,7 +274,6 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
self.main_heading = _( self.main_heading = _(
'<b>You can destroy your library using this feature.</b> ' '<b>You can destroy your library using this feature.</b> '
'Changes are permanent. There is no undo function. ' 'Changes are permanent. There is no undo function. '
' This feature is experimental, and there may be bugs. '
'You are strongly encouraged to back up your library ' 'You are strongly encouraged to back up your library '
'before proceeding.<p>' 'before proceeding.<p>'
'Search and replace in text fields using character matching ' 'Search and replace in text fields using character matching '
@ -338,6 +337,9 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
def s_r_get_field(self, mi, field): def s_r_get_field(self, mi, field):
if field: if field:
fm = self.db.metadata_for_field(field) fm = self.db.metadata_for_field(field)
if field == 'sort':
val = mi.get('title_sort', None)
else:
val = mi.get(field, None) val = mi.get(field, None)
if val is None: if val is None:
val = [] val = []

View File

@ -400,7 +400,7 @@ Future conversion of these books will use the default settings.</string>
</widget> </widget>
<widget class="QWidget" name="tabWidgetPage3"> <widget class="QWidget" name="tabWidgetPage3">
<attribute name="title"> <attribute name="title">
<string>&amp;Search and replace (experimental)</string> <string>&amp;Search and replace</string>
</attribute> </attribute>
<layout class="QGridLayout" name="vargrid"> <layout class="QGridLayout" name="vargrid">
<property name="sizeConstraint"> <property name="sizeConstraint">

View File

@ -845,7 +845,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
if cf is not None and hasattr(cf, 'terminate'): if cf is not None and hasattr(cf, 'terminate'):
cf.terminate() cf.terminate()
cf.wait() cf.wait()
self.save_state()
QDialog.reject(self, *args) QDialog.reject(self, *args)
def read_state(self): def read_state(self):

View File

@ -1,17 +1,75 @@
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>' __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
import re
from PyQt4.QtGui import QDialog import re, copy
from PyQt4.QtGui import QDialog, QDialogButtonBox
from calibre.gui2.dialogs.search_ui import Ui_Dialog from calibre.gui2.dialogs.search_ui import Ui_Dialog
from calibre.library.caches import CONTAINS_MATCH, EQUALS_MATCH from calibre.library.caches import CONTAINS_MATCH, EQUALS_MATCH
from calibre.gui2 import gprefs
box_values = {}
class SearchDialog(QDialog, Ui_Dialog): class SearchDialog(QDialog, Ui_Dialog):
def __init__(self, *args): def __init__(self, parent, db):
QDialog.__init__(self, *args) QDialog.__init__(self, parent)
self.setupUi(self) self.setupUi(self)
self.mc = '' self.mc = ''
searchables = sorted(db.field_metadata.searchable_fields(),
lambda x, y: cmp(x if x[0] != '#' else x[1:],
y if y[0] != '#' else y[1:]))
self.general_combo.addItems(searchables)
self.box_last_values = copy.deepcopy(box_values)
if self.box_last_values:
for k,v in self.box_last_values.items():
if k == 'general_index':
continue
getattr(self, k).setText(v)
self.general_combo.setCurrentIndex(
self.general_combo.findText(self.box_last_values['general_index']))
self.buttonBox.accepted.connect(self.advanced_search_button_pushed)
self.tab_2_button_box.accepted.connect(self.accept)
self.tab_2_button_box.rejected.connect(self.reject)
self.clear_button.clicked.connect(self.clear_button_pushed)
self.adv_search_used = False
current_tab = gprefs.get('advanced search dialog current tab', 0)
self.tabWidget.setCurrentIndex(current_tab)
self.tabWidget.currentChanged[int].connect(self.tab_changed)
self.tab_changed(current_tab)
def save_state(self):
gprefs['advanced search dialog current tab'] = \
self.tabWidget.currentIndex()
def accept(self):
self.save_state()
return QDialog.accept(self)
def reject(self):
self.save_state()
return QDialog.reject(self)
def tab_changed(self, idx):
if idx == 1:
self.tab_2_button_box.button(QDialogButtonBox.Ok).setDefault(True)
else:
self.buttonBox.button(QDialogButtonBox.Ok).setDefault(True)
def advanced_search_button_pushed(self):
self.adv_search_used = True
self.accept()
def clear_button_pushed(self):
self.title_box.setText('')
self.authors_box.setText('')
self.series_box.setText('')
self.tags_box.setText('')
self.general_box.setText('')
def tokens(self, raw): def tokens(self, raw):
phrases = re.findall(r'\s*".*?"\s*', raw) phrases = re.findall(r'\s*".*?"\s*', raw)
@ -21,6 +79,12 @@ class SearchDialog(QDialog, Ui_Dialog):
return ['"' + self.mc + t + '"' for t in phrases + [r.strip() for r in raw.split()]] return ['"' + self.mc + t + '"' for t in phrases + [r.strip() for r in raw.split()]]
def search_string(self): def search_string(self):
if self.adv_search_used:
return self.adv_search_string()
else:
return self.box_search_string()
def adv_search_string(self):
mk = self.matchkind.currentIndex() mk = self.matchkind.currentIndex()
if mk == CONTAINS_MATCH: if mk == CONTAINS_MATCH:
self.mc = '' self.mc = ''
@ -56,3 +120,36 @@ class SearchDialog(QDialog, Ui_Dialog):
tok = '"%s"'%tok tok = '"%s"'%tok
return tok return tok
def box_search_string(self):
ans = []
self.box_last_values = {}
title = unicode(self.title_box.text()).strip()
self.box_last_values['title_box'] = title
if title:
ans.append('title:"' + title + '"')
author = unicode(self.authors_box.text()).strip()
self.box_last_values['authors_box'] = author
if author:
ans.append('author:"' + author + '"')
series = unicode(self.series_box.text()).strip()
self.box_last_values['series_box'] = series
if series:
ans.append('series:"' + series + '"')
self.mc = '='
tags = unicode(self.tags_box.text())
self.box_last_values['tags_box'] = tags
tags = self.tokens(tags)
if tags:
tags = ['tags:' + t for t in tags]
ans.append('(' + ' or '.join(tags) + ')')
general = unicode(self.general_box.text())
self.box_last_values['general_box'] = general
general_index = unicode(self.general_combo.currentText())
self.box_last_values['general_index'] = general_index
global box_values
box_values = copy.deepcopy(self.box_last_values)
if general:
ans.append(unicode(self.general_combo.currentText()) + ':"' + general + '"')
if ans:
return ' and '.join(ans)
return ''

View File

@ -1,76 +1,87 @@
<ui version="4.0" > <?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class> <class>Dialog</class>
<widget class="QDialog" name="Dialog" > <widget class="QDialog" name="Dialog">
<property name="geometry" > <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>667</width> <width>731</width>
<height>391</height> <height>384</height>
</rect> </rect>
</property> </property>
<property name="windowTitle" > <property name="windowTitle">
<string>Advanced Search</string> <string>Advanced Search</string>
</property> </property>
<property name="windowIcon" > <property name="windowIcon">
<iconset resource="../../../../resources/images.qrc" > <iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/search.png</normaloff>:/images/search.png</iconset> <normaloff>:/images/search.png</normaloff>:/images/search.png</iconset>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_3" > <layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>A&amp;dvanced Search</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item> <item>
<widget class="QGroupBox" name="groupBox" > <widget class="QGroupBox" name="groupBox">
<property name="title" > <property name="title">
<string>Find entries that have...</string> <string>Find entries that have...</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout" > <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout" > <layout class="QHBoxLayout" name="horizontalLayout">
<item> <item>
<widget class="QLabel" name="label" > <widget class="QLabel" name="label">
<property name="text" > <property name="text">
<string>&amp;All these words:</string> <string>&amp;All these words:</string>
</property> </property>
<property name="buddy" > <property name="buddy">
<cstring>all</cstring> <cstring>all</cstring>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLineEdit" name="all" /> <widget class="QLineEdit" name="all"/>
</item> </item>
</layout> </layout>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_2" > <layout class="QHBoxLayout" name="horizontalLayout_2">
<item> <item>
<widget class="QLabel" name="label_2" > <widget class="QLabel" name="label_2">
<property name="text" > <property name="text">
<string>This exact &amp;phrase:</string> <string>This exact &amp;phrase:</string>
</property> </property>
<property name="buddy" > <property name="buddy">
<cstring>all</cstring> <cstring>all</cstring>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLineEdit" name="phrase" /> <widget class="QLineEdit" name="phrase"/>
</item> </item>
</layout> </layout>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_3" > <layout class="QHBoxLayout" name="horizontalLayout_3">
<item> <item>
<widget class="QLabel" name="label_3" > <widget class="QLabel" name="label_3">
<property name="text" > <property name="text">
<string>&amp;One or more of these words:</string> <string>&amp;One or more of these words:</string>
</property> </property>
<property name="buddy" > <property name="buddy">
<cstring>all</cstring> <cstring>all</cstring>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLineEdit" name="any" /> <widget class="QLineEdit" name="any"/>
</item> </item>
</layout> </layout>
</item> </item>
@ -78,46 +89,43 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QGroupBox" name="groupBox_2" > <widget class="QGroupBox" name="groupBox_2">
<property name="title" > <property name="title">
<string>But dont show entries that have...</string> <string>But dont show entries that have...</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2" > <layout class="QVBoxLayout" name="verticalLayout_2">
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_4" > <layout class="QHBoxLayout" name="horizontalLayout_4">
<item> <item>
<widget class="QLabel" name="label_4" > <widget class="QLabel" name="label_4">
<property name="text" > <property name="text">
<string>Any of these &amp;unwanted words:</string> <string>Any of these &amp;unwanted words:</string>
</property> </property>
<property name="buddy" > <property name="buddy">
<cstring>all</cstring> <cstring>all</cstring>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLineEdit" name="none" /> <widget class="QLineEdit" name="none"/>
</item> </item>
</layout> </layout>
</item> </item>
</layout>
</widget>
</item>
<item> <item>
<widget class="QGroupBox" name="groupBox" > <widget class="QGroupBox" name="groupBox">
<property name="maximumSize" > <property name="maximumSize">
<size> <size>
<width>16777215</width> <width>16777215</width>
<height>60</height> <height>60</height>
</size> </size>
</property> </property>
<layout class="QHBoxLayout" name="horizontalLayout_5" > <layout class="QHBoxLayout" name="horizontalLayout_5">
<item> <item>
<widget class="QLabel" name="label_5" > <widget class="QLabel" name="label_5">
<property name="text" > <property name="text">
<string>What kind of match to use:</string> <string>What kind of match to use:</string>
</property> </property>
<property name="buddy" > <property name="buddy">
<cstring>matchkind</cstring> <cstring>matchkind</cstring>
</property> </property>
</widget> </widget>
@ -142,17 +150,17 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="label_51" > <widget class="QLabel" name="label_51">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>40</horstretch> <horstretch>40</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="text" > <property name="text">
<string> </string> <string/>
</property> </property>
<property name="buddy" > <property name="buddy">
<cstring>matchkind</cstring> <cstring>matchkind</cstring>
</property> </property>
</widget> </widget>
@ -161,35 +169,191 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="label_6" > <widget class="QLabel" name="label_6">
<property name="maximumSize" > <property name="maximumSize">
<size> <size>
<width>16777215</width> <width>16777215</width>
<height>30</height> <height>30</height>
</size> </size>
</property> </property>
<property name="text" > <property name="text">
<string>See the &lt;a href="http://calibre-ebook.com/user_manual/gui.html#the-search-interface">User Manual&lt;/a> for more help</string> <string>See the &lt;a href=&quot;http://calibre-ebook.com/user_manual/gui.html#the-search-interface&quot;&gt;User Manual&lt;/a&gt; for more help</string>
</property> </property>
<property name="openExternalLinks" > <property name="openExternalLinks">
<bool>true</bool> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
</layout>
</widget>
</item>
<item> <item>
<widget class="QDialogButtonBox" name="buttonBox" > <spacer name="verticalSpacer_2">
<property name="orientation" > <property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="standardButtons" > <property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property> </property>
</widget> </widget>
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Titl&amp;e/Author/Series ...</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>&amp;Title:</string>
</property>
<property name="buddy">
<cstring>title_box</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="title_box">
<property name="toolTip">
<string>Enter the title.</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>&amp;Author:</string>
</property>
<property name="buddy">
<cstring>authors_box</cstring>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>&amp;Series:</string>
</property>
<property name="buddy">
<cstring>series_box</cstring>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Ta&amp;gs:</string>
</property>
<property name="buddy">
<cstring>tags_box</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="authors_box">
<property name="toolTip">
<string>Enter an author's name. Only one author can be used.</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="series_box">
<property name="toolTip">
<string>Enter a series name, without an index. Only one series name can be used.</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="tags_box">
<property name="toolTip">
<string>Enter tags separated by spaces</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="general_box"/>
</item>
<item row="6" column="0">
<widget class="QComboBox" name="general_combo"/>
</item>
<item row="8" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QPushButton" name="clear_button">
<property name="text">
<string>&amp;Clear</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="tab_2_button_box">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
<item row="7" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Search only in specific fields:</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>all</tabstop>
<tabstop>phrase</tabstop>
<tabstop>any</tabstop>
<tabstop>none</tabstop>
<tabstop>matchkind</tabstop>
<tabstop>buttonBox</tabstop>
<tabstop>title_box</tabstop>
<tabstop>authors_box</tabstop>
<tabstop>series_box</tabstop>
<tabstop>tags_box</tabstop>
<tabstop>general_combo</tabstop>
<tabstop>general_box</tabstop>
<tabstop>clear_button</tabstop>
<tabstop>tab_2_button_box</tabstop>
<tabstop>tabWidget</tabstop>
</tabstops>
<resources> <resources>
<include location="../../../../resources/images.qrc" /> <include location="../../../../resources/images.qrc"/>
</resources> </resources>
<connections> <connections>
<connection> <connection>
@ -198,11 +362,11 @@
<receiver>Dialog</receiver> <receiver>Dialog</receiver>
<slot>accept()</slot> <slot>accept()</slot>
<hints> <hints>
<hint type="sourcelabel" > <hint type="sourcelabel">
<x>248</x> <x>248</x>
<y>254</y> <y>254</y>
</hint> </hint>
<hint type="destinationlabel" > <hint type="destinationlabel">
<x>157</x> <x>157</x>
<y>274</y> <y>274</y>
</hint> </hint>
@ -214,11 +378,11 @@
<receiver>Dialog</receiver> <receiver>Dialog</receiver>
<slot>reject()</slot> <slot>reject()</slot>
<hints> <hints>
<hint type="sourcelabel" > <hint type="sourcelabel">
<x>316</x> <x>316</x>
<y>260</y> <y>260</y>
</hint> </hint>
<hint type="destinationlabel" > <hint type="destinationlabel">
<x>286</x> <x>286</x>
<y>274</y> <y>274</y>
</hint> </hint>

View File

@ -167,6 +167,7 @@ class SearchBar(QWidget): # {{{
x.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) x.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
parent.advanced_search_button = x = QToolButton(self) parent.advanced_search_button = x = QToolButton(self)
parent.advanced_search_button.setShortcut(_("Shift+Ctrl+F"))
x.setIcon(QIcon(I('search.png'))) x.setIcon(QIcon(I('search.png')))
l.addWidget(x) l.addWidget(x)
x.setToolTip(_("Advanced search")) x.setToolTip(_("Advanced search"))

View File

@ -51,6 +51,10 @@ class BooksView(QTableView): # {{{
QTableView.__init__(self, parent) QTableView.__init__(self, parent)
self.setEditTriggers(self.SelectedClicked|self.EditKeyPressed) self.setEditTriggers(self.SelectedClicked|self.EditKeyPressed)
if tweaks['doubleclick_on_library_view'] == 'edit_cell':
self.setEditTriggers(self.DoubleClicked|self.editTriggers())
elif tweaks['doubleclick_on_library_view'] == 'open_viewer':
self.doubleClicked.connect(parent.iactions['View'].view_triggered)
self.drag_allowed = True self.drag_allowed = True
self.setDragEnabled(True) self.setDragEnabled(True)
@ -100,8 +104,6 @@ class BooksView(QTableView): # {{{
self._model.about_to_be_sorted.connect(self.about_to_be_sorted) self._model.about_to_be_sorted.connect(self.about_to_be_sorted)
self._model.sorting_done.connect(self.sorting_done) self._model.sorting_done.connect(self.sorting_done)
self.doubleClicked.connect(parent.iactions['View'].view_triggered)
# Column Header Context Menu {{{ # Column Header Context Menu {{{
def column_header_context_handler(self, action=None, column=None): def column_header_context_handler(self, action=None, column=None):
if not action or not column: if not action or not column:

View File

@ -392,7 +392,7 @@ class SearchBoxMixin(object):
self.tags_view.clear() self.tags_view.clear()
def do_advanced_search(self, *args): def do_advanced_search(self, *args):
d = SearchDialog(self) d = SearchDialog(self, self.library_view.model().db)
if d.exec_() == QDialog.Accepted: if d.exec_() == QDialog.Accepted:
self.search.set_search_string(d.search_string()) self.search.set_search_string(d.search_string())

View File

@ -472,8 +472,12 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
if path != self.current_page: if path != self.current_page:
self.pending_anchor = frag self.pending_anchor = frag
self.load_path(path) self.load_path(path)
elif frag: else:
if frag:
self.view.scroll_to(frag) self.view.scroll_to(frag)
else:
# Scroll to top
self.view.scroll_to('#')
else: else:
open_url(url) open_url(url)

View File

@ -245,6 +245,9 @@ class BrowseServer(object):
ans = ans.replace('{sort_select_label}', xml(_('Sort by')+':')) ans = ans.replace('{sort_select_label}', xml(_('Sort by')+':'))
ans = ans.replace('{sort_cookie_name}', scn) ans = ans.replace('{sort_cookie_name}', scn)
ans = ans.replace('{prefix}', self.opts.url_prefix) ans = ans.replace('{prefix}', self.opts.url_prefix)
ans = ans.replace('{library}', _('library'))
ans = ans.replace('{home}', _('home'))
ans = ans.replace('{Search}', _('Search'))
opts = ['<option %svalue="%s">%s</option>' % ( opts = ['<option %svalue="%s">%s</option>' % (
'selected="selected" ' if k==sort else '', 'selected="selected" ' if k==sort else '',
xml(k), xml(n), ) for k, n in xml(k), xml(n), ) for k, n in

View File

@ -377,7 +377,7 @@ They are XPath expressions that match tags in the intermediate XHTML produced by
how to construct XPath expressions. Next to each option is a button that launches a wizard to help with the creation how to construct XPath expressions. Next to each option is a button that launches a wizard to help with the creation
of basic XPath expressions. The following simple example illustrates how to use these options. of basic XPath expressions. The following simple example illustrates how to use these options.
Suppose you have an input document taht results in XHTML that look like this: Suppose you have an input document that results in XHTML that look like this:
.. code-block:: html .. code-block:: html
@ -418,6 +418,25 @@ This will result in an automatically generated two level Table of Contents that
Not all output formats support a multi level Table of Contents. You should first try with EPUB Output. If that Not all output formats support a multi level Table of Contents. You should first try with EPUB Output. If that
works, then try your format of choice. works, then try your format of choice.
Using images as chapter titles when converting HTML input documents
---------------------------------------------------------------------
Suppose you want to use an image as your chapter title, but still want |app| to be able to automatically generate a Table of Contents for you from the chapter titles.
Use the following HTML markup to achieve this
.. code-block:: html
<html>
<body>
<h2>Chapter 1</h2>
<p>chapter 1 text...</p>
<h2 title="Chapter 2"><img src="chapter2.jpg" /></h2>
<p>chapter 2 text...</p>
</body>
</html>
Set the :guilabel:`Level 1 TOC` setting to ``//h:h2``. Then, for chapter two, |app| will take the title from the value of the ``title`` attribute on the ``<h2>`` tag, since the tag has no text.
How options are set/saved for Conversion How options are set/saved for Conversion
------------------------------------------- -------------------------------------------

View File

@ -380,6 +380,8 @@ Calibre has several keyboard shortcuts to save you time and mouse movement. Thes
- Show books in the same series as current book - Show books in the same series as current book
* - :kbd:`/, Ctrl+F` * - :kbd:`/, Ctrl+F`
- Focus the search bar - Focus the search bar
* - :kbd:`Shift+Ctrl+F`
- Open the advanced search dialog
* - :kbd:`Ctrl+D` * - :kbd:`Ctrl+D`
- Download metadata and shortcuts - Download metadata and shortcuts
* - :kbd:`Ctrl+R` * - :kbd:`Ctrl+R`

View File

@ -5,8 +5,8 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: calibre 0.7.27\n" "Project-Id-Version: calibre 0.7.27\n"
"POT-Creation-Date: 2010-11-05 15:17+MDT\n" "POT-Creation-Date: 2010-11-06 09:35+MDT\n"
"PO-Revision-Date: 2010-11-05 15:17+MDT\n" "PO-Revision-Date: 2010-11-06 09:35+MDT\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"
@ -1932,7 +1932,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:313 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:313
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1127 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1127
#: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:160 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:160
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:620 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:623
msgid "Tags" msgid "Tags"
msgstr "" msgstr ""
@ -2299,7 +2299,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/transforms/jacket.py:159 #: /home/kovid/work/calibre/src/calibre/ebooks/oeb/transforms/jacket.py:159
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:71 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:71
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:618 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:621
msgid "Rating" msgid "Rating"
msgstr "" msgstr ""
@ -3570,7 +3570,7 @@ msgid "Click the show details button to see which ones."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/actions/show_book_details.py:16 #: /home/kovid/work/calibre/src/calibre/gui2/actions/show_book_details.py:16
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:625 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:628
msgid "Show book details" msgid "Show book details"
msgstr "" msgstr ""
@ -3878,7 +3878,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:25 #: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:25
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:49 #: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:49
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:58 #: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:58
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:402 #: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:403
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:119 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:119
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:120 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:120
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:121 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:121
@ -3925,7 +3925,7 @@ msgstr ""
msgid "None" msgid "None"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:401 #: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:402
msgid "Double-click to open Book Details window" msgid "Double-click to open Book Details window"
msgstr "" msgstr ""
@ -7601,7 +7601,7 @@ msgid "Successfully downloaded metadata for %d out of %d books"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/metadata.py:287 #: /home/kovid/work/calibre/src/calibre/gui2/metadata.py:287
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:624 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:627
msgid "Details" msgid "Details"
msgstr "" msgstr ""
@ -8581,6 +8581,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:97 #: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:97
#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:270 #: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:270
#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:574 #: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:574
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:250
msgid "Search" msgid "Search"
msgstr "" msgstr ""
@ -10477,7 +10478,7 @@ msgid "Password to access your calibre library. Username is "
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:51 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:51
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:402 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:405
msgid "Loading, please wait" msgid "Loading, please wait"
msgstr "" msgstr ""
@ -10522,70 +10523,78 @@ msgstr ""
msgid "Sort by" msgid "Sort by"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:307 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:248
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:513 msgid "library"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:249
msgid "home"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:310
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:516
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:569 #: /home/kovid/work/calibre/src/calibre/library/server/opds.py:569
msgid "Newest" msgid "Newest"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:308 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:311
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:514 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:517
msgid "All books" msgid "All books"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:341 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:344
msgid "Browse books by" msgid "Browse books by"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:346 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:349
msgid "Choose a category to browse by:" msgid "Choose a category to browse by:"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:422 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:425
msgid "Browsing by" msgid "Browsing by"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:423 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:426
msgid "Up" msgid "Up"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:544 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:547
msgid "in" msgid "in"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:547 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:550
msgid "Books in" msgid "Books in"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:599 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:602
msgid "Other formats" msgid "Other formats"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:606 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:609
msgid "Read %s in the %s format" msgid "Read %s in the %s format"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:611 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:614
msgid "Get" msgid "Get"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:626 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:629
msgid "Permalink" msgid "Permalink"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:627 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:630
msgid "A permanent link to this book" msgid "A permanent link to this book"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:638 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:641
msgid "This book has been deleted" msgid "This book has been deleted"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:722 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:725
msgid "in search" msgid "in search"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:724 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:727
msgid "Matching books" msgid "Matching books"
msgstr "" msgstr ""