mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Pull from trunk
This commit is contained in:
commit
d871e221e3
@ -4,6 +4,31 @@
|
||||
# for important features/bug fixes.
|
||||
# Also, each release can have new and improved recipes.
|
||||
|
||||
- version: 0.7.4
|
||||
date: 2010-06-19
|
||||
|
||||
bug fixes:
|
||||
- title: "Fix regression in 0.7.3 that broke creating custom columns of rating or text types"
|
||||
|
||||
- title: "Fix cover browser breaking if you click on a book in the book list while cover browser is animated"
|
||||
|
||||
- title: "Fix a bug that could be triggered with the new book details pane if a book has a zero size cover"
|
||||
tickets: [5889]
|
||||
|
||||
- title: "SONY driver: Fix bug preventing the editing of collections in the device view"
|
||||
|
||||
new recipes:
|
||||
- title: Auto Prove
|
||||
author: Gabriele Marini
|
||||
|
||||
- title: Forbes India, Maximum PC, Today Online
|
||||
author: rty
|
||||
|
||||
improved recipes:
|
||||
- WSJ
|
||||
- Psychology Today
|
||||
|
||||
|
||||
- version: 0.7.3
|
||||
date: 2010-06-18
|
||||
|
||||
|
90
resources/recipes/auto_prove.recipe
Normal file
90
resources/recipes/auto_prove.recipe
Normal file
@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env python
|
||||
__license__ = 'GPL v3'
|
||||
__author__ = 'GabrieleMarini, based on Darko Miletic'
|
||||
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>, Gabriele Marini'
|
||||
__version__ = 'v1.02 Marini Gabriele '
|
||||
__date__ = '10, January 2010'
|
||||
__description__ = 'Italian daily newspaper'
|
||||
|
||||
'''
|
||||
http://www.corrieredellosport.it/
|
||||
'''
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class AutoPR(BasicNewsRecipe):
|
||||
__author__ = 'Gabriele Marini'
|
||||
description = 'Auto and Formula 1'
|
||||
|
||||
cover_url = 'http://www.auto.it/res/imgs/logo_Auto.png'
|
||||
|
||||
|
||||
title = u'Auto Prove'
|
||||
publisher = 'CONTE Editore'
|
||||
category = 'Sport'
|
||||
|
||||
language = 'it'
|
||||
timefmt = '[%a, %d %b, %Y]'
|
||||
|
||||
oldest_article = 60
|
||||
max_articles_per_feed = 20
|
||||
use_embedded_content = False
|
||||
recursion = 100
|
||||
|
||||
remove_javascript = True
|
||||
no_stylesheets = True
|
||||
|
||||
#html2lrf_options = [
|
||||
# '--comment', description
|
||||
# , '--category', category
|
||||
# , '--publisher', publisher
|
||||
# , '--ignore-tables'
|
||||
# ]
|
||||
|
||||
#html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
|
||||
|
||||
keep_only_tags = [
|
||||
dict(name='h2', attrs={'class':['tit_Article y_Txt']}),
|
||||
dict(name='h2', attrs={'class':['tit_Article']}),
|
||||
dict(name='div', attrs={'class':['box_Img newsdet_new ']}),
|
||||
dict(name='div', attrs={'class':['box_Img newsdet_as ']}),
|
||||
dict(name='table', attrs={'class':['table_A']}),
|
||||
dict(name='div', attrs={'class':['txt_Article txtBox_cms']}),
|
||||
dict(name='testoscheda')]
|
||||
|
||||
def parse_index(self):
|
||||
feeds = []
|
||||
for title, url in [
|
||||
("Prove su Strada" , "http://www.auto.it/rss/prove+6.xml")
|
||||
]:
|
||||
soup = self.index_to_soup(url)
|
||||
soup = soup.find('channel')
|
||||
print soup
|
||||
|
||||
for article in soup.findAllNext('item'):
|
||||
title = self.tag_to_string(article.title)
|
||||
date = self.tag_to_string(article.pubDate)
|
||||
description = self.tag_to_string(article.description)
|
||||
link = self.tag_to_string(article.guid)
|
||||
# print article
|
||||
articles = self.create_links_append(link, date, description)
|
||||
if articles:
|
||||
feeds.append((title, articles))
|
||||
return feeds
|
||||
|
||||
def create_links_append(self, link, date, description):
|
||||
current_articles = []
|
||||
|
||||
current_articles.append({'title': 'Generale', 'url': link,'description':description, 'date':date}),
|
||||
current_articles.append({'title': 'Design', 'url': link.replace('scheda','design'),'description':'scheda', 'date':''}),
|
||||
current_articles.append({'title': 'Interni', 'url': link.replace('scheda','interni'),'description':'Interni', 'date':''}),
|
||||
current_articles.append({'title': 'Tecnica', 'url': link.replace('scheda','tecnica'),'description':'Tecnica', 'date':''}),
|
||||
current_articles.append({'title': 'Su Strada', 'url': link.replace('scheda','su_strada'),'description':'Su Strada', 'date':''}),
|
||||
current_articles.append({'title': 'Pagella', 'url': link.replace('scheda','pagella'),'description':'Pagella', 'date':''}),
|
||||
current_articles.append({'title': 'Rilevamenti', 'url': link.replace('scheda','telemetria'),'description':'Rilevamenti', 'date':''})
|
||||
|
||||
return current_articles
|
||||
|
||||
|
||||
|
||||
|
||||
|
55
resources/recipes/forbes_india.recipe
Normal file
55
resources/recipes/forbes_india.recipe
Normal file
@ -0,0 +1,55 @@
|
||||
from calibre.ptempfile import PersistentTemporaryFile
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class AdvancedUserRecipe1276934715(BasicNewsRecipe):
|
||||
title = u'Forbes India'
|
||||
__author__ = 'rty'
|
||||
description = 'India Edition Forbes'
|
||||
publisher = 'Forbes India'
|
||||
category = 'Business News, Economy, India'
|
||||
oldest_article = 7
|
||||
max_articles_per_feed = 100
|
||||
remove_javascript = True
|
||||
use_embedded_content = False
|
||||
no_stylesheets = True
|
||||
language = 'en_IN'
|
||||
temp_files = []
|
||||
articles_are_obfuscated = True
|
||||
conversion_options = {'linearize_tables':True}
|
||||
feeds = [
|
||||
(u'Contents', u'http://business.in.com/rssfeed/rss_all.xml'),
|
||||
]
|
||||
extra_css = '''
|
||||
.t-10-gy-l{font-style: italic; font-size: small}
|
||||
.t-30-b-d{font-weight: bold; font-size: xx-large}
|
||||
.t-16-gy-l{font-weight: bold; font-size: x-large; font-syle: italic}
|
||||
.storycontent{font-size: 4px;font-family: Times New Roman;}
|
||||
'''
|
||||
|
||||
remove_tags_before = dict(name='div', attrs={'class':'pdl10 pdr15'})
|
||||
|
||||
|
||||
def get_obfuscated_article(self, url):
|
||||
br = self.get_browser()
|
||||
br.open(url)
|
||||
response = br.follow_link(url_regex = r'/printcontent/[0-9]+', nr = 0)
|
||||
html = response.read()
|
||||
self.temp_files.append(PersistentTemporaryFile('_fa.html'))
|
||||
self.temp_files[-1].write(html)
|
||||
self.temp_files[-1].close()
|
||||
return self.temp_files[-1].name
|
||||
|
||||
def get_cover_url(self):
|
||||
index = 'http://business.in.com/magazine/'
|
||||
soup = self.index_to_soup(index)
|
||||
for image in soup.findAll('a',{ "class" : "lbOn a-9-b-d" }):
|
||||
return image['href']
|
||||
#return image['href'] + '.jpg'
|
||||
return None
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for item in soup.findAll(style=True):
|
||||
del item['style']
|
||||
for item in soup.findAll(width=True):
|
||||
del item['width']
|
||||
return soup
|
43
resources/recipes/maximum_pc.recipe
Normal file
43
resources/recipes/maximum_pc.recipe
Normal file
@ -0,0 +1,43 @@
|
||||
from calibre.ptempfile import PersistentTemporaryFile
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class AdvancedUserRecipe1276930924(BasicNewsRecipe):
|
||||
title = u'Maximum PC'
|
||||
__author__ = 'rty'
|
||||
description = 'Maximum PC'
|
||||
publisher = 'http://www.maximumpc.com'
|
||||
category = 'news, computer, technology'
|
||||
language = 'en'
|
||||
oldest_article = 30
|
||||
max_articles_per_feed = 100
|
||||
remove_javascript = True
|
||||
use_embedded_content = False
|
||||
no_stylesheets = True
|
||||
language = 'en'
|
||||
temp_files = []
|
||||
articles_are_obfuscated = True
|
||||
feeds = [(u'News', u'http://www.maximumpc.com/articles/4/feed'),
|
||||
(u'Reviews', u'http://www.maximumpc.com/articles/40/feed'),
|
||||
(u'Editors Blog', u'http://www.maximumpc.com/articles/6/feed'),
|
||||
(u'How-to', u'http://www.maximumpc.com/articles/32/feed'),
|
||||
(u'Features', u'http://www.maximumpc.com/articles/31/feed'),
|
||||
(u'From the Magazine', u'http://www.maximumpc.com/articles/72/feed')
|
||||
]
|
||||
keep_only_tags = [
|
||||
dict(name='div', attrs={'class':['print-title','article_body']}),
|
||||
]
|
||||
remove_tags = [
|
||||
dict(name='div', attrs={'class':'comments-tags-actions'}),
|
||||
]
|
||||
remove_tags_before = dict(name='div', attrs={'class':'print-title'})
|
||||
remove_tags_after = dict(name='div', attrs={'class':'meta-content'})
|
||||
|
||||
def get_obfuscated_article(self, url):
|
||||
br = self.get_browser()
|
||||
br.open(url)
|
||||
response = br.follow_link(url_regex = r'/print/[0-9]+', nr = 0)
|
||||
html = response.read()
|
||||
self.temp_files.append(PersistentTemporaryFile('_fa.html'))
|
||||
self.temp_files[-1].write(html)
|
||||
self.temp_files[-1].close()
|
||||
return self.temp_files[-1].name
|
@ -1,39 +1,44 @@
|
||||
|
||||
from calibre.ptempfile import PersistentTemporaryFile
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
from calibre.ebooks.BeautifulSoup import BeautifulSoup
|
||||
|
||||
class PsychologyToday(BasicNewsRecipe):
|
||||
class AdvancedUserRecipe1275708473(BasicNewsRecipe):
|
||||
title = u'Psychology Today'
|
||||
language = 'en'
|
||||
__author__ = 'Krittika Goyal'
|
||||
oldest_article = 1 #days
|
||||
max_articles_per_feed = 25
|
||||
#encoding = 'latin1'
|
||||
|
||||
remove_stylesheets = True
|
||||
#remove_tags_before = dict(name='h1', attrs={'class':'heading'})
|
||||
#remove_tags_after = dict(name='td', attrs={'class':'newptool1'})
|
||||
_author__ = 'rty'
|
||||
publisher = u'www.psychologytoday.com'
|
||||
category = u'Psychology'
|
||||
max_articles_per_feed = 100
|
||||
remove_javascript = True
|
||||
use_embedded_content = False
|
||||
no_stylesheets = True
|
||||
language = 'en'
|
||||
temp_files = []
|
||||
articles_are_obfuscated = True
|
||||
remove_tags = [
|
||||
dict(name='iframe'),
|
||||
dict(name='div', attrs={'class':['pt-box-title', 'pt-box-content', 'blog-entry-footer', 'item-list', 'article-sub-meta']}),
|
||||
dict(name='div', attrs={'id':['block-td_search_160', 'block-cam_search_160']}),
|
||||
#dict(name='ul', attrs={'class':'article-tools'}),
|
||||
#dict(name='ul', attrs={'class':'articleTools'}),
|
||||
]
|
||||
dict(name='div', attrs={'class':['print-source_url','field-items','print-footer']}),
|
||||
dict(name='span', attrs={'class':'print-footnote'}),
|
||||
]
|
||||
remove_tags_before = dict(name='h1', attrs={'class':'print-title'})
|
||||
remove_tags_after = dict(name='div', attrs={'class':['field-items','print-footer']})
|
||||
|
||||
feeds = [
|
||||
('PSY TODAY',
|
||||
'http://www.psychologytoday.com/articles/index.rss'),
|
||||
]
|
||||
feeds = [(u'Contents', u'http://www.psychologytoday.com/articles/index.rss')]
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
story = soup.find(name='div', attrs={'id':'contentColumn'})
|
||||
#td = heading.findParent(name='td')
|
||||
#td.extract()
|
||||
soup = BeautifulSoup('<html><head><title>t</title></head><body></body></html>')
|
||||
body = soup.find(name='body')
|
||||
body.insert(0, story)
|
||||
for x in soup.findAll(name='p', text=lambda x:x and '-->' in x):
|
||||
p = x.findParent('p')
|
||||
if p is not None:
|
||||
p.extract()
|
||||
return soup
|
||||
def get_article_url(self, article):
|
||||
return article.get('link', None)
|
||||
|
||||
def get_obfuscated_article(self, url):
|
||||
br = self.get_browser()
|
||||
br.open(url)
|
||||
response = br.follow_link(url_regex = r'/print/[0-9]+', nr = 0)
|
||||
html = response.read()
|
||||
self.temp_files.append(PersistentTemporaryFile('_fa.html'))
|
||||
self.temp_files[-1].write(html)
|
||||
self.temp_files[-1].close()
|
||||
return self.temp_files[-1].name
|
||||
|
||||
def get_cover_url(self):
|
||||
index = 'http://www.psychologytoday.com/magazine/'
|
||||
soup = self.index_to_soup(index)
|
||||
for image in soup.findAll('img',{ "class" : "imagefield imagefield-field_magazine_cover" }):
|
||||
return image['src'] + '.jpg'
|
||||
return None
|
||||
|
59
resources/recipes/today_online.recipe
Normal file
59
resources/recipes/today_online.recipe
Normal file
@ -0,0 +1,59 @@
|
||||
from calibre.ptempfile import PersistentTemporaryFile
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class AdvancedUserRecipe1276486274(BasicNewsRecipe):
|
||||
title = u'Today Online - Singapore'
|
||||
publisher = 'MediaCorp Press Ltd - Singapore'
|
||||
__author__ = 'rty'
|
||||
category = 'news, Singapore'
|
||||
oldest_article = 7
|
||||
max_articles_per_feed = 100
|
||||
remove_javascript = True
|
||||
use_embedded_content = False
|
||||
no_stylesheets = True
|
||||
language = 'en_SG'
|
||||
temp_files = []
|
||||
articles_are_obfuscated = True
|
||||
masthead_url = 'http://www.todayonline.com/App_Themes/Default/images/icons/TodayOnlineLogo.gif'
|
||||
conversion_options = {'linearize_tables':True}
|
||||
extra_css = '''
|
||||
.author{font-style: italic; font-size: small}
|
||||
.date{font-style: italic; font-size: small}
|
||||
.Headline{font-weight: bold; font-size: xx-large}
|
||||
.headerStrap{font-weight: bold; font-size: x-large; font-syle: italic}
|
||||
.bodyText{font-size: 4px;font-family: Times New Roman;}
|
||||
'''
|
||||
keep_only_tags = [
|
||||
dict(name='div', attrs={'id':['fullPrintBodyHolder']})
|
||||
]
|
||||
remove_tags_after = [ dict(name='div', attrs={'class':'button'})]
|
||||
|
||||
|
||||
remove_tags = [
|
||||
dict(name='div', attrs={'class':['url','button']})
|
||||
]
|
||||
feeds = [
|
||||
(u'Singapore', u'http://www.todayonline.com/RSS/Singapore'),
|
||||
(u'Hot News', u'http://www.todayonline.com/RSS/Hotnews'),
|
||||
(u'Today Online', u'http://www.todayonline.com/RSS/Todayonline'),
|
||||
(u'Voices', u'http://www.todayonline.com/RSS/Voices'),
|
||||
(u'Commentary', u'http://www.todayonline.com/RSS/Commentary'),
|
||||
(u'World', u'http://www.todayonline.com/RSS/World'),
|
||||
(u'Business', u'http://www.todayonline.com/RSS/Business'),
|
||||
(u'Column', u'http://www.todayonline.com/RSS/Columns'),
|
||||
]
|
||||
|
||||
def get_obfuscated_article(self, url):
|
||||
br = self.get_browser()
|
||||
br.open(url)
|
||||
response = br.follow_link(url_regex = r'/Print/', nr = 0)
|
||||
html = response.read()
|
||||
self.temp_files.append(PersistentTemporaryFile('_fa.html'))
|
||||
self.temp_files[-1].write(html)
|
||||
self.temp_files[-1].close()
|
||||
return self.temp_files[-1].name
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for item in soup.findAll(style=True):
|
||||
del item['style']
|
||||
return soup
|
@ -4,13 +4,14 @@ __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
import copy
|
||||
|
||||
# http://online.wsj.com/page/us_in_todays_paper.html
|
||||
|
||||
class WallStreetJournal(BasicNewsRecipe):
|
||||
|
||||
title = 'The Wall Street Journal (US)'
|
||||
__author__ = 'Kovid Goyal and Sujata Raman'
|
||||
title = 'The Wall Street Journal'
|
||||
__author__ = 'Kovid Goyal, Sujata Raman, and Joshua Oster-Morris'
|
||||
description = 'News and current affairs'
|
||||
needs_subscription = True
|
||||
language = 'en'
|
||||
@ -67,6 +68,16 @@ class WallStreetJournal(BasicNewsRecipe):
|
||||
def wsj_get_index(self):
|
||||
return self.index_to_soup('http://online.wsj.com/itp')
|
||||
|
||||
def wsj_add_feed(self,feeds,title,url):
|
||||
self.log('Found section:', title)
|
||||
if url.endswith('whatsnews'):
|
||||
articles = self.wsj_find_wn_articles(url)
|
||||
else:
|
||||
articles = self.wsj_find_articles(url)
|
||||
if articles:
|
||||
feeds.append((title, articles))
|
||||
return feeds
|
||||
|
||||
def parse_index(self):
|
||||
soup = self.wsj_get_index()
|
||||
|
||||
@ -82,25 +93,62 @@ class WallStreetJournal(BasicNewsRecipe):
|
||||
div = soup.find('div', attrs={'class':'itpHeader'})
|
||||
div = div.find('ul', attrs={'class':'tab'})
|
||||
for a in div.findAll('a', href=lambda x: x and '/itp/' in x):
|
||||
title = self.tag_to_string(a)
|
||||
url = 'http://online.wsj.com' + a['href']
|
||||
self.log('Found section:', title)
|
||||
articles = self.wsj_find_articles(url)
|
||||
if articles:
|
||||
feeds.append((title, articles))
|
||||
|
||||
pageone = a['href'].endswith('pageone')
|
||||
if pageone:
|
||||
title = 'Front Section'
|
||||
url = 'http://online.wsj.com' + a['href']
|
||||
feeds = self.wsj_add_feed(feeds,title,url)
|
||||
title = 'What''s News'
|
||||
url = url.replace('pageone','whatsnews')
|
||||
feeds = self.wsj_add_feed(feeds,title,url)
|
||||
else:
|
||||
title = self.tag_to_string(a)
|
||||
url = 'http://online.wsj.com' + a['href']
|
||||
feeds = self.wsj_add_feed(feeds,title,url)
|
||||
return feeds
|
||||
|
||||
def wsj_find_wn_articles(self, url):
|
||||
soup = self.index_to_soup(url)
|
||||
articles = []
|
||||
|
||||
whats_news = soup.find('div', attrs={'class':lambda x: x and 'whatsNews-simple' in x})
|
||||
if whats_news is not None:
|
||||
for a in whats_news.findAll('a', href=lambda x: x and '/article/' in x):
|
||||
container = a.findParent(['p'])
|
||||
meta = a.find(attrs={'class':'meta_sectionName'})
|
||||
if meta is not None:
|
||||
meta.extract()
|
||||
title = self.tag_to_string(a).strip()
|
||||
url = a['href']
|
||||
desc = ''
|
||||
if container is not None:
|
||||
desc = self.tag_to_string(container)
|
||||
|
||||
articles.append({'title':title, 'url':url,
|
||||
'description':desc, 'date':''})
|
||||
|
||||
self.log('\tFound WN article:', title)
|
||||
|
||||
return articles
|
||||
|
||||
def wsj_find_articles(self, url):
|
||||
soup = self.index_to_soup(url)
|
||||
|
||||
whats_news = soup.find('div', attrs={'class':lambda x: x and
|
||||
'whatsNews-simple' in x})
|
||||
whats_news = soup.find('div', attrs={'class':lambda x: x and 'whatsNews-simple' in x})
|
||||
if whats_news is not None:
|
||||
whats_news.extract()
|
||||
whats_news.extract()
|
||||
|
||||
articles = []
|
||||
|
||||
flavorarea = soup.find('div', attrs={'class':lambda x: x and 'ahed' in x})
|
||||
if flavorarea is not None:
|
||||
flavorstory = flavorarea.find('a', href=lambda x: x and x.startswith('/article'))
|
||||
if flavorstory is not None:
|
||||
flavorstory['class'] = 'mjLinkItem'
|
||||
metapage = soup.find('span', attrs={'class':lambda x: x and 'meta_sectionName' in x})
|
||||
if metapage is not None:
|
||||
flavorstory.append( copy.copy(metapage) ) #metapage should always be A1 because that should be first on the page
|
||||
|
||||
for a in soup.findAll('a', attrs={'class':'mjLinkItem'}, href=True):
|
||||
container = a.findParent(['li', 'div'])
|
||||
meta = a.find(attrs={'class':'meta_sectionName'})
|
||||
@ -118,26 +166,9 @@ class WallStreetJournal(BasicNewsRecipe):
|
||||
|
||||
self.log('\tFound article:', title)
|
||||
|
||||
'''
|
||||
# Find related articles
|
||||
a.extract()
|
||||
for a in container.findAll('a', href=lambda x: x and '/article/'
|
||||
in x and 'articleTabs' not in x):
|
||||
url = a['href']
|
||||
if not url.startswith('http:'):
|
||||
url = 'http://online.wsj.com'+url
|
||||
title = self.tag_to_string(a).strip()
|
||||
if not title or title.startswith('['): continue
|
||||
if title:
|
||||
articles.append({'title':self.tag_to_string(a),
|
||||
'url':url, 'description':'', 'date':''})
|
||||
self.log('\t\tFound related:', title)
|
||||
'''
|
||||
|
||||
return articles
|
||||
|
||||
|
||||
def cleanup(self):
|
||||
self.browser.open('http://online.wsj.com/logout?url=http://online.wsj.com')
|
||||
|
||||
|
||||
|
@ -2,7 +2,7 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
__appname__ = 'calibre'
|
||||
__version__ = '0.7.3'
|
||||
__version__ = '0.7.4'
|
||||
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
||||
|
||||
import re
|
||||
|
@ -6,8 +6,7 @@ __docformat__ = 'restructuredtext en'
|
||||
|
||||
|
||||
import cStringIO, ctypes, datetime, os, re, shutil, subprocess, sys, tempfile, time
|
||||
|
||||
from calibre.constants import DEBUG
|
||||
from calibre.constants import __appname__, __version__, DEBUG
|
||||
from calibre import fit_image
|
||||
from calibre.constants import isosx, iswindows
|
||||
from calibre.devices.errors import UserFeedback
|
||||
@ -79,7 +78,7 @@ class ITUNES(DevicePlugin):
|
||||
supported_platforms = ['osx','windows']
|
||||
author = 'GRiker'
|
||||
#: The version of this plugin as a 3-tuple (major, minor, revision)
|
||||
version = (0,6,0)
|
||||
version = (0,7,0)
|
||||
|
||||
OPEN_FEEDBACK_MESSAGE = _(
|
||||
'Apple device detected, launching iTunes, please wait ...')
|
||||
@ -294,7 +293,7 @@ class ITUNES(DevicePlugin):
|
||||
'author':[book.artist()],
|
||||
'lib_book':library_books[this_book.path] if this_book.path in library_books else None,
|
||||
'dev_book':book,
|
||||
'uuid': book.album()
|
||||
'uuid': book.composer()
|
||||
}
|
||||
|
||||
if self.report_progress is not None:
|
||||
@ -330,7 +329,7 @@ class ITUNES(DevicePlugin):
|
||||
'title':book.Name,
|
||||
'author':book.Artist,
|
||||
'lib_book':library_books[this_book.path] if this_book.path in library_books else None,
|
||||
'uuid': book.Album
|
||||
'uuid': book.Composer
|
||||
}
|
||||
|
||||
if self.report_progress is not None:
|
||||
@ -1426,10 +1425,10 @@ class ITUNES(DevicePlugin):
|
||||
attempts = 9
|
||||
while attempts:
|
||||
# Try by uuid - only one hit
|
||||
hits = dev_books.Search(search['uuid'],self.SearchField.index('Albums'))
|
||||
hits = dev_books.Search(search['uuid'],self.SearchField.index('All'))
|
||||
if hits:
|
||||
hit = hits[0]
|
||||
self.log.info(" found '%s' by %s (%s)" % (hit.Name, hit.Artist, hit.Album))
|
||||
self.log.info(" found '%s' by %s (%s)" % (hit.Name, hit.Artist, hit.Composer))
|
||||
return hit
|
||||
|
||||
# Try by author - there could be multiple hits
|
||||
@ -1438,7 +1437,7 @@ class ITUNES(DevicePlugin):
|
||||
for hit in hits:
|
||||
if hit.Name == search['title']:
|
||||
if DEBUG:
|
||||
self.log.info(" found '%s' by %s (%s)" % (hit.Name, hit.Artist, hit.Album))
|
||||
self.log.info(" found '%s' by %s (%s)" % (hit.Name, hit.Artist, hit.Composer))
|
||||
return hit
|
||||
|
||||
attempts -= 1
|
||||
@ -1493,11 +1492,11 @@ class ITUNES(DevicePlugin):
|
||||
if 'uuid' in search:
|
||||
if DEBUG:
|
||||
self.log.info(" searching by uuid '%s' ..." % search['uuid'])
|
||||
hits = lib_books.Search(search['uuid'],self.SearchField.index('Albums'))
|
||||
hits = lib_books.Search(search['uuid'],self.SearchField.index('All'))
|
||||
if hits:
|
||||
hit = hits[0]
|
||||
if DEBUG:
|
||||
self.log.info(" found '%s' by %s (%s)" % (hit.Name, hit.Artist, hit.Album))
|
||||
self.log.info(" found '%s' by %s (%s)" % (hit.Name, hit.Artist, hit.Composer))
|
||||
return hit
|
||||
|
||||
if DEBUG:
|
||||
@ -1507,7 +1506,7 @@ class ITUNES(DevicePlugin):
|
||||
for hit in hits:
|
||||
if hit.Name == search['title']:
|
||||
if DEBUG:
|
||||
self.log.info(" found '%s' by %s (%s)" % (hit.Name, hit.Artist, hit.Album))
|
||||
self.log.info(" found '%s' by %s (%s)" % (hit.Name, hit.Artist, hit.Composer))
|
||||
return hit
|
||||
|
||||
attempts -= 1
|
||||
@ -1558,6 +1557,10 @@ class ITUNES(DevicePlugin):
|
||||
return thumb.getvalue()
|
||||
except:
|
||||
self.log.error(" error generating thumb for '%s'" % book.name())
|
||||
try:
|
||||
zfw.close()
|
||||
except:
|
||||
pass
|
||||
return None
|
||||
|
||||
elif iswindows:
|
||||
@ -1587,6 +1590,10 @@ class ITUNES(DevicePlugin):
|
||||
return thumb.getvalue()
|
||||
except:
|
||||
self.log.error(" error generating thumb for '%s'" % book.Name)
|
||||
try:
|
||||
zfw.close()
|
||||
except:
|
||||
pass
|
||||
return None
|
||||
|
||||
def _get_device_book_size(self, file, compressed_size):
|
||||
@ -1925,6 +1932,7 @@ class ITUNES(DevicePlugin):
|
||||
self.log.error(" could not confirm valid iTunes.media_dir from %s" % 'com.apple.itunes')
|
||||
self.log.error(" media_dir: %s" % media_dir)
|
||||
if DEBUG:
|
||||
self.log.info(" %s %s" % (__appname__, __version__))
|
||||
self.log.info(" [OSX %s - %s (%s), driver version %d.%d.%d]" %
|
||||
(self.iTunes.name(), self.iTunes.version(), self.initial_status,
|
||||
self.version[0],self.version[1],self.version[2]))
|
||||
@ -1954,6 +1962,7 @@ class ITUNES(DevicePlugin):
|
||||
self.log.error(" '%s' not found" % media_dir)
|
||||
|
||||
if DEBUG:
|
||||
self.log.info(" %s %s" % (__appname__, __version__))
|
||||
self.log.info(" [Windows %s - %s (%s), driver version %d.%d.%d]" %
|
||||
(self.iTunes.Windows[0].name, self.iTunes.Version, self.initial_status,
|
||||
self.version[0],self.version[1],self.version[2]))
|
||||
@ -2041,7 +2050,7 @@ class ITUNES(DevicePlugin):
|
||||
|
||||
elif iswindows:
|
||||
dev_pl = self._get_device_books_playlist()
|
||||
hits = dev_pl.Search(cached_book['uuid'],self.SearchField.index('Albums'))
|
||||
hits = dev_pl.Search(cached_book['uuid'],self.SearchField.index('All'))
|
||||
if hits:
|
||||
hit = hits[0]
|
||||
if False:
|
||||
@ -2095,7 +2104,7 @@ class ITUNES(DevicePlugin):
|
||||
self.iTunes.delete(cached_book['lib_book'])
|
||||
except:
|
||||
if DEBUG:
|
||||
self.log.info(" '%s' not found in iTunes" % cached_book['title'])
|
||||
self.log.info(" unable to remove '%s' from iTunes" % cached_book['title'])
|
||||
|
||||
elif iswindows:
|
||||
'''
|
||||
@ -2107,13 +2116,14 @@ class ITUNES(DevicePlugin):
|
||||
path = book.Location
|
||||
except:
|
||||
book = self._find_library_book(cached_book)
|
||||
path = book.Location
|
||||
|
||||
if book:
|
||||
storage_path = os.path.split(book.Location)
|
||||
if book.Location.startswith(self.iTunes_media):
|
||||
storage_path = os.path.split(path)
|
||||
if path.startswith(self.iTunes_media):
|
||||
if DEBUG:
|
||||
self.log.info(" removing '%s' at %s" %
|
||||
(cached_book['title'], book.Location))
|
||||
(cached_book['title'], path))
|
||||
try:
|
||||
os.remove(path)
|
||||
except:
|
||||
@ -2134,7 +2144,7 @@ class ITUNES(DevicePlugin):
|
||||
book.Delete()
|
||||
except:
|
||||
if DEBUG:
|
||||
self.log.info(" '%s' not found in iTunes" % cached_book['title'])
|
||||
self.log.info(" unable to remove '%s' from iTunes" % cached_book['title'])
|
||||
|
||||
def _update_epub_metadata(self, fpath, metadata):
|
||||
'''
|
||||
@ -2241,14 +2251,16 @@ class ITUNES(DevicePlugin):
|
||||
|
||||
if isosx:
|
||||
if lb_added:
|
||||
lb_added.album.set(metadata.uuid)
|
||||
lb_added.album.set(metadata.title)
|
||||
lb_added.composer.set(metadata.uuid)
|
||||
lb_added.description.set("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S')))
|
||||
lb_added.enabled.set(True)
|
||||
lb_added.sort_artist.set(metadata.author_sort.title())
|
||||
lb_added.sort_name.set(this_book.title_sorter)
|
||||
|
||||
if db_added:
|
||||
db_added.album.set(metadata.uuid)
|
||||
db_added.album.set(metadata.title)
|
||||
db_added.composer.set(metadata.uuid)
|
||||
db_added.description.set("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S')))
|
||||
db_added.enabled.set(True)
|
||||
db_added.sort_artist.set(metadata.author_sort.title())
|
||||
@ -2296,14 +2308,16 @@ class ITUNES(DevicePlugin):
|
||||
|
||||
elif iswindows:
|
||||
if lb_added:
|
||||
lb_added.Album = metadata.uuid
|
||||
lb_added.Album = metadata.title
|
||||
lb_added.Composer = metadata.uuid
|
||||
lb_added.Description = ("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S')))
|
||||
lb_added.Enabled = True
|
||||
lb_added.SortArtist = (metadata.author_sort.title())
|
||||
lb_added.SortName = (this_book.title_sorter)
|
||||
|
||||
if db_added:
|
||||
db_added.Album = metadata.uuid
|
||||
db_added.Album = metadata.title
|
||||
db_added.Composer = metadata.uuid
|
||||
db_added.Description = ("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S')))
|
||||
db_added.Enabled = True
|
||||
db_added.SortArtist = (metadata.author_sort.title())
|
||||
|
@ -84,7 +84,7 @@ class EPUBOutput(OutputFormatPlugin):
|
||||
|
||||
OptionRecommendation(name='no_svg_cover', recommended_value=False,
|
||||
help=_('Do not use SVG for the book cover. Use this option if '
|
||||
'your EPUB is going to be used ona device that does not '
|
||||
'your EPUB is going to be used on a device that does not '
|
||||
'support SVG, like the iPhone or the JetBook Lite. '
|
||||
'Without this option, such devices will display the cover '
|
||||
'as a blank page.')
|
||||
|
@ -93,10 +93,16 @@ class CoverView(QWidget): # {{{
|
||||
self._current_pixmap_size = val
|
||||
|
||||
def do_layout(self):
|
||||
if self.rect().width() == 0 or self.rect().height() == 0:
|
||||
return
|
||||
pixmap = self.pixmap
|
||||
pwidth, pheight = pixmap.width(), pixmap.height()
|
||||
self.pwidth, self.pheight = fit_image(pwidth, pheight,
|
||||
try:
|
||||
self.pwidth, self.pheight = fit_image(pwidth, pheight,
|
||||
self.rect().width(), self.rect().height())[1:]
|
||||
except:
|
||||
self.pwidth, self.pheight = self.rect().width()-1, \
|
||||
self.rect().height()-1
|
||||
self.current_pixmap_size = QSize(self.pwidth, self.pheight)
|
||||
self.animation.setEndValue(self.current_pixmap_size)
|
||||
|
||||
@ -120,7 +126,8 @@ class CoverView(QWidget): # {{{
|
||||
self.data = {'id':data.get('id', None)}
|
||||
if data.has_key('cover'):
|
||||
self.pixmap = QPixmap.fromImage(data.pop('cover'))
|
||||
if self.pixmap.isNull():
|
||||
if self.pixmap.isNull() or self.pixmap.width() < 5 or \
|
||||
self.pixmap.height() < 5:
|
||||
self.pixmap = self.default_pixmap
|
||||
else:
|
||||
self.pixmap = self.default_pixmap
|
||||
|
@ -205,8 +205,8 @@ class CoverFlowMixin(object):
|
||||
sm.select(index, sm.ClearAndSelect|sm.Rows)
|
||||
self.library_view.setCurrentIndex(index)
|
||||
except:
|
||||
pass
|
||||
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def sync_listview_to_cf(self, row):
|
||||
self.cf_last_updated_at = time.time()
|
||||
|
@ -919,8 +919,8 @@ class DeviceBooksModel(BooksModel): # {{{
|
||||
flags = QAbstractTableModel.flags(self, index)
|
||||
if index.isValid() and self.editable:
|
||||
cname = self.column_map[index.column()]
|
||||
if cname in ('title', 'authors') or (cname == 'collection' and \
|
||||
self.db.supports_collections()):
|
||||
if cname in ('title', 'authors') or \
|
||||
(cname == 'collections' and self.db.supports_collections()):
|
||||
flags |= Qt.ItemIsEditable
|
||||
return flags
|
||||
|
||||
|
@ -496,6 +496,7 @@ int PictureFlowPrivate::currentSlide() const
|
||||
|
||||
void PictureFlowPrivate::setCurrentSlide(int index)
|
||||
{
|
||||
animateTimer.stop();
|
||||
step = 0;
|
||||
centerIndex = qBound(index, 0, slideImages->count()-1);
|
||||
target = centerIndex;
|
||||
|
@ -467,7 +467,8 @@ class CustomColumns(object):
|
||||
books_ratings_link as bl,
|
||||
ratings as r
|
||||
WHERE {lt}.value={table}.id and bl.book={lt}.book and
|
||||
r.id = bl.rating and r.rating <> 0) avg_rating
|
||||
r.id = bl.rating and r.rating <> 0) avg_rating,
|
||||
value AS sort
|
||||
FROM {table};
|
||||
|
||||
CREATE VIEW tag_browser_filtered_{table} AS SELECT
|
||||
@ -481,7 +482,8 @@ class CustomColumns(object):
|
||||
ratings as r
|
||||
WHERE {lt}.value={table}.id AND bl.book={lt}.book AND
|
||||
r.id = bl.rating AND r.rating <> 0 AND
|
||||
books_list_filter(bl.book)) avg_rating
|
||||
books_list_filter(bl.book)) avg_rating,
|
||||
value AS sort
|
||||
FROM {table};
|
||||
|
||||
'''.format(lt=lt, table=table),
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -4,9 +4,9 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: calibre 0.7.3\n"
|
||||
"POT-Creation-Date: 2010-06-18 11:10+MDT\n"
|
||||
"PO-Revision-Date: 2010-06-18 11:10+MDT\n"
|
||||
"Project-Id-Version: calibre 0.7.4\n"
|
||||
"POT-Creation-Date: 2010-06-19 18:08+MDT\n"
|
||||
"PO-Revision-Date: 2010-06-19 18:08+MDT\n"
|
||||
"Last-Translator: Automatically generated\n"
|
||||
"Language-Team: LANGUAGE\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@ -422,55 +422,55 @@ msgstr ""
|
||||
msgid "Communicate with S60 phones."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:78
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:77
|
||||
msgid "Communicate with iBooks through iTunes."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:84
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:83
|
||||
msgid "Apple device detected, launching iTunes, please wait ..."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:227
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:230
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:226
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:229
|
||||
msgid "Updating device metadata listing..."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:301
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:338
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:842
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:876
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:300
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:337
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:841
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:875
|
||||
msgid "%d of %d"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:345
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:881
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:344
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:880
|
||||
msgid "finished"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:519
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:518
|
||||
msgid ""
|
||||
"Some books not found in iTunes database.\n"
|
||||
"Delete using the iBooks app.\n"
|
||||
"Click 'Show Details' for a list."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:742
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:741
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/usbms/deviceconfig.py:28
|
||||
msgid "settings for device drivers"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:744
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:743
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/usbms/deviceconfig.py:30
|
||||
msgid "Ordered list of formats the device will accept"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:813
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:812
|
||||
msgid ""
|
||||
"Some cover art could not be converted.\n"
|
||||
"Click 'Show Details' for a list."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2168
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2178
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/usbms/device.py:810
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/usbms/device.py:816
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/usbms/device.py:844
|
||||
@ -1269,7 +1269,7 @@ msgid "Normally, if the input file has no cover and you don't specify one, a def
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:86
|
||||
msgid "Do not use SVG for the book cover. Use this option if your EPUB is going to be used ona device that does not support SVG, like the iPhone or the JetBook Lite. Without this option, such devices will display the cover as a blank page."
|
||||
msgid "Do not use SVG for the book cover. Use this option if your EPUB is going to be used on a device that does not support SVG, like the iPhone or the JetBook Lite. Without this option, such devices will display the cover as a blank page."
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:94
|
||||
@ -1547,10 +1547,10 @@ msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:385
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:34
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:201
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:202
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:207
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:208
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:209
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:214
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:215
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:184
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:99
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:67
|
||||
@ -2886,7 +2886,7 @@ msgstr ""
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:22
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:44
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:53
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:302
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:309
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:114
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:115
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:116
|
||||
@ -2931,7 +2931,7 @@ msgstr ""
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:301
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:308
|
||||
msgid "Click to open Book Details window"
|
||||
msgstr ""
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user