mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
detab gui2.ui
This commit is contained in:
commit
e266737928
@ -4,6 +4,85 @@
|
||||
# for important features/bug fixes.
|
||||
# Also, each release can have new and improved recipes.
|
||||
|
||||
- version: 0.6.44
|
||||
date: 2010-03-05
|
||||
|
||||
new features:
|
||||
- title: "Experimental support for conversion of CHM files"
|
||||
type: major
|
||||
description : >
|
||||
"Conversion and reading of metadata from CHM files is now supported. This feature is
|
||||
still experimental, with more testing needed. Building from source on linux now
|
||||
requires chmlib."
|
||||
|
||||
- title: "Experimental support for fetching annotations from the Kindles"
|
||||
type: major
|
||||
description: >
|
||||
"calibre can now fetch annotations from your kindle and put them into the
|
||||
comments field. To fetch annotations, click the arrow next to the
|
||||
'send to device' button and select 'Fetch Annotations', with your Kindle
|
||||
connected."
|
||||
|
||||
- title: "Support FreeBSD out of the box (except USB)"
|
||||
type: major
|
||||
tickets: [4715]
|
||||
|
||||
|
||||
- title: "News download scheduler: Don't try to download news when no active internet connection is present (linux/windows only)"
|
||||
|
||||
- title: "EPUB to WPUB conversion: Preserve font encryption"
|
||||
|
||||
- title: "calibre-server: Add --pidfile and --daemonize (unix only) options"
|
||||
|
||||
- title: "Plugins: When loading a plugin zip file extract to temp dir and add to sys.path, if the zip file contains binay code (pyd/dll/so/dylib), instead of just adding the zip file to the path, as python cannot load compiled code from a zip file"
|
||||
|
||||
|
||||
|
||||
bug fixes:
|
||||
- title: "Ebook-viewer: Handle non-ascii CSS files when doing font substitutions"
|
||||
|
||||
- title: "Conversion pipline: Ignore non-integral play orders when parsing NCX files"
|
||||
|
||||
- title: "When decoding NCX toc files, if no encoding is declared and detection has less that 100% confidence, assume UTF-8."
|
||||
tickets: [5039]
|
||||
|
||||
- title: "PML chapter definitions missing from toc.ncx"
|
||||
tickets: [4990]
|
||||
|
||||
- title: "Unicode string for cover causes calibredb --output-format stanza to fail"
|
||||
ticket: [5035]
|
||||
|
||||
- title: "Search cover:False fails, cover:True succeeds"
|
||||
tickets: [5034]
|
||||
|
||||
- title: "Plugins: correctly use context"
|
||||
|
||||
- title: "MOBI Input: Don't lose cover if it is also referred to in main text"
|
||||
ticket: [5020]
|
||||
|
||||
- title: "RTF Output: Don't choke on PNG images"
|
||||
|
||||
new recipes:
|
||||
- title: Journal of Hospital Medicine, San Francisco Bay Guardian, Smithsonian Magazine
|
||||
author: Krittika Goyal
|
||||
|
||||
- title: Astronomy Pick of the Day, Epicurious
|
||||
author: Starson17
|
||||
|
||||
- title: Diario Vasco, Various Chilean newspapers
|
||||
author: Darko Miletic
|
||||
|
||||
- title: Kukuburi
|
||||
author: Mori
|
||||
|
||||
|
||||
improved recipes:
|
||||
- Ars Technica
|
||||
- Fudzilla
|
||||
- The Atlantic
|
||||
- The Economist
|
||||
- Huffington Post
|
||||
|
||||
- version: 0.6.43
|
||||
date: 2010-02-26
|
||||
|
||||
|
@ -12,7 +12,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class al(BasicNewsRecipe):
|
||||
author = 'Lorenzo Vigentini'
|
||||
description = 'the Escapist Magazine'
|
||||
description = 'The Escapist Magazine'
|
||||
|
||||
cover_url = 'http://cdn.themis-media.com/themes/escapistmagazine/default/images/logo.png'
|
||||
title = u'the Escapist Magazine'
|
||||
|
@ -2,7 +2,7 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
__appname__ = 'calibre'
|
||||
__version__ = '0.6.43'
|
||||
__version__ = '0.6.44'
|
||||
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
||||
|
||||
import re
|
||||
|
@ -190,11 +190,11 @@ class Stylizer(object):
|
||||
selector = CSSSelector(ntext)
|
||||
matches = selector(tree)
|
||||
|
||||
if not matches and class_sel_pat.match(text):
|
||||
if not matches and class_sel_pat.match(text) and text.lower() != text:
|
||||
found = False
|
||||
ltext = text.lower()
|
||||
for x in tree.xpath('//*[@class]'):
|
||||
if text.lower().endswith('.'+x.get('class').lower()) and \
|
||||
text.lower() != text:
|
||||
if ltext.endswith('.'+x.get('class').lower()):
|
||||
matches.append(x)
|
||||
found = True
|
||||
if found:
|
||||
|
@ -926,33 +926,33 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
||||
######################### Fetch annotations ################################
|
||||
|
||||
def fetch_annotations(self, *args):
|
||||
# Generate a path_map from selected ids
|
||||
# Generate a path_map from selected ids
|
||||
def get_ids_from_selected_rows():
|
||||
rows = self.library_view.selectionModel().selectedRows()
|
||||
if not rows or len(rows) < 2:
|
||||
rows = xrange(self.library_view.model().rowCount(QModelIndex()))
|
||||
ids = map(self.library_view.model().id, rows)
|
||||
return ids
|
||||
rows = self.library_view.selectionModel().selectedRows()
|
||||
if not rows or len(rows) < 2:
|
||||
rows = xrange(self.library_view.model().rowCount(QModelIndex()))
|
||||
ids = map(self.library_view.model().id, rows)
|
||||
return ids
|
||||
|
||||
def get_formats(id):
|
||||
formats = db.formats(id, index_is_id=True)
|
||||
fmts = []
|
||||
def get_formats(id):
|
||||
formats = db.formats(id, index_is_id=True)
|
||||
fmts = []
|
||||
if formats:
|
||||
for format in formats.split(','):
|
||||
fmts.append(format.lower())
|
||||
return fmts
|
||||
return fmts
|
||||
|
||||
def generate_annotation_paths(ids, db, device):
|
||||
# Generate path templates
|
||||
# Individual storage mount points scanned/resolved in driver.get_annotations()
|
||||
path_map = {}
|
||||
for id in ids:
|
||||
mi = db.get_metadata(id, index_is_id=True)
|
||||
a_path = device.create_upload_path(os.path.abspath('/<storage>'), mi, 'x.bookmark', create_dirs=False)
|
||||
path_map[id] = dict(path=a_path, fmts=get_formats(id))
|
||||
return path_map
|
||||
def generate_annotation_paths(ids, db, device):
|
||||
# Generate path templates
|
||||
# Individual storage mount points scanned/resolved in driver.get_annotations()
|
||||
path_map = {}
|
||||
for id in ids:
|
||||
mi = db.get_metadata(id, index_is_id=True)
|
||||
a_path = device.create_upload_path(os.path.abspath('/<storage>'), mi, 'x.bookmark', create_dirs=False)
|
||||
path_map[id] = dict(path=a_path, fmts=get_formats(id))
|
||||
return path_map
|
||||
|
||||
device = self.device_manager.device
|
||||
device = self.device_manager.device
|
||||
|
||||
if self.current_view() is not self.library_view:
|
||||
return error_dialog(self, _('Use library only'),
|
||||
@ -960,120 +960,120 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
||||
show=True)
|
||||
db = self.library_view.model().db
|
||||
|
||||
# Get the list of ids
|
||||
# Get the list of ids
|
||||
ids = get_ids_from_selected_rows()
|
||||
if not ids:
|
||||
return error_dialog(self, _('No books selected'),
|
||||
_('No books selected to fetch annotations from'),
|
||||
show=True)
|
||||
|
||||
# Map ids to paths
|
||||
path_map = generate_annotation_paths(ids, db, device)
|
||||
# Map ids to paths
|
||||
path_map = generate_annotation_paths(ids, db, device)
|
||||
|
||||
# Dispatch to devices.kindle.driver.get_annotations()
|
||||
# Dispatch to devices.kindle.driver.get_annotations()
|
||||
self.device_manager.annotations(Dispatcher(self.annotations_fetched),
|
||||
path_map)
|
||||
|
||||
def annotations_fetched(self, job):
|
||||
from calibre.devices.usbms.device import Device
|
||||
from calibre.gui2.dialogs.progress import ProgressDialog
|
||||
from calibre.devices.usbms.device import Device
|
||||
from calibre.gui2.dialogs.progress import ProgressDialog
|
||||
|
||||
class Updater(QThread):
|
||||
class Updater(QThread):
|
||||
|
||||
update_progress = pyqtSignal(int)
|
||||
update_done = pyqtSignal()
|
||||
|
||||
def __init__(self, parent, db, annotation_map, done_callback):
|
||||
QThread.__init__(self, parent)
|
||||
self.db = db
|
||||
self.pd = ProgressDialog(_('Merging user annotations into database'), '',
|
||||
def __init__(self, parent, db, annotation_map, done_callback):
|
||||
QThread.__init__(self, parent)
|
||||
self.db = db
|
||||
self.pd = ProgressDialog(_('Merging user annotations into database'), '',
|
||||
0, len(job.result), parent=parent)
|
||||
|
||||
self.am = annotation_map
|
||||
self.am = annotation_map
|
||||
self.done_callback = done_callback
|
||||
self.connect(self.pd, SIGNAL('canceled()'), self.canceled)
|
||||
self.pd.setModal(True)
|
||||
self.pd.show()
|
||||
self.connect(self.pd, SIGNAL('canceled()'), self.canceled)
|
||||
self.pd.setModal(True)
|
||||
self.pd.show()
|
||||
self.update_progress.connect(self.pd.set_value,
|
||||
type=Qt.QueuedConnection)
|
||||
self.update_done.connect(self.pd.hide, type=Qt.QueuedConnection)
|
||||
|
||||
def generate_annotation_html(self, bookmark):
|
||||
# Returns <div class="user_annotations"> ... </div>
|
||||
last_read_location = bookmark.last_read_location
|
||||
timestamp = datetime.datetime.utcfromtimestamp(bookmark.timestamp)
|
||||
percent_read = bookmark.percent_read
|
||||
def generate_annotation_html(self, bookmark):
|
||||
# Returns <div class="user_annotations"> ... </div>
|
||||
last_read_location = bookmark.last_read_location
|
||||
timestamp = datetime.datetime.utcfromtimestamp(bookmark.timestamp)
|
||||
percent_read = bookmark.percent_read
|
||||
|
||||
ka_soup = BeautifulSoup()
|
||||
dtc = 0
|
||||
divTag = Tag(ka_soup,'div')
|
||||
divTag['class'] = 'user_annotations'
|
||||
ka_soup = BeautifulSoup()
|
||||
dtc = 0
|
||||
divTag = Tag(ka_soup,'div')
|
||||
divTag['class'] = 'user_annotations'
|
||||
|
||||
# Add the last-read location
|
||||
spanTag = Tag(ka_soup, 'span')
|
||||
spanTag['style'] = 'font-weight:bold'
|
||||
spanTag.insert(0,NavigableString("%s<br />Last Page Read: Location %d (%d%%)" % \
|
||||
(strftime(u'%x', timestamp.timetuple()),
|
||||
# Add the last-read location
|
||||
spanTag = Tag(ka_soup, 'span')
|
||||
spanTag['style'] = 'font-weight:bold'
|
||||
spanTag.insert(0,NavigableString("%s<br />Last Page Read: Location %d (%d%%)" % \
|
||||
(strftime(u'%x', timestamp.timetuple()),
|
||||
last_read_location, percent_read)))
|
||||
|
||||
divTag.insert(dtc, spanTag)
|
||||
dtc += 1
|
||||
divTag.insert(dtc, Tag(ka_soup,'br'))
|
||||
dtc += 1
|
||||
divTag.insert(dtc, spanTag)
|
||||
dtc += 1
|
||||
divTag.insert(dtc, Tag(ka_soup,'br'))
|
||||
dtc += 1
|
||||
|
||||
if bookmark.user_notes:
|
||||
user_notes = bookmark.user_notes
|
||||
annotations = []
|
||||
if bookmark.user_notes:
|
||||
user_notes = bookmark.user_notes
|
||||
annotations = []
|
||||
|
||||
# Add the annotations sorted by location
|
||||
# Italicize highlighted text
|
||||
for location in sorted(user_notes):
|
||||
if user_notes[location]['text']:
|
||||
annotations.append('<b>Location %d • %s</b><br />%s<br />' % \
|
||||
(user_notes[location]['displayed_location'],
|
||||
# Add the annotations sorted by location
|
||||
# Italicize highlighted text
|
||||
for location in sorted(user_notes):
|
||||
if user_notes[location]['text']:
|
||||
annotations.append('<b>Location %d • %s</b><br />%s<br />' % \
|
||||
(user_notes[location]['displayed_location'],
|
||||
user_notes[location]['type'],
|
||||
user_notes[location]['text'] if \
|
||||
user_notes[location]['type'] == 'Note' else \
|
||||
'<i>%s</i>' % user_notes[location]['text']))
|
||||
else:
|
||||
annotations.append('<b>Location %d • %s</b><br />' % \
|
||||
(user_notes[location]['displayed_location'],
|
||||
'<i>%s</i>' % user_notes[location]['text']))
|
||||
else:
|
||||
annotations.append('<b>Location %d • %s</b><br />' % \
|
||||
(user_notes[location]['displayed_location'],
|
||||
user_notes[location]['type']))
|
||||
|
||||
for annotation in annotations:
|
||||
divTag.insert(dtc, annotation)
|
||||
dtc += 1
|
||||
for annotation in annotations:
|
||||
divTag.insert(dtc, annotation)
|
||||
dtc += 1
|
||||
|
||||
ka_soup.insert(0,divTag)
|
||||
return ka_soup
|
||||
ka_soup.insert(0,divTag)
|
||||
return ka_soup
|
||||
|
||||
def canceled(self):
|
||||
self.pd.hide()
|
||||
def canceled(self):
|
||||
self.pd.hide()
|
||||
|
||||
def run(self):
|
||||
for (i, id) in enumerate(self.am):
|
||||
bm = Device.UserAnnotation(self.am[id][0],self.am[id][1])
|
||||
user_notes_soup = self.generate_annotation_html(bm.bookmark)
|
||||
def run(self):
|
||||
for (i, id) in enumerate(self.am):
|
||||
bm = Device.UserAnnotation(self.am[id][0],self.am[id][1])
|
||||
user_notes_soup = self.generate_annotation_html(bm.bookmark)
|
||||
|
||||
mi = self.db.get_metadata(id, index_is_id=True)
|
||||
if mi.comments:
|
||||
a_offset = mi.comments.find('<div class="user_annotations">')
|
||||
ad_offset = mi.comments.find('<hr class="annotations_divider" />')
|
||||
mi = self.db.get_metadata(id, index_is_id=True)
|
||||
if mi.comments:
|
||||
a_offset = mi.comments.find('<div class="user_annotations">')
|
||||
ad_offset = mi.comments.find('<hr class="annotations_divider" />')
|
||||
|
||||
if a_offset >= 0:
|
||||
mi.comments = mi.comments[:a_offset]
|
||||
if ad_offset >= 0:
|
||||
mi.comments = mi.comments[:ad_offset]
|
||||
if mi.comments:
|
||||
hrTag = Tag(user_notes_soup,'hr')
|
||||
hrTag['class'] = 'annotations_divider'
|
||||
user_notes_soup.insert(0,hrTag)
|
||||
if a_offset >= 0:
|
||||
mi.comments = mi.comments[:a_offset]
|
||||
if ad_offset >= 0:
|
||||
mi.comments = mi.comments[:ad_offset]
|
||||
if mi.comments:
|
||||
hrTag = Tag(user_notes_soup,'hr')
|
||||
hrTag['class'] = 'annotations_divider'
|
||||
user_notes_soup.insert(0,hrTag)
|
||||
|
||||
mi.comments += user_notes_soup.prettify()
|
||||
else:
|
||||
mi.comments = unicode(user_notes_soup.prettify())
|
||||
# Update library comments
|
||||
self.db.set_comment(id, mi.comments)
|
||||
mi.comments += user_notes_soup.prettify()
|
||||
else:
|
||||
mi.comments = unicode(user_notes_soup.prettify())
|
||||
# Update library comments
|
||||
self.db.set_comment(id, mi.comments)
|
||||
self.update_progress.emit(i)
|
||||
self.update_done.emit()
|
||||
self.done_callback(self.am.keys())
|
||||
@ -1599,12 +1599,12 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
||||
dynamic.set('catalogs_to_be_synced', sync)
|
||||
self.status_bar.showMessage(_('Catalog generated.'), 3000)
|
||||
self.sync_catalogs()
|
||||
if job.fmt not in ['EPUB','MOBI']:
|
||||
export_dir = choose_dir(self, _('Export Catalog Directory'),
|
||||
if job.fmt not in ['EPUB','MOBI']:
|
||||
export_dir = choose_dir(self, _('Export Catalog Directory'),
|
||||
_('Select destination for %s.%s') % (job.catalog_title, job.fmt.lower()))
|
||||
if export_dir:
|
||||
destination = os.path.join(export_dir, '%s.%s' % (job.catalog_title, job.fmt.lower()))
|
||||
shutil.copyfile(job.catalog_file_path, destination)
|
||||
if export_dir:
|
||||
destination = os.path.join(export_dir, '%s.%s' % (job.catalog_title, job.fmt.lower()))
|
||||
shutil.copyfile(job.catalog_file_path, destination)
|
||||
|
||||
############################### Fetch news #################################
|
||||
|
||||
|
@ -14,6 +14,7 @@ from calibre.customize.conversion import OptionRecommendation, DummyReporter
|
||||
from calibre.ebooks.BeautifulSoup import BeautifulSoup, BeautifulStoneSoup, Tag, NavigableString
|
||||
from calibre.ptempfile import PersistentTemporaryDirectory
|
||||
from calibre.utils.date import isoformat, now as nowf
|
||||
from calibre.utils.logging import default_log as log
|
||||
|
||||
FIELDS = ['all', 'author_sort', 'authors', 'comments',
|
||||
'cover', 'formats', 'id', 'isbn', 'pubdate', 'publisher', 'rating',
|
||||
@ -53,7 +54,6 @@ class CSV_XML(CatalogPlugin):
|
||||
"Applies to: CSV, XML output formats"))]
|
||||
|
||||
def run(self, path_to_output, opts, db, notification=DummyReporter()):
|
||||
log = Log()
|
||||
self.fmt = path_to_output.rpartition('.')[2]
|
||||
self.notification = notification
|
||||
|
||||
@ -348,7 +348,7 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
self.number_as_float = 0.0
|
||||
self.text = ''
|
||||
self.verbose = verbose
|
||||
self.log = Log()
|
||||
self.log = log
|
||||
self.numberTranslate()
|
||||
|
||||
def stringFromInt(self, intToTranslate):
|
||||
@ -3852,6 +3852,8 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
lost_cr.group(2),
|
||||
lost_cr.group(3)))
|
||||
# Extract pre-built elements - annotations, etc.
|
||||
if not isinstance(comments, unicode):
|
||||
comments = comments.decode('utf-8', 'replace')
|
||||
soup = BeautifulSoup(comments)
|
||||
elems = soup.findAll('div')
|
||||
for elem in elems:
|
||||
@ -3859,11 +3861,13 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
|
||||
# Reconstruct comments w/o <div>s
|
||||
comments = soup.renderContents()
|
||||
if not isinstance(comments, unicode):
|
||||
comments = comments.decode('utf-8', 'replace')
|
||||
|
||||
# Convert \n\n to <p>s
|
||||
if re.search('\n\n', comments):
|
||||
soup = BeautifulSoup()
|
||||
split_ps = comments.split('\n\n')
|
||||
split_ps = comments.split(u'\n\n')
|
||||
tsc = 0
|
||||
for p in split_ps:
|
||||
pTag = Tag(soup,'p')
|
||||
@ -3966,7 +3970,7 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
self.opts.log.info('%s not implemented' % self.error)
|
||||
|
||||
def run(self, path_to_output, opts, db, notification=DummyReporter()):
|
||||
opts.log = log = Log()
|
||||
opts.log = log
|
||||
opts.fmt = self.fmt = path_to_output.rpartition('.')[2]
|
||||
|
||||
# Add local options
|
||||
|
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
8044
src/calibre/translations/hi.po
Normal file
8044
src/calibre/translations/hi.po
Normal file
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
8052
src/calibre/translations/lt.po
Normal file
8052
src/calibre/translations/lt.po
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user