mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
0.9.15
This commit is contained in:
commit
1216bac1e3
@ -19,6 +19,81 @@
|
|||||||
# new recipes:
|
# new recipes:
|
||||||
# - title:
|
# - title:
|
||||||
|
|
||||||
|
- version: 0.9.15
|
||||||
|
date: 2013-01-18
|
||||||
|
|
||||||
|
new features:
|
||||||
|
- title: "Linux MTP driver: Detect devices that have MTP interfaces even if their USB ids are not known"
|
||||||
|
|
||||||
|
- title: "Content server: Allow picking a random book by clicking the 'Random book' link on the start page. You can also refresh the random book page to get a new random book"
|
||||||
|
|
||||||
|
- title: "E-book viewer: Add an option to hide the toolbars in the viewer window (Preferences->Miscellaneous->Show controls in the viewr preferences). You can unhide them by right clicking in the viewer window."
|
||||||
|
|
||||||
|
- title: "Kobo driver: Speedup initial connect by avoiding unnecessary update of series metadata in some situations."
|
||||||
|
tickets: [1099190]
|
||||||
|
|
||||||
|
- title: "Get Books: Allow the store plugins to be dynamically loaded so that future website changes of a store dont require a calibre update to fix Get Books."
|
||||||
|
|
||||||
|
- title: "Wireless driver: Always replace file when resending a previously sent book to the device, even if the title/author have changed."
|
||||||
|
|
||||||
|
- title: "Add PocketBook Pro 912 driver."
|
||||||
|
tickets: [1099571]
|
||||||
|
|
||||||
|
- title: "When creating/exporting epub and mobi files, add the calibre book identifier as a special field in the book's metadata. This allows third party tools to identify the book record in calibre to which the file belongs."
|
||||||
|
|
||||||
|
- title: "Wireless driver: Add support for using the book uuid as the filename"
|
||||||
|
|
||||||
|
- title: "Remove the experimental tag from the subset fonts feature, since there has been only one reported problem (now fixed) with it in the two months since it was released"
|
||||||
|
|
||||||
|
bug fixes:
|
||||||
|
- title: "Get Books: Update the amazon, waterstones and libri.de plugins to account for website changes"
|
||||||
|
|
||||||
|
- title: "MOBI Input: Do not choke on MOBI files with incorrectly encoded titles."
|
||||||
|
tickets: [1100601]
|
||||||
|
|
||||||
|
- title: "Font subsetting: Fix a bug in the parsing of the GSUB table that could cause some ligatures to not be included in the subset font"
|
||||||
|
|
||||||
|
- title: "E-book-viewer: Fix TOC links without anchors not scrolling to the top of the current flow"
|
||||||
|
|
||||||
|
- title: "LIT Input: Handle lit files that set an incorrect XML mimetype for their text."
|
||||||
|
tickets: [1099621]
|
||||||
|
|
||||||
|
- title: "Catalogs: Fix 'X' being droppen from isbns on export"
|
||||||
|
tickets: [1098325]
|
||||||
|
|
||||||
|
- title: "Fix an error when editing date in the main book list and all visible dates are blank."
|
||||||
|
tickets: [1098675]
|
||||||
|
|
||||||
|
- title: "Fix calibre-smtp using incorrect escaping for non-ascii attachment filenames"
|
||||||
|
tickets: [1098478]
|
||||||
|
|
||||||
|
- title: "Conversion: When subsetting fonts, handle multiple @font-face rules referring to the same physical font"
|
||||||
|
|
||||||
|
- title: "Content server: Update metadata when serving azw3 files"
|
||||||
|
|
||||||
|
- title: "CHM Input: Handle chm files that contain files with url unsafe filenames."
|
||||||
|
tickets: [1100610]
|
||||||
|
|
||||||
|
- title: "Content server: Fix custom icons for top level categories incorrect."
|
||||||
|
tickets: [1095016]
|
||||||
|
|
||||||
|
- title: "Kobo driver: When resending a file to the device, update the filesize in the Kobo db to prevent the device from deleting the file."
|
||||||
|
tickets: [1100607]
|
||||||
|
|
||||||
|
improved recipes:
|
||||||
|
- The Chronicle of Higher Education
|
||||||
|
- Smithsonian Magazine
|
||||||
|
- Philosophy Now
|
||||||
|
- The Economist
|
||||||
|
- Business Week Magazine
|
||||||
|
|
||||||
|
new recipes:
|
||||||
|
- title: Asco de Vida
|
||||||
|
author: Krittika Goyal
|
||||||
|
|
||||||
|
- title: Schattenblick
|
||||||
|
author: ThB
|
||||||
|
|
||||||
- version: 0.9.14
|
- version: 0.9.14
|
||||||
date: 2013-01-11
|
date: 2013-01-11
|
||||||
|
|
||||||
|
20
recipes/asco_de_vida.recipe
Normal file
20
recipes/asco_de_vida.recipe
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class HindustanTimes(BasicNewsRecipe):
|
||||||
|
title = u'Asco de vida'
|
||||||
|
language = 'es'
|
||||||
|
__author__ = 'Krittika Goyal'
|
||||||
|
oldest_article = 1 #days
|
||||||
|
max_articles_per_feed = 25
|
||||||
|
#encoding = 'cp1252'
|
||||||
|
use_embedded_content = False
|
||||||
|
|
||||||
|
no_stylesheets = True
|
||||||
|
keep_only_tags = dict(name='div', attrs={'class':'box story'})
|
||||||
|
|
||||||
|
|
||||||
|
feeds = [
|
||||||
|
('News',
|
||||||
|
'http://feeds2.feedburner.com/AscoDeVida'),
|
||||||
|
]
|
||||||
|
|
@ -38,7 +38,7 @@ class BusinessWeekMagazine(BasicNewsRecipe):
|
|||||||
title=self.tag_to_string(div.a).strip()
|
title=self.tag_to_string(div.a).strip()
|
||||||
url=div.a['href']
|
url=div.a['href']
|
||||||
soup0 = self.index_to_soup(url)
|
soup0 = self.index_to_soup(url)
|
||||||
urlprint=soup0.find('li', attrs={'class':'print'}).a['href']
|
urlprint=soup0.find('li', attrs={'class':'print tracked'}).a['href']
|
||||||
articles.append({'title':title, 'url':urlprint, 'description':'', 'date':''})
|
articles.append({'title':title, 'url':urlprint, 'description':'', 'date':''})
|
||||||
|
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ class BusinessWeekMagazine(BasicNewsRecipe):
|
|||||||
title=self.tag_to_string(div.a).strip()
|
title=self.tag_to_string(div.a).strip()
|
||||||
url=div.a['href']
|
url=div.a['href']
|
||||||
soup0 = self.index_to_soup(url)
|
soup0 = self.index_to_soup(url)
|
||||||
urlprint=soup0.find('li', attrs={'class':'print'}).a['href']
|
urlprint=soup0.find('li', attrs={'class':'print tracked'}).a['href']
|
||||||
articles.append({'title':title, 'url':urlprint, 'description':desc, 'date':''})
|
articles.append({'title':title, 'url':urlprint, 'description':desc, 'date':''})
|
||||||
|
|
||||||
if articles:
|
if articles:
|
||||||
|
@ -41,10 +41,11 @@ class Economist(BasicNewsRecipe):
|
|||||||
remove_tags = [
|
remove_tags = [
|
||||||
dict(name=['script', 'noscript', 'title', 'iframe', 'cf_floatingcontent']),
|
dict(name=['script', 'noscript', 'title', 'iframe', 'cf_floatingcontent']),
|
||||||
dict(attrs={'class':['dblClkTrk', 'ec-article-info',
|
dict(attrs={'class':['dblClkTrk', 'ec-article-info',
|
||||||
'share_inline_header', 'related-items']}),
|
'share_inline_header', 'related-items',
|
||||||
|
'main-content-container']}),
|
||||||
{'class': lambda x: x and 'share-links-header' in x},
|
{'class': lambda x: x and 'share-links-header' in x},
|
||||||
]
|
]
|
||||||
keep_only_tags = [dict(id='ec-article-body')]
|
keep_only_tags = [dict(name='article')]
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
preprocess_regexps = [(re.compile('</html>.*', re.DOTALL),
|
preprocess_regexps = [(re.compile('</html>.*', re.DOTALL),
|
||||||
lambda x:'</html>')]
|
lambda x:'</html>')]
|
||||||
|
@ -41,10 +41,11 @@ class Economist(BasicNewsRecipe):
|
|||||||
remove_tags = [
|
remove_tags = [
|
||||||
dict(name=['script', 'noscript', 'title', 'iframe', 'cf_floatingcontent']),
|
dict(name=['script', 'noscript', 'title', 'iframe', 'cf_floatingcontent']),
|
||||||
dict(attrs={'class':['dblClkTrk', 'ec-article-info',
|
dict(attrs={'class':['dblClkTrk', 'ec-article-info',
|
||||||
'share_inline_header', 'related-items']}),
|
'share_inline_header', 'related-items',
|
||||||
|
'main-content-container']}),
|
||||||
{'class': lambda x: x and 'share-links-header' in x},
|
{'class': lambda x: x and 'share-links-header' in x},
|
||||||
]
|
]
|
||||||
keep_only_tags = [dict(id='ec-article-body')]
|
keep_only_tags = [dict(name='article')]
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
preprocess_regexps = [(re.compile('</html>.*', re.DOTALL),
|
preprocess_regexps = [(re.compile('</html>.*', re.DOTALL),
|
||||||
lambda x:'</html>')]
|
lambda x:'</html>')]
|
||||||
|
@ -124,19 +124,19 @@ class NYTimes(BasicNewsRecipe):
|
|||||||
if headlinesOnly:
|
if headlinesOnly:
|
||||||
title='New York Times Headlines'
|
title='New York Times Headlines'
|
||||||
description = 'Headlines from the New York Times'
|
description = 'Headlines from the New York Times'
|
||||||
needs_subscription = True
|
needs_subscription = 'optional'
|
||||||
elif webEdition:
|
elif webEdition:
|
||||||
title='New York Times (Web)'
|
title='New York Times (Web)'
|
||||||
description = 'New York Times on the Web'
|
description = 'New York Times on the Web'
|
||||||
needs_subscription = True
|
needs_subscription = 'optional'
|
||||||
elif replaceKindleVersion:
|
elif replaceKindleVersion:
|
||||||
title='The New York Times'
|
title='The New York Times'
|
||||||
description = 'Today\'s New York Times'
|
description = 'Today\'s New York Times'
|
||||||
needs_subscription = True
|
needs_subscription = 'optional'
|
||||||
else:
|
else:
|
||||||
title='New York Times'
|
title='New York Times'
|
||||||
description = 'Today\'s New York Times'
|
description = 'Today\'s New York Times'
|
||||||
needs_subscription = True
|
needs_subscription = 'optional'
|
||||||
|
|
||||||
def decode_url_date(self,url):
|
def decode_url_date(self,url):
|
||||||
urlitems = url.split('/')
|
urlitems = url.split('/')
|
||||||
|
@ -9,14 +9,14 @@ msgstr ""
|
|||||||
"Project-Id-Version: calibre\n"
|
"Project-Id-Version: calibre\n"
|
||||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"POT-Creation-Date: 2011-11-25 14:01+0000\n"
|
"POT-Creation-Date: 2011-11-25 14:01+0000\n"
|
||||||
"PO-Revision-Date: 2012-12-28 09:13+0000\n"
|
"PO-Revision-Date: 2013-01-12 08:34+0000\n"
|
||||||
"Last-Translator: Jellby <Unknown>\n"
|
"Last-Translator: Jellby <Unknown>\n"
|
||||||
"Language-Team: Español; Castellano <>\n"
|
"Language-Team: Español; Castellano <>\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2012-12-29 05:00+0000\n"
|
"X-Launchpad-Export-Date: 2013-01-13 04:37+0000\n"
|
||||||
"X-Generator: Launchpad (build 16378)\n"
|
"X-Generator: Launchpad (build 16420)\n"
|
||||||
|
|
||||||
#. name for aaa
|
#. name for aaa
|
||||||
msgid "Ghotuo"
|
msgid "Ghotuo"
|
||||||
@ -9652,7 +9652,7 @@ msgstr "Haruku"
|
|||||||
|
|
||||||
#. name for hrm
|
#. name for hrm
|
||||||
msgid "Miao; Horned"
|
msgid "Miao; Horned"
|
||||||
msgstr ""
|
msgstr "Miao blanco"
|
||||||
|
|
||||||
#. name for hro
|
#. name for hro
|
||||||
msgid "Haroi"
|
msgid "Haroi"
|
||||||
@ -9756,7 +9756,7 @@ msgstr ""
|
|||||||
|
|
||||||
#. name for huj
|
#. name for huj
|
||||||
msgid "Miao; Northern Guiyang"
|
msgid "Miao; Northern Guiyang"
|
||||||
msgstr ""
|
msgstr "Miao de Guiyang septentrional"
|
||||||
|
|
||||||
#. name for huk
|
#. name for huk
|
||||||
msgid "Hulung"
|
msgid "Hulung"
|
||||||
@ -16280,7 +16280,7 @@ msgstr ""
|
|||||||
|
|
||||||
#. name for mmr
|
#. name for mmr
|
||||||
msgid "Miao; Western Xiangxi"
|
msgid "Miao; Western Xiangxi"
|
||||||
msgstr ""
|
msgstr "Miao de Xiangxi occidental"
|
||||||
|
|
||||||
#. name for mmt
|
#. name for mmt
|
||||||
msgid "Malalamai"
|
msgid "Malalamai"
|
||||||
@ -17064,7 +17064,7 @@ msgstr ""
|
|||||||
|
|
||||||
#. name for muq
|
#. name for muq
|
||||||
msgid "Miao; Eastern Xiangxi"
|
msgid "Miao; Eastern Xiangxi"
|
||||||
msgstr ""
|
msgstr "Miao de Xiangxi oriental"
|
||||||
|
|
||||||
#. name for mur
|
#. name for mur
|
||||||
msgid "Murle"
|
msgid "Murle"
|
||||||
@ -22836,7 +22836,7 @@ msgstr ""
|
|||||||
|
|
||||||
#. name for sfm
|
#. name for sfm
|
||||||
msgid "Miao; Small Flowery"
|
msgid "Miao; Small Flowery"
|
||||||
msgstr ""
|
msgstr "Pequeño miao florido"
|
||||||
|
|
||||||
#. name for sfs
|
#. name for sfs
|
||||||
msgid "South African Sign Language"
|
msgid "South African Sign Language"
|
||||||
|
@ -4,7 +4,7 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
__appname__ = u'calibre'
|
__appname__ = u'calibre'
|
||||||
numeric_version = (0, 9, 14)
|
numeric_version = (0, 9, 15)
|
||||||
__version__ = u'.'.join(map(unicode, numeric_version))
|
__version__ = u'.'.join(map(unicode, numeric_version))
|
||||||
__author__ = u"Kovid Goyal <kovid@kovidgoyal.net>"
|
__author__ = u"Kovid Goyal <kovid@kovidgoyal.net>"
|
||||||
|
|
||||||
|
@ -1402,7 +1402,6 @@ class StoreEmpikStore(StoreBase):
|
|||||||
|
|
||||||
headquarters = 'PL'
|
headquarters = 'PL'
|
||||||
formats = ['EPUB', 'MOBI', 'PDF']
|
formats = ['EPUB', 'MOBI', 'PDF']
|
||||||
affiliate = True
|
|
||||||
|
|
||||||
class StoreEscapeMagazineStore(StoreBase):
|
class StoreEscapeMagazineStore(StoreBase):
|
||||||
name = 'EscapeMagazine'
|
name = 'EscapeMagazine'
|
||||||
@ -1471,9 +1470,9 @@ class StoreLegimiStore(StoreBase):
|
|||||||
affiliate = True
|
affiliate = True
|
||||||
|
|
||||||
class StoreLibreDEStore(StoreBase):
|
class StoreLibreDEStore(StoreBase):
|
||||||
name = 'Libri DE'
|
name = 'ebook.de'
|
||||||
author = 'Charles Haley'
|
author = 'Charles Haley'
|
||||||
description = u'Sicher Bücher, Hörbücher und Downloads online bestellen.'
|
description = u'All Ihre Bücher immer dabei. Suchen, finden, kaufen: so einfach wie nie. ebook.de war libre.de'
|
||||||
actual_plugin = 'calibre.gui2.store.stores.libri_de_plugin:LibreDEStore'
|
actual_plugin = 'calibre.gui2.store.stores.libri_de_plugin:LibreDEStore'
|
||||||
|
|
||||||
headquarters = 'DE'
|
headquarters = 'DE'
|
||||||
|
@ -33,7 +33,7 @@ class KOBO(USBMS):
|
|||||||
gui_name = 'Kobo Reader'
|
gui_name = 'Kobo Reader'
|
||||||
description = _('Communicate with the Kobo Reader')
|
description = _('Communicate with the Kobo Reader')
|
||||||
author = 'Timothy Legge and David Forrester'
|
author = 'Timothy Legge and David Forrester'
|
||||||
version = (2, 0, 4)
|
version = (2, 0, 5)
|
||||||
|
|
||||||
dbversion = 0
|
dbversion = 0
|
||||||
fwversion = 0
|
fwversion = 0
|
||||||
@ -1706,6 +1706,7 @@ class KOBOTOUCH(KOBO):
|
|||||||
def upload_books(self, files, names, on_card=None, end_session=True,
|
def upload_books(self, files, names, on_card=None, end_session=True,
|
||||||
metadata=None):
|
metadata=None):
|
||||||
debug_print('KoboTouch:upload_books - %d books'%(len(files)))
|
debug_print('KoboTouch:upload_books - %d books'%(len(files)))
|
||||||
|
debug_print('KoboTouch:upload_books - files=', files)
|
||||||
|
|
||||||
result = super(KOBOTOUCH, self).upload_books(files, names, on_card, end_session, metadata)
|
result = super(KOBOTOUCH, self).upload_books(files, names, on_card, end_session, metadata)
|
||||||
# debug_print('KoboTouch:upload_books - result=', result)
|
# debug_print('KoboTouch:upload_books - result=', result)
|
||||||
@ -1717,7 +1718,7 @@ class KOBOTOUCH(KOBO):
|
|||||||
'.kobo/KoboReader.sqlite'))) as connection:
|
'.kobo/KoboReader.sqlite'))) as connection:
|
||||||
connection.text_factory = lambda x: unicode(x, "utf-8", "ignore")
|
connection.text_factory = lambda x: unicode(x, "utf-8", "ignore")
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
query = "DELETE FROM content WHERE ContentID = ? AND Accessibility = 1 AND IsDownloaded = 'false'"
|
cleanup_query = "DELETE FROM content WHERE ContentID = ? AND Accessibility = 1 AND IsDownloaded = 'false'"
|
||||||
|
|
||||||
for fname, cycle in result:
|
for fname, cycle in result:
|
||||||
show_debug = self.is_debugging_title(fname)
|
show_debug = self.is_debugging_title(fname)
|
||||||
@ -1726,9 +1727,11 @@ class KOBOTOUCH(KOBO):
|
|||||||
debug_print('KoboTouch:upload_books: fname=', fname)
|
debug_print('KoboTouch:upload_books: fname=', fname)
|
||||||
debug_print('KoboTouch:upload_books: contentID=', contentID)
|
debug_print('KoboTouch:upload_books: contentID=', contentID)
|
||||||
|
|
||||||
t = (contentID,)
|
cleanup_values = (contentID,)
|
||||||
# debug_print('KoboTouch:upload_books: Delete record left if deleted on Touch')
|
# debug_print('KoboTouch:upload_books: Delete record left if deleted on Touch')
|
||||||
cursor.execute(query, t)
|
cursor.execute(cleanup_query, cleanup_values)
|
||||||
|
|
||||||
|
self.set_filesize_in_device_database(connection, contentID, fname)
|
||||||
|
|
||||||
connection.commit()
|
connection.commit()
|
||||||
|
|
||||||
@ -2183,6 +2186,43 @@ class KOBOTOUCH(KOBO):
|
|||||||
connection.commit()
|
connection.commit()
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
|
||||||
|
def set_filesize_in_device_database(self, connection, contentID, fpath):
|
||||||
|
show_debug = self.is_debugging_title(fpath)
|
||||||
|
if show_debug:
|
||||||
|
debug_print('KoboTouch:set_filesize_in_device_database contentID="%s"'%contentID)
|
||||||
|
|
||||||
|
test_query = 'SELECT ___FileSize ' \
|
||||||
|
'FROM content ' \
|
||||||
|
'WHERE ContentID = ? ' \
|
||||||
|
' AND ContentType = 6'
|
||||||
|
test_values = (contentID, )
|
||||||
|
|
||||||
|
updatequery = 'UPDATE content ' \
|
||||||
|
'SET ___FileSize = ? ' \
|
||||||
|
'WHERE ContentId = ? ' \
|
||||||
|
'AND ContentType = 6'
|
||||||
|
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute(test_query, test_values)
|
||||||
|
result = cursor.fetchone()
|
||||||
|
if result is None:
|
||||||
|
if show_debug:
|
||||||
|
debug_print(' Did not find a record - new book on device')
|
||||||
|
elif os.path.exists(fpath):
|
||||||
|
file_size = os.stat(self.normalize_path(fpath)).st_size
|
||||||
|
if show_debug:
|
||||||
|
debug_print(' Found a record - will update - ___FileSize=', result[0], ' file_size=', file_size)
|
||||||
|
if file_size != int(result[0]):
|
||||||
|
update_values = (file_size, contentID, )
|
||||||
|
cursor.execute(updatequery, update_values)
|
||||||
|
if show_debug:
|
||||||
|
debug_print(' Size updated.')
|
||||||
|
|
||||||
|
connection.commit()
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
# debug_print("KoboTouch:set_filesize_in_device_database - end")
|
||||||
|
|
||||||
def delete_empty_bookshelves(self, connection):
|
def delete_empty_bookshelves(self, connection):
|
||||||
debug_print("KoboTouch:delete_empty_bookshelves - start")
|
debug_print("KoboTouch:delete_empty_bookshelves - start")
|
||||||
|
|
||||||
@ -2353,10 +2393,17 @@ class KOBOTOUCH(KOBO):
|
|||||||
debug_print('KoboTouch:set_series book.series="%s"'%book.series)
|
debug_print('KoboTouch:set_series book.series="%s"'%book.series)
|
||||||
debug_print('KoboTouch:set_series book.series_index=', book.series_index)
|
debug_print('KoboTouch:set_series book.series_index=', book.series_index)
|
||||||
|
|
||||||
if book.series == book.kobo_series and book.series_index == book.kobo_series_number:
|
if book.series == book.kobo_series:
|
||||||
if show_debug:
|
kobo_series_number = None
|
||||||
debug_print('KoboTouch:set_series - series info the same - not changing')
|
if book.kobo_series_number is not None:
|
||||||
return
|
try:
|
||||||
|
kobo_series_number = float(book.kobo_series_number)
|
||||||
|
except:
|
||||||
|
kobo_series_number = None
|
||||||
|
if kobo_series_number == book.series_index:
|
||||||
|
if show_debug:
|
||||||
|
debug_print('KoboTouch:set_series - series info the same - not changing')
|
||||||
|
return
|
||||||
|
|
||||||
update_query = 'UPDATE content SET Series=?, SeriesNumber==? where BookID is Null and ContentID = ?'
|
update_query = 'UPDATE content SET Series=?, SeriesNumber==? where BookID is Null and ContentID = ?'
|
||||||
if book.series is None:
|
if book.series is None:
|
||||||
|
@ -919,6 +919,9 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
self.connection_attempts[peer] = 0
|
self.connection_attempts[peer] = 0
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
self.known_metadata = {}
|
||||||
|
self.known_uuids = {}
|
||||||
return True
|
return True
|
||||||
except socket.timeout:
|
except socket.timeout:
|
||||||
self._close_device_socket()
|
self._close_device_socket()
|
||||||
|
@ -58,9 +58,9 @@ class CHMInput(InputFormatPlugin):
|
|||||||
|
|
||||||
metadata = get_metadata_from_reader(self._chm_reader)
|
metadata = get_metadata_from_reader(self._chm_reader)
|
||||||
self._chm_reader.CloseCHM()
|
self._chm_reader.CloseCHM()
|
||||||
#print tdir
|
# print tdir, mainpath
|
||||||
#from calibre import ipython
|
# from calibre import ipython
|
||||||
#ipython()
|
# ipython()
|
||||||
|
|
||||||
options.debug_pipeline = None
|
options.debug_pipeline = None
|
||||||
options.input_encoding = 'utf-8'
|
options.input_encoding = 'utf-8'
|
||||||
@ -143,6 +143,8 @@ class CHMInput(InputFormatPlugin):
|
|||||||
|
|
||||||
def _create_html_root(self, hhcpath, log):
|
def _create_html_root(self, hhcpath, log):
|
||||||
from lxml import html
|
from lxml import html
|
||||||
|
from urllib import unquote as _unquote
|
||||||
|
from calibre.ebooks.oeb.base import urlquote
|
||||||
hhcdata = self._read_file(hhcpath)
|
hhcdata = self._read_file(hhcpath)
|
||||||
hhcroot = html.fromstring(hhcdata)
|
hhcroot = html.fromstring(hhcdata)
|
||||||
chapters = self._process_nodes(hhcroot)
|
chapters = self._process_nodes(hhcroot)
|
||||||
@ -152,23 +154,41 @@ class CHMInput(InputFormatPlugin):
|
|||||||
#print "============================="
|
#print "============================="
|
||||||
log.debug('Found %d section nodes' % len(chapters))
|
log.debug('Found %d section nodes' % len(chapters))
|
||||||
htmlpath = os.path.splitext(hhcpath)[0] + ".html"
|
htmlpath = os.path.splitext(hhcpath)[0] + ".html"
|
||||||
|
base = os.path.dirname(os.path.abspath(htmlpath))
|
||||||
|
|
||||||
|
def unquote(x):
|
||||||
|
if isinstance(x, unicode):
|
||||||
|
x = x.encode('utf-8')
|
||||||
|
return _unquote(x).decode('utf-8')
|
||||||
|
|
||||||
|
def unquote_path(x):
|
||||||
|
y = unquote(x)
|
||||||
|
if (not os.path.exists(os.path.join(base, x)) and
|
||||||
|
os.path.exists(os.path.join(base, y))):
|
||||||
|
x = y
|
||||||
|
return x
|
||||||
|
|
||||||
with open(htmlpath, 'wb') as f:
|
with open(htmlpath, 'wb') as f:
|
||||||
if chapters:
|
if chapters:
|
||||||
f.write('<html><head><meta http-equiv="Content-type"'
|
f.write('<html><head><meta http-equiv="Content-type"'
|
||||||
' content="text/html;charset=UTF-8" /></head><body>\n')
|
' content="text/html;charset=UTF-8" /></head><body>\n')
|
||||||
path0 = chapters[0][1]
|
path0 = chapters[0][1]
|
||||||
|
path0 = unquote_path(path0)
|
||||||
subpath = os.path.dirname(path0)
|
subpath = os.path.dirname(path0)
|
||||||
base = os.path.dirname(f.name)
|
base = os.path.dirname(f.name)
|
||||||
|
|
||||||
for chapter in chapters:
|
for chapter in chapters:
|
||||||
title = chapter[0]
|
title = chapter[0]
|
||||||
rsrcname = os.path.basename(chapter[1])
|
raw = unquote_path(chapter[1])
|
||||||
|
rsrcname = os.path.basename(raw)
|
||||||
rsrcpath = os.path.join(subpath, rsrcname)
|
rsrcpath = os.path.join(subpath, rsrcname)
|
||||||
if (not os.path.exists(os.path.join(base, rsrcpath)) and
|
if (not os.path.exists(os.path.join(base, rsrcpath)) and
|
||||||
os.path.exists(os.path.join(base, chapter[1]))):
|
os.path.exists(os.path.join(base, raw))):
|
||||||
rsrcpath = chapter[1]
|
rsrcpath = raw
|
||||||
|
|
||||||
# title should already be url encoded
|
# title should already be url encoded
|
||||||
|
if '%' not in rsrcpath:
|
||||||
|
rsrcpath = urlquote(rsrcpath)
|
||||||
url = "<br /><a href=" + rsrcpath + ">" + title + " </a>\n"
|
url = "<br /><a href=" + rsrcpath + ">" + title + " </a>\n"
|
||||||
if isinstance(url, unicode):
|
if isinstance(url, unicode):
|
||||||
url = url.encode('utf-8')
|
url = url.encode('utf-8')
|
||||||
|
@ -249,7 +249,10 @@ class MobiReader(object):
|
|||||||
head.insert(0, m)
|
head.insert(0, m)
|
||||||
if not title:
|
if not title:
|
||||||
title = head.makeelement('title', {})
|
title = head.makeelement('title', {})
|
||||||
title.text = self.book_header.title
|
try:
|
||||||
|
title.text = self.book_header.title
|
||||||
|
except ValueError:
|
||||||
|
title.text = clean_ascii_chars(self.book_header.title)
|
||||||
title.tail = '\n\t'
|
title.tail = '\n\t'
|
||||||
head.insert(0, title)
|
head.insert(0, title)
|
||||||
head.text = '\n\t'
|
head.text = '\n\t'
|
||||||
|
@ -519,6 +519,7 @@ class PluginUpdaterDialog(SizePersistedDialog):
|
|||||||
self.description.setFrameStyle(QFrame.Panel | QFrame.Sunken)
|
self.description.setFrameStyle(QFrame.Panel | QFrame.Sunken)
|
||||||
self.description.setAlignment(Qt.AlignTop | Qt.AlignLeft)
|
self.description.setAlignment(Qt.AlignTop | Qt.AlignLeft)
|
||||||
self.description.setMinimumHeight(40)
|
self.description.setMinimumHeight(40)
|
||||||
|
self.description.setWordWrap(True)
|
||||||
layout.addWidget(self.description)
|
layout.addWidget(self.description)
|
||||||
|
|
||||||
self.button_box = QDialogButtonBox(QDialogButtonBox.Close)
|
self.button_box = QDialogButtonBox(QDialogButtonBox.Close)
|
||||||
|
@ -7,9 +7,100 @@ __license__ = 'GPL 3'
|
|||||||
__copyright__ = '2011, John Schember <john@nachtimwald.com>'
|
__copyright__ = '2011, John Schember <john@nachtimwald.com>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
from calibre.gui2.store.stores.amazon_uk_plugin import AmazonUKKindleStore
|
from contextlib import closing
|
||||||
|
from lxml import html
|
||||||
|
|
||||||
class AmazonDEKindleStore(AmazonUKKindleStore):
|
from PyQt4.Qt import QUrl
|
||||||
|
|
||||||
|
from calibre.gui2.store import StorePlugin
|
||||||
|
from calibre import browser
|
||||||
|
from calibre.gui2 import open_url
|
||||||
|
from calibre.gui2.store.search_result import SearchResult
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# This class is copy/pasted from amason_uk_plugin. Do not modify it in any
|
||||||
|
# other amazon EU plugin. Be sure to paste it into all other amazon EU plugins
|
||||||
|
# when modified.
|
||||||
|
|
||||||
|
class AmazonEUBase(StorePlugin):
|
||||||
|
'''
|
||||||
|
For comments on the implementation, please see amazon_plugin.py
|
||||||
|
'''
|
||||||
|
|
||||||
|
def open(self, parent=None, detail_item=None, external=False):
|
||||||
|
|
||||||
|
store_link = self.store_link % self.aff_id
|
||||||
|
if detail_item:
|
||||||
|
self.aff_id['asin'] = detail_item
|
||||||
|
store_link = self.store_link_details % self.aff_id
|
||||||
|
open_url(QUrl(store_link))
|
||||||
|
|
||||||
|
def search(self, query, max_results=10, timeout=60):
|
||||||
|
url = self.search_url + query.encode('ascii', 'backslashreplace').replace('%', '%25').replace('\\x', '%').replace(' ', '+')
|
||||||
|
br = browser()
|
||||||
|
|
||||||
|
counter = max_results
|
||||||
|
with closing(br.open(url, timeout=timeout)) as f:
|
||||||
|
doc = html.fromstring(f.read())#.decode('latin-1', 'replace'))
|
||||||
|
|
||||||
|
data_xpath = '//div[contains(@class, "prod")]'
|
||||||
|
format_xpath = './/ul[contains(@class, "rsltL")]//span[contains(@class, "lrg") and not(contains(@class, "bld"))]/text()'
|
||||||
|
asin_xpath = '@name'
|
||||||
|
cover_xpath = './/img[@class="productImage"]/@src'
|
||||||
|
title_xpath = './/h3[@class="newaps"]/a//text()'
|
||||||
|
author_xpath = './/h3[@class="newaps"]//span[contains(@class, "reg")]/text()'
|
||||||
|
price_xpath = './/ul[contains(@class, "rsltL")]//span[contains(@class, "lrg") and contains(@class, "bld")]/text()'
|
||||||
|
|
||||||
|
for data in doc.xpath(data_xpath):
|
||||||
|
if counter <= 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Even though we are searching digital-text only Amazon will still
|
||||||
|
# put in results for non Kindle books (author pages). Se we need
|
||||||
|
# to explicitly check if the item is a Kindle book and ignore it
|
||||||
|
# if it isn't.
|
||||||
|
format_ = ''.join(data.xpath(format_xpath))
|
||||||
|
if 'kindle' not in format_.lower():
|
||||||
|
continue
|
||||||
|
|
||||||
|
# We must have an asin otherwise we can't easily reference the
|
||||||
|
# book later.
|
||||||
|
asin = data.xpath(asin_xpath)
|
||||||
|
if asin:
|
||||||
|
asin = asin[0]
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
cover_url = ''.join(data.xpath(cover_xpath))
|
||||||
|
|
||||||
|
title = ''.join(data.xpath(title_xpath))
|
||||||
|
author = ''.join(data.xpath(author_xpath))
|
||||||
|
try:
|
||||||
|
if self.author_article:
|
||||||
|
author = author.split(self.author_article, 1)[1].split(" (")[0]
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
price = ''.join(data.xpath(price_xpath))
|
||||||
|
|
||||||
|
counter -= 1
|
||||||
|
|
||||||
|
s = SearchResult()
|
||||||
|
s.cover_url = cover_url.strip()
|
||||||
|
s.title = title.strip()
|
||||||
|
s.author = author.strip()
|
||||||
|
s.price = price.strip()
|
||||||
|
s.detail_item = asin.strip()
|
||||||
|
s.drm = SearchResult.DRM_UNKNOWN
|
||||||
|
s.formats = 'Kindle'
|
||||||
|
|
||||||
|
yield s
|
||||||
|
|
||||||
|
def get_details(self, search_result, timeout):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class AmazonDEKindleStore(AmazonEUBase):
|
||||||
'''
|
'''
|
||||||
For comments on the implementation, please see amazon_plugin.py
|
For comments on the implementation, please see amazon_plugin.py
|
||||||
'''
|
'''
|
||||||
|
@ -7,9 +7,99 @@ __license__ = 'GPL 3'
|
|||||||
__copyright__ = '2011, John Schember <john@nachtimwald.com>'
|
__copyright__ = '2011, John Schember <john@nachtimwald.com>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
from calibre.gui2.store.stores.amazon_uk_plugin import AmazonUKKindleStore
|
from contextlib import closing
|
||||||
|
from lxml import html
|
||||||
|
|
||||||
class AmazonESKindleStore(AmazonUKKindleStore):
|
from PyQt4.Qt import QUrl
|
||||||
|
|
||||||
|
from calibre.gui2.store import StorePlugin
|
||||||
|
from calibre import browser
|
||||||
|
from calibre.gui2 import open_url
|
||||||
|
from calibre.gui2.store.search_result import SearchResult
|
||||||
|
|
||||||
|
|
||||||
|
# This class is copy/pasted from amason_uk_plugin. Do not modify it in any
|
||||||
|
# other amazon EU plugin. Be sure to paste it into all other amazon EU plugins
|
||||||
|
# when modified.
|
||||||
|
|
||||||
|
class AmazonEUBase(StorePlugin):
|
||||||
|
'''
|
||||||
|
For comments on the implementation, please see amazon_plugin.py
|
||||||
|
'''
|
||||||
|
|
||||||
|
def open(self, parent=None, detail_item=None, external=False):
|
||||||
|
|
||||||
|
store_link = self.store_link % self.aff_id
|
||||||
|
if detail_item:
|
||||||
|
self.aff_id['asin'] = detail_item
|
||||||
|
store_link = self.store_link_details % self.aff_id
|
||||||
|
open_url(QUrl(store_link))
|
||||||
|
|
||||||
|
def search(self, query, max_results=10, timeout=60):
|
||||||
|
url = self.search_url + query.encode('ascii', 'backslashreplace').replace('%', '%25').replace('\\x', '%').replace(' ', '+')
|
||||||
|
br = browser()
|
||||||
|
|
||||||
|
counter = max_results
|
||||||
|
with closing(br.open(url, timeout=timeout)) as f:
|
||||||
|
doc = html.fromstring(f.read())#.decode('latin-1', 'replace'))
|
||||||
|
|
||||||
|
data_xpath = '//div[contains(@class, "prod")]'
|
||||||
|
format_xpath = './/ul[contains(@class, "rsltL")]//span[contains(@class, "lrg") and not(contains(@class, "bld"))]/text()'
|
||||||
|
asin_xpath = '@name'
|
||||||
|
cover_xpath = './/img[@class="productImage"]/@src'
|
||||||
|
title_xpath = './/h3[@class="newaps"]/a//text()'
|
||||||
|
author_xpath = './/h3[@class="newaps"]//span[contains(@class, "reg")]/text()'
|
||||||
|
price_xpath = './/ul[contains(@class, "rsltL")]//span[contains(@class, "lrg") and contains(@class, "bld")]/text()'
|
||||||
|
|
||||||
|
for data in doc.xpath(data_xpath):
|
||||||
|
if counter <= 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Even though we are searching digital-text only Amazon will still
|
||||||
|
# put in results for non Kindle books (author pages). Se we need
|
||||||
|
# to explicitly check if the item is a Kindle book and ignore it
|
||||||
|
# if it isn't.
|
||||||
|
format_ = ''.join(data.xpath(format_xpath))
|
||||||
|
if 'kindle' not in format_.lower():
|
||||||
|
continue
|
||||||
|
|
||||||
|
# We must have an asin otherwise we can't easily reference the
|
||||||
|
# book later.
|
||||||
|
asin = data.xpath(asin_xpath)
|
||||||
|
if asin:
|
||||||
|
asin = asin[0]
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
cover_url = ''.join(data.xpath(cover_xpath))
|
||||||
|
|
||||||
|
title = ''.join(data.xpath(title_xpath))
|
||||||
|
author = ''.join(data.xpath(author_xpath))
|
||||||
|
try:
|
||||||
|
if self.author_article:
|
||||||
|
author = author.split(self.author_article, 1)[1].split(" (")[0]
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
price = ''.join(data.xpath(price_xpath))
|
||||||
|
|
||||||
|
counter -= 1
|
||||||
|
|
||||||
|
s = SearchResult()
|
||||||
|
s.cover_url = cover_url.strip()
|
||||||
|
s.title = title.strip()
|
||||||
|
s.author = author.strip()
|
||||||
|
s.price = price.strip()
|
||||||
|
s.detail_item = asin.strip()
|
||||||
|
s.drm = SearchResult.DRM_UNKNOWN
|
||||||
|
s.formats = 'Kindle'
|
||||||
|
|
||||||
|
yield s
|
||||||
|
|
||||||
|
def get_details(self, search_result, timeout):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class AmazonESKindleStore(AmazonEUBase):
|
||||||
'''
|
'''
|
||||||
For comments on the implementation, please see amazon_plugin.py
|
For comments on the implementation, please see amazon_plugin.py
|
||||||
'''
|
'''
|
||||||
|
@ -8,9 +8,100 @@ __copyright__ = '2011, John Schember <john@nachtimwald.com>'
|
|||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
|
||||||
from calibre.gui2.store.stores.amazon_uk_plugin import AmazonUKKindleStore
|
from contextlib import closing
|
||||||
|
from lxml import html
|
||||||
|
|
||||||
class AmazonFRKindleStore(AmazonUKKindleStore):
|
from PyQt4.Qt import QUrl
|
||||||
|
|
||||||
|
from calibre.gui2.store import StorePlugin
|
||||||
|
from calibre import browser
|
||||||
|
from calibre.gui2 import open_url
|
||||||
|
from calibre.gui2.store.search_result import SearchResult
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# This class is copy/pasted from amason_uk_plugin. Do not modify it in any
|
||||||
|
# other amazon EU plugin. Be sure to paste it into all other amazon EU plugins
|
||||||
|
# when modified.
|
||||||
|
|
||||||
|
class AmazonEUBase(StorePlugin):
|
||||||
|
'''
|
||||||
|
For comments on the implementation, please see amazon_plugin.py
|
||||||
|
'''
|
||||||
|
|
||||||
|
def open(self, parent=None, detail_item=None, external=False):
|
||||||
|
|
||||||
|
store_link = self.store_link % self.aff_id
|
||||||
|
if detail_item:
|
||||||
|
self.aff_id['asin'] = detail_item
|
||||||
|
store_link = self.store_link_details % self.aff_id
|
||||||
|
open_url(QUrl(store_link))
|
||||||
|
|
||||||
|
def search(self, query, max_results=10, timeout=60):
|
||||||
|
url = self.search_url + query.encode('ascii', 'backslashreplace').replace('%', '%25').replace('\\x', '%').replace(' ', '+')
|
||||||
|
br = browser()
|
||||||
|
|
||||||
|
counter = max_results
|
||||||
|
with closing(br.open(url, timeout=timeout)) as f:
|
||||||
|
doc = html.fromstring(f.read())#.decode('latin-1', 'replace'))
|
||||||
|
|
||||||
|
data_xpath = '//div[contains(@class, "prod")]'
|
||||||
|
format_xpath = './/ul[contains(@class, "rsltL")]//span[contains(@class, "lrg") and not(contains(@class, "bld"))]/text()'
|
||||||
|
asin_xpath = '@name'
|
||||||
|
cover_xpath = './/img[@class="productImage"]/@src'
|
||||||
|
title_xpath = './/h3[@class="newaps"]/a//text()'
|
||||||
|
author_xpath = './/h3[@class="newaps"]//span[contains(@class, "reg")]/text()'
|
||||||
|
price_xpath = './/ul[contains(@class, "rsltL")]//span[contains(@class, "lrg") and contains(@class, "bld")]/text()'
|
||||||
|
|
||||||
|
for data in doc.xpath(data_xpath):
|
||||||
|
if counter <= 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Even though we are searching digital-text only Amazon will still
|
||||||
|
# put in results for non Kindle books (author pages). Se we need
|
||||||
|
# to explicitly check if the item is a Kindle book and ignore it
|
||||||
|
# if it isn't.
|
||||||
|
format_ = ''.join(data.xpath(format_xpath))
|
||||||
|
if 'kindle' not in format_.lower():
|
||||||
|
continue
|
||||||
|
|
||||||
|
# We must have an asin otherwise we can't easily reference the
|
||||||
|
# book later.
|
||||||
|
asin = data.xpath(asin_xpath)
|
||||||
|
if asin:
|
||||||
|
asin = asin[0]
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
cover_url = ''.join(data.xpath(cover_xpath))
|
||||||
|
|
||||||
|
title = ''.join(data.xpath(title_xpath))
|
||||||
|
author = ''.join(data.xpath(author_xpath))
|
||||||
|
try:
|
||||||
|
if self.author_article:
|
||||||
|
author = author.split(self.author_article, 1)[1].split(" (")[0]
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
price = ''.join(data.xpath(price_xpath))
|
||||||
|
|
||||||
|
counter -= 1
|
||||||
|
|
||||||
|
s = SearchResult()
|
||||||
|
s.cover_url = cover_url.strip()
|
||||||
|
s.title = title.strip()
|
||||||
|
s.author = author.strip()
|
||||||
|
s.price = price.strip()
|
||||||
|
s.detail_item = asin.strip()
|
||||||
|
s.drm = SearchResult.DRM_UNKNOWN
|
||||||
|
s.formats = 'Kindle'
|
||||||
|
|
||||||
|
yield s
|
||||||
|
|
||||||
|
def get_details(self, search_result, timeout):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class AmazonFRKindleStore(AmazonEUBase):
|
||||||
'''
|
'''
|
||||||
For comments on the implementation, please see amazon_plugin.py
|
For comments on the implementation, please see amazon_plugin.py
|
||||||
'''
|
'''
|
||||||
|
@ -7,9 +7,100 @@ __license__ = 'GPL 3'
|
|||||||
__copyright__ = '2011, John Schember <john@nachtimwald.com>'
|
__copyright__ = '2011, John Schember <john@nachtimwald.com>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
from calibre.gui2.store.stores.amazon_uk_plugin import AmazonUKKindleStore
|
from contextlib import closing
|
||||||
|
from lxml import html
|
||||||
|
|
||||||
class AmazonITKindleStore(AmazonUKKindleStore):
|
from PyQt4.Qt import QUrl
|
||||||
|
|
||||||
|
from calibre.gui2.store import StorePlugin
|
||||||
|
from calibre import browser
|
||||||
|
from calibre.gui2 import open_url
|
||||||
|
from calibre.gui2.store.search_result import SearchResult
|
||||||
|
|
||||||
|
|
||||||
|
# This class is copy/pasted from amason_uk_plugin. Do not modify it in any
|
||||||
|
# other amazon EU plugin. Be sure to paste it into all other amazon EU plugins
|
||||||
|
# when modified.
|
||||||
|
|
||||||
|
class AmazonEUBase(StorePlugin):
|
||||||
|
'''
|
||||||
|
For comments on the implementation, please see amazon_plugin.py
|
||||||
|
'''
|
||||||
|
|
||||||
|
def open(self, parent=None, detail_item=None, external=False):
|
||||||
|
|
||||||
|
store_link = self.store_link % self.aff_id
|
||||||
|
if detail_item:
|
||||||
|
self.aff_id['asin'] = detail_item
|
||||||
|
store_link = self.store_link_details % self.aff_id
|
||||||
|
open_url(QUrl(store_link))
|
||||||
|
|
||||||
|
def search(self, query, max_results=10, timeout=60):
|
||||||
|
url = self.search_url + query.encode('ascii', 'backslashreplace').replace('%', '%25').replace('\\x', '%').replace(' ', '+')
|
||||||
|
br = browser()
|
||||||
|
|
||||||
|
counter = max_results
|
||||||
|
with closing(br.open(url, timeout=timeout)) as f:
|
||||||
|
doc = html.fromstring(f.read())#.decode('latin-1', 'replace'))
|
||||||
|
|
||||||
|
data_xpath = '//div[contains(@class, "prod")]'
|
||||||
|
format_xpath = './/ul[contains(@class, "rsltL")]//span[contains(@class, "lrg") and not(contains(@class, "bld"))]/text()'
|
||||||
|
asin_xpath = '@name'
|
||||||
|
cover_xpath = './/img[@class="productImage"]/@src'
|
||||||
|
title_xpath = './/h3[@class="newaps"]/a//text()'
|
||||||
|
author_xpath = './/h3[@class="newaps"]//span[contains(@class, "reg")]/text()'
|
||||||
|
price_xpath = './/ul[contains(@class, "rsltL")]//span[contains(@class, "lrg") and contains(@class, "bld")]/text()'
|
||||||
|
|
||||||
|
for data in doc.xpath(data_xpath):
|
||||||
|
if counter <= 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Even though we are searching digital-text only Amazon will still
|
||||||
|
# put in results for non Kindle books (author pages). Se we need
|
||||||
|
# to explicitly check if the item is a Kindle book and ignore it
|
||||||
|
# if it isn't.
|
||||||
|
format_ = ''.join(data.xpath(format_xpath))
|
||||||
|
if 'kindle' not in format_.lower():
|
||||||
|
continue
|
||||||
|
|
||||||
|
# We must have an asin otherwise we can't easily reference the
|
||||||
|
# book later.
|
||||||
|
asin = data.xpath(asin_xpath)
|
||||||
|
if asin:
|
||||||
|
asin = asin[0]
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
cover_url = ''.join(data.xpath(cover_xpath))
|
||||||
|
|
||||||
|
title = ''.join(data.xpath(title_xpath))
|
||||||
|
author = ''.join(data.xpath(author_xpath))
|
||||||
|
try:
|
||||||
|
if self.author_article:
|
||||||
|
author = author.split(self.author_article, 1)[1].split(" (")[0]
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
price = ''.join(data.xpath(price_xpath))
|
||||||
|
|
||||||
|
counter -= 1
|
||||||
|
|
||||||
|
s = SearchResult()
|
||||||
|
s.cover_url = cover_url.strip()
|
||||||
|
s.title = title.strip()
|
||||||
|
s.author = author.strip()
|
||||||
|
s.price = price.strip()
|
||||||
|
s.detail_item = asin.strip()
|
||||||
|
s.drm = SearchResult.DRM_UNKNOWN
|
||||||
|
s.formats = 'Kindle'
|
||||||
|
|
||||||
|
yield s
|
||||||
|
|
||||||
|
def get_details(self, search_result, timeout):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AmazonITKindleStore(AmazonEUBase):
|
||||||
'''
|
'''
|
||||||
For comments on the implementation, please see amazon_plugin.py
|
For comments on the implementation, please see amazon_plugin.py
|
||||||
'''
|
'''
|
||||||
|
@ -8,7 +8,6 @@ __copyright__ = '2011, John Schember <john@nachtimwald.com>'
|
|||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
import random
|
import random
|
||||||
import re
|
|
||||||
from contextlib import closing
|
from contextlib import closing
|
||||||
|
|
||||||
from lxml import html
|
from lxml import html
|
||||||
@ -131,7 +130,7 @@ class AmazonKindleStore(StorePlugin):
|
|||||||
|
|
||||||
data_xpath = '//div[contains(@class, "prod")]'
|
data_xpath = '//div[contains(@class, "prod")]'
|
||||||
format_xpath = './/ul[contains(@class, "rsltL")]//span[contains(@class, "lrg") and not(contains(@class, "bld"))]/text()'
|
format_xpath = './/ul[contains(@class, "rsltL")]//span[contains(@class, "lrg") and not(contains(@class, "bld"))]/text()'
|
||||||
asin_xpath = './/div[@class="image"]/a[1]'
|
asin_xpath = '@name'
|
||||||
cover_xpath = './/img[@class="productImage"]/@src'
|
cover_xpath = './/img[@class="productImage"]/@src'
|
||||||
title_xpath = './/h3[@class="newaps"]/a//text()'
|
title_xpath = './/h3[@class="newaps"]/a//text()'
|
||||||
author_xpath = './/h3[@class="newaps"]//span[contains(@class, "reg")]/text()'
|
author_xpath = './/h3[@class="newaps"]//span[contains(@class, "reg")]/text()'
|
||||||
@ -151,15 +150,9 @@ class AmazonKindleStore(StorePlugin):
|
|||||||
|
|
||||||
# We must have an asin otherwise we can't easily reference the
|
# We must have an asin otherwise we can't easily reference the
|
||||||
# book later.
|
# book later.
|
||||||
asin_href = None
|
asin = data.xpath(asin_xpath)
|
||||||
asin_a = data.xpath(asin_xpath)
|
if asin:
|
||||||
if asin_a:
|
asin = asin[0]
|
||||||
asin_href = asin_a[0].get('href', '')
|
|
||||||
m = re.search(r'/dp/(?P<asin>.+?)(/|$)', asin_href)
|
|
||||||
if m:
|
|
||||||
asin = m.group('asin')
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -7,8 +7,6 @@ __license__ = 'GPL 3'
|
|||||||
__copyright__ = '2011, John Schember <john@nachtimwald.com>'
|
__copyright__ = '2011, John Schember <john@nachtimwald.com>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
import re
|
|
||||||
|
|
||||||
from contextlib import closing
|
from contextlib import closing
|
||||||
from lxml import html
|
from lxml import html
|
||||||
|
|
||||||
@ -19,19 +17,12 @@ from calibre.gui2 import open_url
|
|||||||
from calibre.gui2.store import StorePlugin
|
from calibre.gui2.store import StorePlugin
|
||||||
from calibre.gui2.store.search_result import SearchResult
|
from calibre.gui2.store.search_result import SearchResult
|
||||||
|
|
||||||
class AmazonUKKindleStore(StorePlugin):
|
|
||||||
aff_id = {'tag': 'calcharles-21'}
|
|
||||||
store_link = ('http://www.amazon.co.uk/gp/redirect.html?ie=UTF8&'
|
|
||||||
'location=http://www.amazon.co.uk/Kindle-eBooks/b?'
|
|
||||||
'ie=UTF8&node=341689031&ref_=sa_menu_kbo2&tag=%(tag)s&'
|
|
||||||
'linkCode=ur2&camp=1634&creative=19450')
|
|
||||||
store_link_details = ('http://www.amazon.co.uk/gp/redirect.html?ie=UTF8&'
|
|
||||||
'location=http://www.amazon.co.uk/dp/%(asin)s&tag=%(tag)s&'
|
|
||||||
'linkCode=ur2&camp=1634&creative=6738')
|
|
||||||
search_url = 'http://www.amazon.co.uk/s/?url=search-alias%3Ddigital-text&field-keywords='
|
|
||||||
|
|
||||||
author_article = 'by '
|
# This class is copy/pasted from amason_uk_plugin. Do not modify it in any
|
||||||
|
# other amazon EU plugin. Be sure to paste it into all other amazon EU plugins
|
||||||
|
# when modified.
|
||||||
|
|
||||||
|
class AmazonEUBase(StorePlugin):
|
||||||
'''
|
'''
|
||||||
For comments on the implementation, please see amazon_plugin.py
|
For comments on the implementation, please see amazon_plugin.py
|
||||||
'''
|
'''
|
||||||
@ -54,7 +45,7 @@ class AmazonUKKindleStore(StorePlugin):
|
|||||||
|
|
||||||
data_xpath = '//div[contains(@class, "prod")]'
|
data_xpath = '//div[contains(@class, "prod")]'
|
||||||
format_xpath = './/ul[contains(@class, "rsltL")]//span[contains(@class, "lrg") and not(contains(@class, "bld"))]/text()'
|
format_xpath = './/ul[contains(@class, "rsltL")]//span[contains(@class, "lrg") and not(contains(@class, "bld"))]/text()'
|
||||||
asin_xpath = './/div[@class="image"]/a[1]'
|
asin_xpath = '@name'
|
||||||
cover_xpath = './/img[@class="productImage"]/@src'
|
cover_xpath = './/img[@class="productImage"]/@src'
|
||||||
title_xpath = './/h3[@class="newaps"]/a//text()'
|
title_xpath = './/h3[@class="newaps"]/a//text()'
|
||||||
author_xpath = './/h3[@class="newaps"]//span[contains(@class, "reg")]/text()'
|
author_xpath = './/h3[@class="newaps"]//span[contains(@class, "reg")]/text()'
|
||||||
@ -74,15 +65,9 @@ class AmazonUKKindleStore(StorePlugin):
|
|||||||
|
|
||||||
# We must have an asin otherwise we can't easily reference the
|
# We must have an asin otherwise we can't easily reference the
|
||||||
# book later.
|
# book later.
|
||||||
asin_href = None
|
asin = data.xpath(asin_xpath)
|
||||||
asin_a = data.xpath(asin_xpath)
|
if asin:
|
||||||
if asin_a:
|
asin = asin[0]
|
||||||
asin_href = asin_a[0].get('href', '')
|
|
||||||
m = re.search(r'/dp/(?P<asin>.+?)(/|$)', asin_href)
|
|
||||||
if m:
|
|
||||||
asin = m.group('asin')
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@ -113,3 +98,17 @@ class AmazonUKKindleStore(StorePlugin):
|
|||||||
|
|
||||||
def get_details(self, search_result, timeout):
|
def get_details(self, search_result, timeout):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class AmazonUKKindleStore(AmazonEUBase):
|
||||||
|
aff_id = {'tag': 'calcharles-21'}
|
||||||
|
store_link = ('http://www.amazon.co.uk/gp/redirect.html?ie=UTF8&'
|
||||||
|
'location=http://www.amazon.co.uk/Kindle-eBooks/b?'
|
||||||
|
'ie=UTF8&node=341689031&ref_=sa_menu_kbo2&tag=%(tag)s&'
|
||||||
|
'linkCode=ur2&camp=1634&creative=19450')
|
||||||
|
store_link_details = ('http://www.amazon.co.uk/gp/redirect.html?ie=UTF8&'
|
||||||
|
'location=http://www.amazon.co.uk/dp/%(asin)s&tag=%(tag)s&'
|
||||||
|
'linkCode=ur2&camp=1634&creative=6738')
|
||||||
|
search_url = 'http://www.amazon.co.uk/s/?url=search-alias%3Ddigital-text&field-keywords='
|
||||||
|
|
||||||
|
author_article = 'by '
|
||||||
|
|
||||||
|
@ -25,17 +25,12 @@ from calibre.gui2.store.web_store_dialog import WebStoreDialog
|
|||||||
class EmpikStore(BasicStoreConfig, StorePlugin):
|
class EmpikStore(BasicStoreConfig, StorePlugin):
|
||||||
|
|
||||||
def open(self, parent=None, detail_item=None, external=False):
|
def open(self, parent=None, detail_item=None, external=False):
|
||||||
plain_url = 'http://www.empik.com/ebooki'
|
url = 'http://www.empik.com/ebooki'
|
||||||
url = 'https://ssl.afiliant.com/affskrypt,,2f9de2,,23c7f,,,?u=(' + plain_url + ')'
|
|
||||||
detail_url = None
|
|
||||||
|
|
||||||
if detail_item:
|
|
||||||
detail_url = 'https://ssl.afiliant.com/affskrypt,,2f9de2,,23c7f,,,?u=(' + detail_item + ')'
|
|
||||||
|
|
||||||
if external or self.config.get('open_external', False):
|
if external or self.config.get('open_external', False):
|
||||||
open_url(QUrl(url_slash_cleaner(detail_url if detail_url else url)))
|
open_url(QUrl(url_slash_cleaner(detail_item if detail_item else url)))
|
||||||
else:
|
else:
|
||||||
d = WebStoreDialog(self.gui, url, parent, detail_url)
|
d = WebStoreDialog(self.gui, url, parent, detail_item)
|
||||||
d.setWindowTitle(self.name)
|
d.setWindowTitle(self.name)
|
||||||
d.set_tags(self.config.get('tags', ''))
|
d.set_tags(self.config.get('tags', ''))
|
||||||
d.exec_()
|
d.exec_()
|
||||||
|
@ -41,7 +41,7 @@ class WaterstonesUKStore(BasicStoreConfig, StorePlugin):
|
|||||||
d.exec_()
|
d.exec_()
|
||||||
|
|
||||||
def search(self, query, max_results=10, timeout=60):
|
def search(self, query, max_results=10, timeout=60):
|
||||||
url = 'http://www.waterstones.com/waterstonesweb/advancedSearch.do?buttonClicked=1&format=3757&bookkeywords=' + urllib2.quote(query)
|
url = 'http://www.waterstones.com/waterstonesweb/simpleSearch.do?simpleSearchString=ebook+' + urllib2.quote(query)
|
||||||
|
|
||||||
br = browser()
|
br = browser()
|
||||||
|
|
||||||
@ -56,6 +56,8 @@ class WaterstonesUKStore(BasicStoreConfig, StorePlugin):
|
|||||||
if not id:
|
if not id:
|
||||||
continue
|
continue
|
||||||
cover_url = ''.join(data.xpath('.//div[@class="image"]/a/img/@src'))
|
cover_url = ''.join(data.xpath('.//div[@class="image"]/a/img/@src'))
|
||||||
|
if not cover_url.startswith("http"):
|
||||||
|
cover_url = 'http://www.waterstones.com' + cover_url
|
||||||
title = ''.join(data.xpath('./div/div/h2/a/text()'))
|
title = ''.join(data.xpath('./div/div/h2/a/text()'))
|
||||||
author = ', '.join(data.xpath('.//p[@class="byAuthor"]/a/text()'))
|
author = ', '.join(data.xpath('.//p[@class="byAuthor"]/a/text()'))
|
||||||
price = ''.join(data.xpath('.//p[@class="price"]/span[@class="priceRed2"]/text()'))
|
price = ''.join(data.xpath('.//p[@class="price"]/span[@class="priceRed2"]/text()'))
|
||||||
|
@ -70,6 +70,7 @@ def config(defaults=None):
|
|||||||
c.add_opt('bottom_margin', default=20)
|
c.add_opt('bottom_margin', default=20)
|
||||||
c.add_opt('text_color', default=None)
|
c.add_opt('text_color', default=None)
|
||||||
c.add_opt('background_color', default=None)
|
c.add_opt('background_color', default=None)
|
||||||
|
c.add_opt('show_controls', default=True)
|
||||||
|
|
||||||
fonts = c.add_group('FONTS', _('Font options'))
|
fonts = c.add_group('FONTS', _('Font options'))
|
||||||
fonts('serif_family', default='Times New Roman' if iswindows else 'Liberation Serif',
|
fonts('serif_family', default='Times New Roman' if iswindows else 'Liberation Serif',
|
||||||
@ -221,6 +222,7 @@ class ConfigDialog(QDialog, Ui_Dialog):
|
|||||||
for x in ('text', 'background'):
|
for x in ('text', 'background'):
|
||||||
setattr(self, 'current_%s_color'%x, getattr(opts, '%s_color'%x))
|
setattr(self, 'current_%s_color'%x, getattr(opts, '%s_color'%x))
|
||||||
self.update_sample_colors()
|
self.update_sample_colors()
|
||||||
|
self.opt_show_controls.setChecked(opts.show_controls)
|
||||||
|
|
||||||
def change_color(self, which, reset=False):
|
def change_color(self, which, reset=False):
|
||||||
if reset:
|
if reset:
|
||||||
@ -292,6 +294,7 @@ class ConfigDialog(QDialog, Ui_Dialog):
|
|||||||
self.opt_override_book_margins.isChecked())
|
self.opt_override_book_margins.isChecked())
|
||||||
c.set('text_color', self.current_text_color)
|
c.set('text_color', self.current_text_color)
|
||||||
c.set('background_color', self.current_background_color)
|
c.set('background_color', self.current_background_color)
|
||||||
|
c.set('show_controls', self.opt_show_controls.isChecked())
|
||||||
for x in ('top', 'bottom', 'side'):
|
for x in ('top', 'bottom', 'side'):
|
||||||
c.set(x+'_margin', int(getattr(self, 'opt_%s_margin'%x).value()))
|
c.set(x+'_margin', int(getattr(self, 'opt_%s_margin'%x).value()))
|
||||||
|
|
||||||
|
@ -347,8 +347,8 @@ QToolBox::tab:hover {
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>811</width>
|
<width>352</width>
|
||||||
<height>352</height>
|
<height>176</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<attribute name="label">
|
<attribute name="label">
|
||||||
@ -573,8 +573,8 @@ QToolBox::tab:hover {
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>352</width>
|
<width>811</width>
|
||||||
<height>123</height>
|
<height>352</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<attribute name="label">
|
<attribute name="label">
|
||||||
@ -605,20 +605,27 @@ QToolBox::tab:hover {
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0" colspan="2">
|
<item row="3" column="0" colspan="2">
|
||||||
<widget class="QCheckBox" name="opt_remember_window_size">
|
<widget class="QCheckBox" name="opt_remember_window_size">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Remember last used &window size and layout</string>
|
<string>Remember last used &window size and layout</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0" colspan="2">
|
<item row="4" column="0" colspan="2">
|
||||||
<widget class="QCheckBox" name="opt_remember_current_page">
|
<widget class="QCheckBox" name="opt_remember_current_page">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Remember the &current page when quitting</string>
|
<string>Remember the &current page when quitting</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="2" column="0" colspan="2">
|
||||||
|
<widget class="QCheckBox" name="opt_show_controls">
|
||||||
|
<property name="text">
|
||||||
|
<string>Show &controls in the viewer window</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
|
@ -33,6 +33,7 @@ class Document(QWebPage): # {{{
|
|||||||
|
|
||||||
page_turn = pyqtSignal(object)
|
page_turn = pyqtSignal(object)
|
||||||
mark_element = pyqtSignal(QWebElement)
|
mark_element = pyqtSignal(QWebElement)
|
||||||
|
settings_changed = pyqtSignal()
|
||||||
|
|
||||||
def set_font_settings(self, opts):
|
def set_font_settings(self, opts):
|
||||||
settings = self.settings()
|
settings = self.settings()
|
||||||
@ -57,6 +58,7 @@ class Document(QWebPage): # {{{
|
|||||||
self.set_font_settings(opts)
|
self.set_font_settings(opts)
|
||||||
self.set_user_stylesheet(opts)
|
self.set_user_stylesheet(opts)
|
||||||
self.misc_config(opts)
|
self.misc_config(opts)
|
||||||
|
self.settings_changed.emit()
|
||||||
self.after_load()
|
self.after_load()
|
||||||
|
|
||||||
def __init__(self, shortcuts, parent=None, debug_javascript=False):
|
def __init__(self, shortcuts, parent=None, debug_javascript=False):
|
||||||
@ -153,6 +155,7 @@ class Document(QWebPage): # {{{
|
|||||||
self.cols_per_screen = opts.cols_per_screen
|
self.cols_per_screen = opts.cols_per_screen
|
||||||
self.side_margin = opts.side_margin
|
self.side_margin = opts.side_margin
|
||||||
self.top_margin, self.bottom_margin = opts.top_margin, opts.bottom_margin
|
self.top_margin, self.bottom_margin = opts.top_margin, opts.bottom_margin
|
||||||
|
self.show_controls = opts.show_controls
|
||||||
|
|
||||||
def fit_images(self):
|
def fit_images(self):
|
||||||
if self.do_fit_images and not self.in_paged_mode:
|
if self.do_fit_images and not self.in_paged_mode:
|
||||||
@ -676,7 +679,7 @@ class DocumentView(QWebView): # {{{
|
|||||||
|
|
||||||
if not text and img.isNull() and self.manager is not None:
|
if not text and img.isNull() and self.manager is not None:
|
||||||
menu.addSeparator()
|
menu.addSeparator()
|
||||||
if self.document.in_fullscreen_mode and self.manager is not None:
|
if (not self.document.show_controls or self.document.in_fullscreen_mode) and self.manager is not None:
|
||||||
menu.addAction(self.manager.toggle_toolbar_action)
|
menu.addAction(self.manager.toggle_toolbar_action)
|
||||||
menu.addAction(self.manager.action_full_screen)
|
menu.addAction(self.manager.action_full_screen)
|
||||||
|
|
||||||
|
@ -303,6 +303,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
|||||||
self.toggle_toolbar_action = QAction(_('Show/hide controls'), self)
|
self.toggle_toolbar_action = QAction(_('Show/hide controls'), self)
|
||||||
self.toggle_toolbar_action.setCheckable(True)
|
self.toggle_toolbar_action.setCheckable(True)
|
||||||
self.toggle_toolbar_action.triggered.connect(self.toggle_toolbars)
|
self.toggle_toolbar_action.triggered.connect(self.toggle_toolbars)
|
||||||
|
self.toolbar_hidden = None
|
||||||
self.addAction(self.toggle_toolbar_action)
|
self.addAction(self.toggle_toolbar_action)
|
||||||
self.full_screen_label_anim = QPropertyAnimation(
|
self.full_screen_label_anim = QPropertyAnimation(
|
||||||
self.full_screen_label, 'size')
|
self.full_screen_label, 'size')
|
||||||
@ -359,7 +360,10 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
|||||||
# continue to function even when the toolbars are hidden
|
# continue to function even when the toolbars are hidden
|
||||||
self.addAction(action)
|
self.addAction(action)
|
||||||
|
|
||||||
|
self.view.document.settings_changed.connect(self.settings_changed)
|
||||||
|
|
||||||
self.restore_state()
|
self.restore_state()
|
||||||
|
self.settings_changed()
|
||||||
self.action_toggle_paged_mode.toggled[bool].connect(self.toggle_paged_mode)
|
self.action_toggle_paged_mode.toggled[bool].connect(self.toggle_paged_mode)
|
||||||
if (start_in_fullscreen or self.view.document.start_in_fullscreen):
|
if (start_in_fullscreen or self.view.document.start_in_fullscreen):
|
||||||
self.action_full_screen.trigger()
|
self.action_full_screen.trigger()
|
||||||
@ -373,6 +377,11 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
|||||||
if at_start: return
|
if at_start: return
|
||||||
self.reload()
|
self.reload()
|
||||||
|
|
||||||
|
def settings_changed(self):
|
||||||
|
for x in ('', '2'):
|
||||||
|
x = getattr(self, 'tool_bar'+x)
|
||||||
|
x.setVisible(self.view.document.show_controls)
|
||||||
|
|
||||||
def reload(self):
|
def reload(self):
|
||||||
if hasattr(self, 'current_index') and self.current_index > -1:
|
if hasattr(self, 'current_index') and self.current_index > -1:
|
||||||
self.view.document.page_position.save(overwrite=False)
|
self.view.document.page_position.save(overwrite=False)
|
||||||
@ -575,8 +584,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
|||||||
self.vertical_scrollbar.setVisible(True)
|
self.vertical_scrollbar.setVisible(True)
|
||||||
self.window_mode_changed = 'normal'
|
self.window_mode_changed = 'normal'
|
||||||
self.esc_full_screen_action.setEnabled(False)
|
self.esc_full_screen_action.setEnabled(False)
|
||||||
self.tool_bar.setVisible(True)
|
self.settings_changed()
|
||||||
self.tool_bar2.setVisible(True)
|
|
||||||
self.full_screen_label.setVisible(False)
|
self.full_screen_label.setVisible(False)
|
||||||
if hasattr(self, '_original_frame_margins'):
|
if hasattr(self, '_original_frame_margins'):
|
||||||
om = self._original_frame_margins
|
om = self._original_frame_margins
|
||||||
@ -758,7 +766,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
|||||||
self.view.scroll_to(frag)
|
self.view.scroll_to(frag)
|
||||||
else:
|
else:
|
||||||
# Scroll to top
|
# Scroll to top
|
||||||
self.view.scroll_to('#')
|
self.view.scroll_to(0)
|
||||||
if self.view.document.ypos == oldpos:
|
if self.view.document.ypos == oldpos:
|
||||||
# If we are coming from goto_next_section() call this will
|
# If we are coming from goto_next_section() call this will
|
||||||
# cause another goto next section call with the next toc
|
# cause another goto next section call with the next toc
|
||||||
|
@ -372,8 +372,10 @@ class BrowseServer(object):
|
|||||||
if meta['is_custom'] and category not in displayed_custom_fields:
|
if meta['is_custom'] and category not in displayed_custom_fields:
|
||||||
continue
|
continue
|
||||||
# get the icon files
|
# get the icon files
|
||||||
if category in self.icon_map:
|
main_cat = (category.partition('.')[0]) if hasattr(category,
|
||||||
icon = '_'+quote(self.icon_map[category])
|
'partition') else category
|
||||||
|
if main_cat in self.icon_map:
|
||||||
|
icon = '_'+quote(self.icon_map[main_cat])
|
||||||
elif category in category_icon_map:
|
elif category in category_icon_map:
|
||||||
icon = category_icon_map[category]
|
icon = category_icon_map[category]
|
||||||
elif meta['is_custom']:
|
elif meta['is_custom']:
|
||||||
@ -894,7 +896,8 @@ class BrowseServer(object):
|
|||||||
@Endpoint()
|
@Endpoint()
|
||||||
def browse_random(self, *args, **kwargs):
|
def browse_random(self, *args, **kwargs):
|
||||||
import random
|
import random
|
||||||
book_id = random.choice(tuple(self.db.all_ids()))
|
book_id = random.choice(self.db.search_getting_ids(
|
||||||
|
'', self.search_restriction))
|
||||||
ans = self.browse_render_details(book_id)
|
ans = self.browse_render_details(book_id)
|
||||||
return self.browse_template('').format(
|
return self.browse_template('').format(
|
||||||
title='', script='book();', main=ans)
|
title='', script='book();', main=ans)
|
||||||
|
@ -77,7 +77,7 @@ def build_navigation(start, num, total, url_base): # {{{
|
|||||||
right_buttons = TD(CLASS('button', style='text-align:right'))
|
right_buttons = TD(CLASS('button', style='text-align:right'))
|
||||||
|
|
||||||
if start > 1:
|
if start > 1:
|
||||||
for t,s in [('First', 1), ('Previous', max(start-(num+1),1))]:
|
for t,s in [('First', 1), ('Previous', max(start-num,1))]:
|
||||||
left_buttons.append(A(t, href='%s;start=%d'%(url_base, s)))
|
left_buttons.append(A(t, href='%s;start=%d'%(url_base, s)))
|
||||||
|
|
||||||
if total > start + num:
|
if total > start + num:
|
||||||
|
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
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