mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge from trunk
This commit is contained in:
commit
5e6498556f
@ -19,6 +19,66 @@
|
||||
# new recipes:
|
||||
# - title:
|
||||
|
||||
- version: 0.8.30
|
||||
date: 2011-12-09
|
||||
|
||||
new features:
|
||||
- title: "Get Books: Add amazon.es and amazon.it"
|
||||
|
||||
- title: "Bulk convert dialog: Disable the Use saved conversion settings checkbox when none of the books being converted has saved conversion settings"
|
||||
|
||||
- title: "ebook-viewer: And a command line switch to specify the position at which the file should be opened."
|
||||
tickets: [899325]
|
||||
|
||||
- title: "Distribute calibre source code compressed with xz instead of gzip for a 40% reduction in size"
|
||||
|
||||
bug fixes:
|
||||
- title: "Get Books: Fix ebooks.com and amazon.fr. Fix cover display in Diesel ebooks store."
|
||||
|
||||
- title: "HTML Input: Fix regression that broke processing of a small fraction of HTML files encoded in a multi-byte character encoding."
|
||||
tickets: [899691]
|
||||
|
||||
- title: "Greatly reduce the delay at the end of a bulk metadata edit operation that operates on a very large number (thousands) of books"
|
||||
|
||||
- title: "Template language: Fix the subitems formatter function to split only when the period is surrounded by non-white space and not another period"
|
||||
|
||||
- title: "Fix ampersands in titles not displaying in the Cover Browser"
|
||||
|
||||
- title: "MOBI Output: Do not ignore an empty anchor at the end of a block element."
|
||||
|
||||
- title: "MOBI Output: Handle links to inline anchors placed inside large blocks of text correctly, i.e. the link should not point to the start of the block."
|
||||
tickets: [899831]
|
||||
|
||||
- title: "E-book viewer: Fix searching for text that is represented as entities in the underlying HTML."
|
||||
tickets: [899573]
|
||||
|
||||
- title: "Have the Esc shortcut perform exactly the same set of actions as clicking the clear button."
|
||||
tickets: [900048]
|
||||
|
||||
- title: "Prevent the adding books dialog from becoming too wide"
|
||||
|
||||
- title: "Fix custom column editing not behaving correctly with the Previous button in the edit metadata dialog."
|
||||
tickets: [899836]
|
||||
|
||||
- title: "T1 driver. More fixes to datetime handling to try to convince the T1's buggy firmware to not rescan metadata."
|
||||
tickets: [899514]
|
||||
|
||||
- title: "Only allow searching via non accented author names if the user interface language in calibre is set to English."
|
||||
tickets: [899227]
|
||||
|
||||
improved recipes:
|
||||
- Die Zeit subscription
|
||||
- Metro UK
|
||||
- suedeutsche.de
|
||||
|
||||
new recipes:
|
||||
- title: Blues News
|
||||
author: Oskar Kunicki
|
||||
|
||||
- title: "TVXS"
|
||||
author: Hargikas
|
||||
|
||||
|
||||
- version: 0.8.29
|
||||
date: 2011-12-02
|
||||
|
||||
|
26
recipes/blues.recipe
Normal file
26
recipes/blues.recipe
Normal file
@ -0,0 +1,26 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2011, Oskar Kunicki <rakso at interia.pl>'
|
||||
'''
|
||||
Changelog:
|
||||
2011-11-27
|
||||
News from BluesRSS.info
|
||||
'''
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class BluesRSS(BasicNewsRecipe):
|
||||
title = 'Blues News'
|
||||
__author__ = 'Oskar Kunicki'
|
||||
description ='Blues news from around the world'
|
||||
publisher = 'BluesRSS.info'
|
||||
category = 'news, blues, USA,UK'
|
||||
oldest_article = 5
|
||||
max_articles_per_feed = 100
|
||||
language = 'en'
|
||||
cover_url = 'http://bluesrss.info/cover.jpg'
|
||||
masthead_url = 'http://bluesrss.info/cover.jpg'
|
||||
no_stylesheets = True
|
||||
|
||||
remove_tags = [dict(name='div', attrs={'class':'wp-pagenavi'})]
|
||||
|
||||
feeds = [(u'News', u'http://bluesrss.info/feed/')]
|
27
recipes/descopera_org.recipe
Normal file
27
recipes/descopera_org.recipe
Normal file
@ -0,0 +1,27 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
descopera.org
|
||||
'''
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class Descopera(BasicNewsRecipe):
|
||||
title = u'Descoperă.org'
|
||||
__author__ = 'Marius Ignătescu'
|
||||
description = 'Descoperă. Placerea de a cunoaște'
|
||||
publisher = 'descopera.org'
|
||||
category = 'science, technology, culture, history, earth'
|
||||
language = 'ro'
|
||||
oldest_article = 14
|
||||
max_articles_per_feed = 100
|
||||
encoding = 'utf8'
|
||||
no_stylesheets = True
|
||||
extra_css = ' body{ font-family: Verdana,Helvetica,Arial,sans-serif } .introduction{font-weight: bold} .story-feature{display: block; padding: 0; border: 1px solid; width: 40%; font-size: small} .story-feature h2{text-align: center; text-transform: uppercase} '
|
||||
keep_only_tags = [dict(name='div', attrs={'class':['post']})]
|
||||
remove_tags = [dict(name='div', attrs={'class':['topnav', 'box_a', 'shr-bookmarks shr-bookmarks-expand shr-bookmarks-center shr-bookmarks-bg-knowledge']})]
|
||||
remove_attributes = ['width','height']
|
||||
cover_url = 'http://www.descopera.org/wp-content/themes/dorg/styles/default/img/b_top.png?width=400'
|
||||
feeds = [(u'Articles', u'http://www.descopera.org/feed/')]
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
return self.adeify_images(soup)
|
BIN
recipes/icons/blues.png
Normal file
BIN
recipes/icons/blues.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 910 B |
BIN
recipes/icons/descopera_org.png
Normal file
BIN
recipes/icons/descopera_org.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.3 KiB |
BIN
recipes/icons/zaman.png
Normal file
BIN
recipes/icons/zaman.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 999 B |
@ -25,12 +25,12 @@ class LaRepubblica(BasicNewsRecipe):
|
||||
use_embedded_content = False
|
||||
no_stylesheets = True
|
||||
publication_type = 'newspaper'
|
||||
articles_are_obfuscated = True
|
||||
temp_files = []
|
||||
articles_are_obfuscated = True
|
||||
temp_files = []
|
||||
extra_css = """
|
||||
img{display: block}
|
||||
"""
|
||||
|
||||
|
||||
remove_attributes = ['width','height','lang','xmlns:og','xmlns:fb']
|
||||
|
||||
preprocess_regexps = [
|
||||
@ -38,14 +38,14 @@ class LaRepubblica(BasicNewsRecipe):
|
||||
(re.compile(r'<head>.*?<title>', re.DOTALL|re.IGNORECASE), lambda match: '<head><title>'),
|
||||
(re.compile(r'</title>.*?</head>', re.DOTALL|re.IGNORECASE), lambda match: '</title></head>')
|
||||
]
|
||||
|
||||
|
||||
def get_article_url(self, article):
|
||||
link = BasicNewsRecipe.get_article_url(self, article)
|
||||
if link and not '.repubblica.it/' in link:
|
||||
link2 = article.get('id', article.get('guid', None))
|
||||
if link2:
|
||||
link = link2
|
||||
return link.rpartition('?')[0]
|
||||
return link.rpartition('?')[0]
|
||||
|
||||
def get_obfuscated_article(self, url):
|
||||
count = 0
|
||||
@ -56,12 +56,12 @@ class LaRepubblica(BasicNewsRecipe):
|
||||
count = 10
|
||||
except:
|
||||
print "Retrying download..."
|
||||
count += 1
|
||||
count += 1
|
||||
self.temp_files.append(PersistentTemporaryFile('_fa.html'))
|
||||
self.temp_files[-1].write(html)
|
||||
self.temp_files[-1].close()
|
||||
return self.temp_files[-1].name
|
||||
|
||||
|
||||
keep_only_tags = [
|
||||
dict(attrs={'class':'articolo'}),
|
||||
dict(attrs={'class':'body-text'}),
|
||||
@ -105,8 +105,8 @@ class LaRepubblica(BasicNewsRecipe):
|
||||
def preprocess_html(self, soup):
|
||||
for item in soup.findAll(['hgroup','deresponsabilizzazione','per']):
|
||||
item.name = 'div'
|
||||
item.attrs = []
|
||||
item.attrs = []
|
||||
for item in soup.findAll(style=True):
|
||||
del item['style']
|
||||
del item['style']
|
||||
return soup
|
||||
|
||||
|
||||
|
@ -15,13 +15,13 @@ try:
|
||||
SHOWDEBUG1 = mlog.showdebuglevel(1)
|
||||
SHOWDEBUG2 = mlog.showdebuglevel(2)
|
||||
except:
|
||||
print 'drMerry debuglogger not found, skipping debug options'
|
||||
#print 'drMerry debuglogger not found, skipping debug options'
|
||||
SHOWDEBUG0 = False
|
||||
SHOWDEBUG1 = False
|
||||
SHOWDEBUG2 = False
|
||||
KEEPSTATS = False
|
||||
|
||||
print ('level0: %s\nlevel1: %s\nlevel2: %s' % (SHOWDEBUG0,SHOWDEBUG1,SHOWDEBUG2))
|
||||
#print ('level0: %s\nlevel1: %s\nlevel2: %s' % (SHOWDEBUG0,SHOWDEBUG1,SHOWDEBUG2))
|
||||
|
||||
''' Version 1.2, updated cover image to match the changed website.
|
||||
added info date on title
|
||||
|
21
recipes/rynek_zdrowia.recipe
Normal file
21
recipes/rynek_zdrowia.recipe
Normal file
@ -0,0 +1,21 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class rynekzdrowia(BasicNewsRecipe):
|
||||
title = u'Rynek Zdrowia'
|
||||
__author__ = u'spi630'
|
||||
language = 'pl'
|
||||
masthead_url = 'http://k.rynekzdrowia.pl/images/headerLogo.png'
|
||||
cover_url = 'http://k.rynekzdrowia.pl/images/headerLogo.png'
|
||||
oldest_article = 3
|
||||
max_articles_per_feed = 25
|
||||
no_stylesheets = True
|
||||
auto_cleanup = True
|
||||
remove_empty_feeds=True
|
||||
|
||||
remove_tags_before = dict(name='h3')
|
||||
|
||||
feeds = [(u'Finanse i Zarz\u0105dzanie', u'http://www.rynekzdrowia.pl/Kanal/finanse.html'), (u'Inwestycje', u'http://www.rynekzdrowia.pl/Kanal/inwestycje.html'), (u'Aparatura i wyposa\u017cenie', u'http://www.rynekzdrowia.pl/Kanal/aparatura.html'), (u'Informatyka', u'http://www.rynekzdrowia.pl/Kanal/informatyka.html'), (u'Prawo', u'http://www.rynekzdrowia.pl/Kanal/prawo.html'), (u'Polityka zdrowotna', u'http://www.rynekzdrowia.pl/Kanal/polityka_zdrowotna.html'), (u'Ubezpieczenia Zdrowotne', u'http://www.rynekzdrowia.pl/Kanal/ubezpieczenia.html'), (u'Farmacja', u'http://www.rynekzdrowia.pl/Kanal/farmacja.html'), (u'Badania i rozw\xf3j', u'http://www.rynekzdrowia.pl/Kanal/badania.html'), (u'Nauka', u'http://www.rynekzdrowia.pl/Kanal/nauka.html'), (u'Po godzinach', u'http://www.rynekzdrowia.pl/Kanal/godziny.html'), (u'Us\u0142ugi medyczne', u'http://www.rynekzdrowia.pl/Kanal/uslugi.html')]
|
||||
|
||||
def print_version(self, url):
|
||||
url = url.replace('.html', ',drukuj.html')
|
||||
return url
|
@ -5,9 +5,10 @@ from calibre.web.feeds.news import BasicNewsRecipe
|
||||
class Zaman (BasicNewsRecipe):
|
||||
|
||||
title = u'ZAMAN Gazetesi'
|
||||
description = ' Zaman Gazetesi''nin internet sitesinden günlük haberler'
|
||||
__author__ = u'thomass'
|
||||
oldest_article = 2
|
||||
max_articles_per_feed =100
|
||||
max_articles_per_feed =50
|
||||
# no_stylesheets = True
|
||||
#delay = 1
|
||||
#use_embedded_content = False
|
||||
@ -16,19 +17,19 @@ class Zaman (BasicNewsRecipe):
|
||||
category = 'news, haberler,TR,gazete'
|
||||
language = 'tr'
|
||||
publication_type = 'newspaper '
|
||||
extra_css = ' body{ font-family: Verdana,Helvetica,Arial,sans-serif } .introduction{font-weight: bold} .story-feature{display: block; padding: 0; border: 1px solid; width: 40%; font-size: small} .story-feature h2{text-align: center; text-transform: uppercase} '
|
||||
extra_css = '.buyukbaslik{font-weight: bold; font-size: 18px;color:#0000FF}'#body{ font-family: Verdana,Helvetica,Arial,sans-serif } .introduction{font-weight: bold} .story-feature{display: block; padding: 0; border: 1px solid; width: 40%; font-size: small} .story-feature h2{text-align: center; text-transform: uppercase} '
|
||||
conversion_options = {
|
||||
'tags' : category
|
||||
,'language' : language
|
||||
,'publisher' : publisher
|
||||
,'linearize_tables': False
|
||||
,'linearize_tables': True
|
||||
}
|
||||
cover_img_url = 'https://fbcdn-profile-a.akamaihd.net/hprofile-ak-snc4/188140_81722291869_2111820_n.jpg'
|
||||
masthead_url = 'http://medya.zaman.com.tr/extentions/zaman.com.tr/img/section/logo-section.png'
|
||||
|
||||
|
||||
keep_only_tags = [dict(name='div', attrs={'id':[ 'news-detail-content']}), dict(name='td', attrs={'class':['columnist-detail','columnist_head']}) ]
|
||||
remove_tags = [ dict(name='div', attrs={'id':['news-detail-news-text-font-size','news-detail-gallery','news-detail-news-bottom-social']}),dict(name='div', attrs={'class':['radioEmbedBg','radyoProgramAdi']}),dict(name='a', attrs={'class':['webkit-html-attribute-value webkit-html-external-link']}),dict(name='table', attrs={'id':['yaziYorumTablosu']}),dict(name='img', attrs={'src':['http://medya.zaman.com.tr/pics/paylas.gif','http://medya.zaman.com.tr/extentions/zaman.com.tr/img/columnist/ma-16.png']})]
|
||||
#keep_only_tags = [dict(name='div', attrs={'id':[ 'news-detail-content']}), dict(name='td', attrs={'class':['columnist-detail','columnist_head']}) ]
|
||||
remove_tags = [ dict(name='img', attrs={'src':['http://medya.zaman.com.tr/zamantryeni/pics/zamanonline.gif']})]#,dict(name='div', attrs={'class':['radioEmbedBg','radyoProgramAdi']}),dict(name='a', attrs={'class':['webkit-html-attribute-value webkit-html-external-link']}),dict(name='table', attrs={'id':['yaziYorumTablosu']}),dict(name='img', attrs={'src':['http://medya.zaman.com.tr/pics/paylas.gif','http://medya.zaman.com.tr/extentions/zaman.com.tr/img/columnist/ma-16.png']})
|
||||
|
||||
|
||||
#remove_attributes = ['width','height']
|
||||
@ -37,7 +38,8 @@ class Zaman (BasicNewsRecipe):
|
||||
feeds = [
|
||||
( u'Anasayfa', u'http://www.zaman.com.tr/anasayfa.rss'),
|
||||
( u'Son Dakika', u'http://www.zaman.com.tr/sondakika.rss'),
|
||||
( u'En çok Okunanlar', u'http://www.zaman.com.tr/max_all.rss'),
|
||||
#( u'En çok Okunanlar', u'http://www.zaman.com.tr/max_all.rss'),
|
||||
#( u'Manşet', u'http://www.zaman.com.tr/manset.rss'),
|
||||
( u'Gündem', u'http://www.zaman.com.tr/gundem.rss'),
|
||||
( u'Yazarlar', u'http://www.zaman.com.tr/yazarlar.rss'),
|
||||
( u'Politika', u'http://www.zaman.com.tr/politika.rss'),
|
||||
@ -45,11 +47,20 @@ class Zaman (BasicNewsRecipe):
|
||||
( u'Dış Haberler', u'http://www.zaman.com.tr/dishaberler.rss'),
|
||||
( u'Yorumlar', u'http://www.zaman.com.tr/yorumlar.rss'),
|
||||
( u'Röportaj', u'http://www.zaman.com.tr/roportaj.rss'),
|
||||
( u'Dizi Yazı', u'http://www.zaman.com.tr/dizi.rss'),
|
||||
( u'Bilişim', u'http://www.zaman.com.tr/bilisim.rss'),
|
||||
( u'Otomotiv', u'http://www.zaman.com.tr/otomobil.rss'),
|
||||
( u'Spor', u'http://www.zaman.com.tr/spor.rss'),
|
||||
( u'Kürsü', u'http://www.zaman.com.tr/kursu.rss'),
|
||||
( u'Eğitim', u'http://www.zaman.com.tr/egitim.rss'),
|
||||
( u'Kültür Sanat', u'http://www.zaman.com.tr/kultursanat.rss'),
|
||||
( u'Televizyon', u'http://www.zaman.com.tr/televizyon.rss'),
|
||||
( u'Manşet', u'http://www.zaman.com.tr/manset.rss'),
|
||||
|
||||
( u'Aile', u'http://www.zaman.com.tr/aile.rss'),
|
||||
( u'Cuma Eki', u'http://www.zaman.com.tr/cuma.rss'),
|
||||
( u'Cumaertesi Eki', u'http://www.zaman.com.tr/cumaertesi.rss'),
|
||||
( u'Pazar Eki', u'http://www.zaman.com.tr/pazar.rss'),
|
||||
|
||||
]
|
||||
def print_version(self, url):
|
||||
return url.replace('http://www.zaman.com.tr/haber.do?haberno=', 'http://www.zaman.com.tr/yazdir.do?haberno=')
|
||||
|
||||
|
@ -12,14 +12,14 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: Debian iso-codes team <pkg-isocodes-"
|
||||
"devel@lists.alioth.debian.org>\n"
|
||||
"POT-Creation-Date: 2011-11-25 14:01+0000\n"
|
||||
"PO-Revision-Date: 2011-09-27 15:33+0000\n"
|
||||
"Last-Translator: Kovid Goyal <Unknown>\n"
|
||||
"PO-Revision-Date: 2011-12-03 15:11+0000\n"
|
||||
"Last-Translator: Yuri Chornoivan <yurchor@gmail.com>\n"
|
||||
"Language-Team: Ukrainian <translation-team-uk@lists.sourceforge.net>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2011-11-26 05:43+0000\n"
|
||||
"X-Generator: Launchpad (build 14381)\n"
|
||||
"X-Launchpad-Export-Date: 2011-12-04 04:43+0000\n"
|
||||
"X-Generator: Launchpad (build 14418)\n"
|
||||
"Language: uk\n"
|
||||
|
||||
#. name for aaa
|
||||
@ -17956,7 +17956,7 @@ msgstr "ндоола"
|
||||
|
||||
#. name for nds
|
||||
msgid "German; Low"
|
||||
msgstr ""
|
||||
msgstr "нижньонімецька"
|
||||
|
||||
#. name for ndt
|
||||
msgid "Ndunga"
|
||||
|
@ -4,7 +4,7 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
__appname__ = u'calibre'
|
||||
numeric_version = (0, 8, 29)
|
||||
numeric_version = (0, 8, 30)
|
||||
__version__ = u'.'.join(map(unicode, numeric_version))
|
||||
__author__ = u"Kovid Goyal <kovid@kovidgoyal.net>"
|
||||
|
||||
|
@ -451,6 +451,10 @@ class CatalogPlugin(Plugin): # {{{
|
||||
'series_index','series','size','tags','timestamp',
|
||||
'title_sort','title','uuid','languages'])
|
||||
all_custom_fields = set(db.custom_field_keys())
|
||||
for field in list(all_custom_fields):
|
||||
fm = db.field_metadata[field]
|
||||
if fm['datatype'] == 'series':
|
||||
all_custom_fields.add(field+'_index')
|
||||
all_fields = all_std_fields.union(all_custom_fields)
|
||||
|
||||
if opts.fields != 'all':
|
||||
|
@ -143,6 +143,9 @@ class ANDROID(USBMS):
|
||||
# Kobo
|
||||
0x2237: { 0x2208 : [0x0226] },
|
||||
|
||||
# Lenovo
|
||||
0x17ef : { 0x7421 : [0x0216] },
|
||||
|
||||
}
|
||||
EBOOK_DIR_MAIN = ['eBooks/import', 'wordplayer/calibretransfer', 'Books',
|
||||
'sdcard/ebooks']
|
||||
@ -155,7 +158,7 @@ class ANDROID(USBMS):
|
||||
'GT-I5700', 'SAMSUNG', 'DELL', 'LINUX', 'GOOGLE', 'ARCHOS',
|
||||
'TELECHIP', 'HUAWEI', 'T-MOBILE', 'SEMC', 'LGE', 'NVIDIA',
|
||||
'GENERIC-', 'ZTE', 'MID', 'QUALCOMM', 'PANDIGIT', 'HYSTON',
|
||||
'VIZIO', 'GOOGLE', 'FREESCAL', 'KOBO_INC']
|
||||
'VIZIO', 'GOOGLE', 'FREESCAL', 'KOBO_INC', 'LENOVO']
|
||||
WINDOWS_MAIN_MEM = ['ANDROID_PHONE', 'A855', 'A853', 'INC.NEXUS_ONE',
|
||||
'__UMS_COMPOSITE', '_MB200', 'MASS_STORAGE', '_-_CARD', 'SGH-I897',
|
||||
'GT-I9000', 'FILE-STOR_GADGET', 'SGH-T959', 'SAMSUNG_ANDROID',
|
||||
@ -167,12 +170,13 @@ class ANDROID(USBMS):
|
||||
'MB525', 'ANDROID2.3', 'SGH-I997', 'GT-I5800_CARD', 'MB612',
|
||||
'GT-S5830_CARD', 'GT-S5570_CARD', 'MB870', 'MID7015A',
|
||||
'ALPANDIGITAL', 'ANDROID_MID', 'VTAB1008', 'EMX51_BBG_ANDROI',
|
||||
'UMS', '.K080', 'P990', 'LTE', 'MB853', 'GT-S5660_CARD']
|
||||
'UMS', '.K080', 'P990', 'LTE', 'MB853', 'GT-S5660_CARD', 'A107']
|
||||
WINDOWS_CARD_A_MEM = ['ANDROID_PHONE', 'GT-I9000_CARD', 'SGH-I897',
|
||||
'FILE-STOR_GADGET', 'SGH-T959', 'SAMSUNG_ANDROID', 'GT-P1000_CARD',
|
||||
'A70S', 'A101IT', '7', 'INCREDIBLE', 'A7EB', 'SGH-T849_CARD',
|
||||
'__UMS_COMPOSITE', 'SGH-I997_CARD', 'MB870', 'ALPANDIGITAL',
|
||||
'ANDROID_MID', 'P990_SD_CARD', '.K080', 'LTE_CARD', 'MB853']
|
||||
'ANDROID_MID', 'P990_SD_CARD', '.K080', 'LTE_CARD', 'MB853',
|
||||
'A1-07___C0541A4F']
|
||||
|
||||
OSX_MAIN_MEM = 'Android Device Main Memory'
|
||||
|
||||
|
@ -17,6 +17,10 @@ from calibre.ptempfile import PersistentTemporaryDirectory
|
||||
from calibre.utils.ipc.server import Server
|
||||
from calibre.utils.ipc.job import ParallelJob
|
||||
|
||||
# If the specified screen has either dimension larger than this value, no image
|
||||
# rescaling is done (we assume that it is a tablet output profile)
|
||||
MAX_SCREEN_SIZE = 3000
|
||||
|
||||
def extract_comic(path_to_comic_file):
|
||||
'''
|
||||
Un-archive the comic file.
|
||||
@ -141,7 +145,7 @@ class PageProcessor(list): # {{{
|
||||
newsizey = int(newsizex / aspect)
|
||||
deltax = 0
|
||||
deltay = (SCRHEIGHT - newsizey) / 2
|
||||
if newsizex < 20000 and newsizey < 20000:
|
||||
if newsizex < MAX_SCREEN_SIZE and newsizey < MAX_SCREEN_SIZE:
|
||||
# Too large and resizing fails, so better
|
||||
# to leave it as original size
|
||||
wand.size = (newsizex, newsizey)
|
||||
@ -165,14 +169,14 @@ class PageProcessor(list): # {{{
|
||||
newsizey = int(newsizex / aspect)
|
||||
deltax = 0
|
||||
deltay = (wscreeny - newsizey) / 2
|
||||
if newsizex < 20000 and newsizey < 20000:
|
||||
if newsizex < MAX_SCREEN_SIZE and newsizey < MAX_SCREEN_SIZE:
|
||||
# Too large and resizing fails, so better
|
||||
# to leave it as original size
|
||||
wand.size = (newsizex, newsizey)
|
||||
wand.set_border_color(pw)
|
||||
wand.add_border(pw, deltax, deltay)
|
||||
else:
|
||||
if SCRWIDTH < 20000 and SCRHEIGHT < 20000:
|
||||
if SCRWIDTH < MAX_SCREEN_SIZE and SCRHEIGHT < MAX_SCREEN_SIZE:
|
||||
wand.size = (SCRWIDTH, SCRHEIGHT)
|
||||
|
||||
if not self.opts.dont_sharpen:
|
||||
|
@ -148,7 +148,11 @@ class HTMLFile(object):
|
||||
url = match.group(i)
|
||||
if url:
|
||||
break
|
||||
link = self.resolve(url)
|
||||
try:
|
||||
link = self.resolve(url)
|
||||
except ValueError:
|
||||
# Unparseable URL, ignore
|
||||
continue
|
||||
if link not in self.links:
|
||||
self.links.append(link)
|
||||
|
||||
|
@ -178,7 +178,11 @@ class Serializer(object):
|
||||
at the end.
|
||||
'''
|
||||
hrefs = self.oeb.manifest.hrefs
|
||||
path, frag = urldefrag(urlnormalize(href))
|
||||
try:
|
||||
path, frag = urldefrag(urlnormalize(href))
|
||||
except ValueError:
|
||||
# Unparseable URL
|
||||
return False
|
||||
if path and base:
|
||||
path = base.abshref(path)
|
||||
if path and path not in hrefs:
|
||||
|
@ -154,7 +154,11 @@ class Split(object):
|
||||
|
||||
def rewrite_links(self, url):
|
||||
href, frag = urldefrag(url)
|
||||
href = self.current_item.abshref(href)
|
||||
try:
|
||||
href = self.current_item.abshref(href)
|
||||
except ValueError:
|
||||
# Unparseable URL
|
||||
return url
|
||||
if href in self.map:
|
||||
anchor_map = self.map[href]
|
||||
nhref = anchor_map[frag if frag else None]
|
||||
|
@ -35,7 +35,10 @@ class PluginWidget(QWidget, Ui_Form):
|
||||
|
||||
self.all_fields = [x for x in FIELDS if x != 'all']
|
||||
#add custom columns
|
||||
self.all_fields.extend([x for x in sorted(db.custom_field_keys())])
|
||||
for x in sorted(db.custom_field_keys()):
|
||||
self.all_fields.append(x)
|
||||
if db.field_metadata[x]['datatype'] == 'series':
|
||||
self.all_fields.append(x+'_index')
|
||||
#populate
|
||||
for x in self.all_fields:
|
||||
QListWidgetItem(x, self.db_fields)
|
||||
|
@ -33,6 +33,9 @@ class PluginWidget(QWidget, Ui_Form):
|
||||
self.all_fields.append(x)
|
||||
QListWidgetItem(x, self.db_fields)
|
||||
|
||||
fm = db.field_metadata[x]
|
||||
if fm['datatype'] == 'series':
|
||||
QListWidgetItem(x+'_index', self.db_fields)
|
||||
|
||||
def initialize(self, name, db):
|
||||
self.name = name
|
||||
|
@ -419,6 +419,13 @@ class Scheduler(QObject):
|
||||
QObject.__init__(self, parent)
|
||||
self.internet_connection_failed = False
|
||||
self._parent = parent
|
||||
self.no_internet_msg = _('Cannot download news as no internet connection '
|
||||
'is active')
|
||||
self.no_internet_dialog = d = error_dialog(self._parent,
|
||||
self.no_internet_msg, _('No internet connection'),
|
||||
show_copy_button=False)
|
||||
d.setModal(False)
|
||||
|
||||
self.recipe_model = RecipeModel()
|
||||
self.db = db
|
||||
self.lock = QMutex(QMutex.Recursive)
|
||||
@ -523,7 +530,6 @@ class Scheduler(QObject):
|
||||
finally:
|
||||
self.lock.unlock()
|
||||
|
||||
|
||||
def download_clicked(self, urn):
|
||||
if urn is not None:
|
||||
return self.download(urn)
|
||||
@ -534,18 +540,25 @@ class Scheduler(QObject):
|
||||
def download_all_scheduled(self):
|
||||
self.download_clicked(None)
|
||||
|
||||
def download(self, urn):
|
||||
self.lock.lock()
|
||||
def has_internet_connection(self):
|
||||
if not internet_connected():
|
||||
if not self.internet_connection_failed:
|
||||
self.internet_connection_failed = True
|
||||
d = error_dialog(self._parent, _('No internet connection'),
|
||||
_('Cannot download news as no internet connection '
|
||||
'is active'))
|
||||
d.setModal(False)
|
||||
d.show()
|
||||
if self._parent.is_minimized_to_tray:
|
||||
self._parent.status_bar.show_message(self.no_internet_msg,
|
||||
5000)
|
||||
elif not self.no_internet_dialog.isVisible():
|
||||
self.no_internet_dialog.show()
|
||||
return False
|
||||
self.internet_connection_failed = False
|
||||
if self.no_internet_dialog.isVisible():
|
||||
self.no_internet_dialog.hide()
|
||||
return True
|
||||
|
||||
def download(self, urn):
|
||||
self.lock.lock()
|
||||
if not self.has_internet_connection():
|
||||
return False
|
||||
doit = urn not in self.download_queue
|
||||
self.lock.unlock()
|
||||
if doit:
|
||||
@ -555,7 +568,9 @@ class Scheduler(QObject):
|
||||
def check(self):
|
||||
recipes = self.recipe_model.get_to_be_downloaded_recipes()
|
||||
for urn in recipes:
|
||||
self.download(urn)
|
||||
if not self.download(urn):
|
||||
# No internet connection, we will try again in a minute
|
||||
break
|
||||
|
||||
if __name__ == '__main__':
|
||||
from calibre.gui2 import is_ok_to_use_qt
|
||||
|
@ -28,11 +28,11 @@ class BaseModel(QAbstractListModel):
|
||||
|
||||
def name_to_action(self, name, gui):
|
||||
if name == 'Donate':
|
||||
return FakeAction(name, 'donate.png',
|
||||
return FakeAction(_('Donate'), 'donate.png',
|
||||
dont_add_to=frozenset(['context-menu',
|
||||
'context-menu-device']))
|
||||
if name == 'Location Manager':
|
||||
return FakeAction(name, None,
|
||||
return FakeAction(_('Location Manager'), None,
|
||||
_('Switch between library and device views'),
|
||||
dont_add_to=frozenset(['menubar', 'toolbar',
|
||||
'toolbar-child', 'context-menu',
|
||||
|
@ -723,10 +723,10 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
|
||||
self.write_settings()
|
||||
if self.system_tray_icon.isVisible():
|
||||
if not dynamic['systray_msg'] and not isosx:
|
||||
info_dialog(self, 'calibre', 'calibre '+\
|
||||
info_dialog(self, 'calibre', 'calibre '+ \
|
||||
_('will keep running in the system tray. To close it, '
|
||||
'choose <b>Quit</b> in the context menu of the '
|
||||
'system tray.')).exec_()
|
||||
'system tray.'), show_copy_button=False).exec_()
|
||||
dynamic['systray_msg'] = True
|
||||
self.hide_windows()
|
||||
e.ignore()
|
||||
|
@ -537,6 +537,12 @@ class DocumentView(QWebView): # {{{
|
||||
self.dictionary_action.setShortcut(Qt.CTRL+Qt.Key_L)
|
||||
self.dictionary_action.triggered.connect(self.lookup)
|
||||
self.addAction(self.dictionary_action)
|
||||
self.search_action = QAction(QIcon(I('dictionary.png')),
|
||||
_('&Search for next occurrence'), self)
|
||||
self.search_action.setShortcut(Qt.CTRL+Qt.Key_S)
|
||||
self.search_action.triggered.connect(self.search_next)
|
||||
self.addAction(self.search_action)
|
||||
|
||||
self.goto_location_action = QAction(_('Go to...'), self)
|
||||
self.goto_location_menu = m = QMenu(self)
|
||||
self.goto_location_actions = a = {
|
||||
@ -620,6 +626,7 @@ class DocumentView(QWebView): # {{{
|
||||
text = unicode(self.selectedText())
|
||||
if text:
|
||||
menu.insertAction(list(menu.actions())[0], self.dictionary_action)
|
||||
menu.insertAction(list(menu.actions())[0], self.search_action)
|
||||
menu.addSeparator()
|
||||
menu.addAction(self.goto_location_action)
|
||||
menu.exec_(ev.globalPos())
|
||||
@ -630,6 +637,12 @@ class DocumentView(QWebView): # {{{
|
||||
if t:
|
||||
self.manager.lookup(t.split()[0])
|
||||
|
||||
def search_next(self):
|
||||
if self.manager is not None:
|
||||
t = unicode(self.selectedText()).strip()
|
||||
if t:
|
||||
self.manager.search.set_search_string(t)
|
||||
|
||||
def set_manager(self, manager):
|
||||
self.manager = manager
|
||||
self.scrollbar = manager.horizontal_scrollbar
|
||||
|
@ -347,7 +347,9 @@ class BIBTEX(CatalogPlugin): # {{{
|
||||
|
||||
for field in fields:
|
||||
if field.startswith('#'):
|
||||
item = db.get_field(entry['id'],field,index_is_id=True)
|
||||
item = db.get_field(entry['id'],field,index_is_id=True)
|
||||
if isinstance(item, (bool, float, int)):
|
||||
item = repr(item)
|
||||
elif field == 'title_sort':
|
||||
item = entry['sort']
|
||||
else:
|
||||
@ -391,7 +393,7 @@ class BIBTEX(CatalogPlugin): # {{{
|
||||
|
||||
elif field == 'isbn' :
|
||||
# Could be 9, 10 or 13 digits
|
||||
bibtex_entry.append(u'isbn = "%s"' % re.sub(u'[\D]', u'', item))
|
||||
bibtex_entry.append(u'isbn = "%s"' % re.sub(u'[0-9xX]', u'', item))
|
||||
|
||||
elif field == 'formats' :
|
||||
#Add file path if format is selected
|
||||
@ -413,7 +415,8 @@ class BIBTEX(CatalogPlugin): # {{{
|
||||
bibtex_entry.append(u'month = "%s"' % bibtexdict.utf8ToBibtex(strftime("%b", item)))
|
||||
|
||||
elif field.startswith('#') :
|
||||
bibtex_entry.append(u'%s = "%s"' % (field[1:], bibtexdict.utf8ToBibtex(item)))
|
||||
bibtex_entry.append(u'custom_%s = "%s"' % (field[1:],
|
||||
bibtexdict.utf8ToBibtex(item)))
|
||||
|
||||
else:
|
||||
# elif field in ['title', 'publisher', 'cover', 'uuid', 'ondevice',
|
||||
|
@ -64,8 +64,17 @@ def do_list(db, fields, afields, sort_by, ascending, search_text, line_width, se
|
||||
data = db.get_data_as_dict(prefix, authors_as_string=True)
|
||||
fields = ['id'] + fields
|
||||
title_fields = fields
|
||||
fields = [db.custom_column_label_map[x[1:]]['num'] if x[0]=='*'
|
||||
else x for x in fields]
|
||||
def field_name(f):
|
||||
ans = f
|
||||
if f[0] == '*':
|
||||
if f.endswith('_index'):
|
||||
fkey = f[1:-len('_index')]
|
||||
num = db.custom_column_label_map[fkey]['num']
|
||||
ans = '%d_index'%num
|
||||
else:
|
||||
ans = db.custom_column_label_map[f[1:]]['num']
|
||||
return ans
|
||||
fields = list(map(field_name, fields))
|
||||
|
||||
for f in data:
|
||||
fmts = [x for x in f['formats'] if x is not None]
|
||||
@ -121,8 +130,10 @@ def do_list(db, fields, afields, sort_by, ascending, search_text, line_width, se
|
||||
def list_option_parser(db=None):
|
||||
fields = set(FIELDS)
|
||||
if db is not None:
|
||||
for f in db.custom_column_label_map:
|
||||
for f, data in db.custom_column_label_map.iteritems():
|
||||
fields.add('*'+f)
|
||||
if data['datatype'] == 'series':
|
||||
fields.add('*'+f+'_index')
|
||||
|
||||
parser = get_parser(_(
|
||||
'''\
|
||||
@ -161,8 +172,10 @@ def command_list(args, dbpath):
|
||||
opts, args = parser.parse_args(sys.argv[:1] + args)
|
||||
afields = set(FIELDS)
|
||||
if db is not None:
|
||||
for f in db.custom_column_label_map:
|
||||
for f, data in db.custom_column_label_map.iteritems():
|
||||
afields.add('*'+f)
|
||||
if data['datatype'] == 'series':
|
||||
afields.add('*'+f+'_index')
|
||||
fields = [str(f.strip().lower()) for f in opts.fields.split(',')]
|
||||
if 'all' in fields:
|
||||
fields = sorted(list(afields))
|
||||
|
@ -1089,8 +1089,12 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
|
||||
ids = tuple(ids)
|
||||
if len(ids) > 50000:
|
||||
return True
|
||||
if len(ids) == 1:
|
||||
ids = '(%d)'%ids[0]
|
||||
else:
|
||||
ids = repr(ids)
|
||||
return self.conn.get('''
|
||||
SELECT data FROM conversion_options WHERE book IN %r AND
|
||||
SELECT data FROM conversion_options WHERE book IN %s AND
|
||||
format=? LIMIT 1'''%(ids,), (format,), all=False) is not None
|
||||
|
||||
def delete_conversion_options(self, id, format, commit=True):
|
||||
|
@ -3376,11 +3376,15 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
'''
|
||||
if prefix is None:
|
||||
prefix = self.library_path
|
||||
FIELDS = set(['title', 'sort', 'authors', 'author_sort', 'publisher', 'rating',
|
||||
'timestamp', 'size', 'tags', 'comments', 'series', 'series_index',
|
||||
'uuid', 'pubdate', 'last_modified', 'identifiers', 'languages'])
|
||||
for x in self.custom_column_num_map:
|
||||
FIELDS.add(x)
|
||||
fdata = self.custom_column_num_map
|
||||
|
||||
FIELDS = set(['title', 'sort', 'authors', 'author_sort', 'publisher',
|
||||
'rating', 'timestamp', 'size', 'tags', 'comments', 'series',
|
||||
'series_index', 'uuid', 'pubdate', 'last_modified', 'identifiers',
|
||||
'languages']).union(set(fdata))
|
||||
for x, data in fdata.iteritems():
|
||||
if data['datatype'] == 'series':
|
||||
FIELDS.add('%d_index'%x)
|
||||
data = []
|
||||
for record in self.data:
|
||||
if record is None: continue
|
||||
|
@ -47,7 +47,7 @@ Overriding icons, templates, etcetera
|
||||
|
||||
|app| allows you to override the static resources, like icons, templates, javascript, etc. with customized versions that you like.
|
||||
All static resources are stored in the resources sub-folder of the calibre install location. On Windows, this is usually
|
||||
:file:`C:\Program Files\Calibre2\resources`. On OS X, :file:`/Applications/calibre.app/Contents/Resources/resources/`. On linux, if you are using the binary installer
|
||||
:file:`C:/Program Files/Calibre2/resources`. On OS X, :file:`/Applications/calibre.app/Contents/Resources/resources/`. On linux, if you are using the binary installer
|
||||
from the calibre website it will be :file:`/opt/calibre/resources`. These paths can change depending on where you choose to install |app|.
|
||||
|
||||
You should not change the files in this resources folder, as your changes will get overwritten the next time you update |app|. Instead, go to
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
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
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user