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
5330c07458
@ -4,6 +4,85 @@
|
||||
# for important features/bug fixes.
|
||||
# Also, each release can have new and improved recipes.
|
||||
|
||||
- version: 0.7.23
|
||||
date: 2010-10-08
|
||||
|
||||
new features:
|
||||
- title: "Drag and drop to Tag Browser. You can use this to conveniently add tags, set series/publisher etc for a group of books"
|
||||
|
||||
- title: "Allow switching of library even when a device is connected"
|
||||
|
||||
- title: "Support for the PD Novel running Kobo"
|
||||
|
||||
- title: "Move check library integrity from preferences to drop down menu accessed by clicking arrow next to calibre icon"
|
||||
|
||||
- title: "Nicer, non-blocking update available notification"
|
||||
|
||||
- title: "E-book viewer: If you choose to remeber last used window size, the state of the Table of Contents view is also remembered"
|
||||
tickets: [7082]
|
||||
|
||||
- title: "Allow moving as well as copying of books to another library"
|
||||
|
||||
- title: "Apple devices: Add support for plugboards"
|
||||
|
||||
- title: "Allow DJVU to be sent to the DR1000"
|
||||
|
||||
bug fixes:
|
||||
- title: "Searching: Fix search expression parser to allow use of escaped double quotes in the search expression"
|
||||
|
||||
- title: "When saving cover images don't re-encode the image data unless absolutely neccessary. This prevents information loss due to JPEG re-compression"
|
||||
|
||||
- title: "Fix regression that broke setting of metadata for some MOBI/AZW/PRC files"
|
||||
|
||||
- title: "Fix regression in last release that could cause download of metadata for multiple files to only download the metadata for a few of them"
|
||||
tickets: [7071]
|
||||
|
||||
- title: "MOBI Output: More tweaking of the margin handling to yield results closer to the input document."
|
||||
|
||||
- title: "Device drivers: Fix regression that could cause geenration of invalid metadata.calibre cache files"
|
||||
|
||||
- title: "Fix saving to disk with ISBN in filename"
|
||||
tickets: [7090]
|
||||
|
||||
- title: "Fix another regression in the ISBNdb.com metadata download plugin"
|
||||
|
||||
- title: "Fix dragging to not interfere with multi-selection. Also dont allow drag and drop from the library to itself"
|
||||
|
||||
- title: "CHM input: handle another class of broken CHM files"
|
||||
tickets: [7058]
|
||||
|
||||
|
||||
new recipes:
|
||||
- title: "Communications of the Association for Computing Machinery"
|
||||
author: jonmisurda
|
||||
|
||||
- title: "Anand Tech"
|
||||
author: "Oliver Niesner"
|
||||
|
||||
- title: "gsp.ro"
|
||||
author: "bucsie"
|
||||
|
||||
- title: "Il Fatto Quotidiano"
|
||||
author: "egilh"
|
||||
|
||||
- title: "Serbian Literature blog and Rusia Hoy"
|
||||
author: "Darko Miletic"
|
||||
|
||||
- title: "Medscape"
|
||||
author: "Tony Stegall"
|
||||
|
||||
|
||||
improved recipes:
|
||||
- The Age
|
||||
- Australian
|
||||
- Wiki news
|
||||
- Times Online
|
||||
- New Yorker
|
||||
- Guardian
|
||||
- Sueddeutsche
|
||||
- HNA
|
||||
- Revista Muy Interesante
|
||||
|
||||
- version: 0.7.22
|
||||
date: 2010-10-03
|
||||
|
||||
|
@ -13,6 +13,8 @@
|
||||
font-size: 1.25em;
|
||||
border: 1px solid black;
|
||||
text-color: black;
|
||||
text-decoration: none;
|
||||
margin-right: 0.5em;
|
||||
background-color: #ddd;
|
||||
border-top: 1px solid ThreeDLightShadow;
|
||||
border-right: 1px solid ButtonShadow;
|
||||
@ -70,6 +72,7 @@ div.navigation {
|
||||
padding-right: 0em;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#logo {
|
||||
|
@ -38,7 +38,7 @@ class Guardian(BasicNewsRecipe):
|
||||
dict(name='div', attrs={'id':["article-toolbox","subscribe-feeds",]}),
|
||||
dict(name='ul', attrs={'class':["pagination"]}),
|
||||
dict(name='ul', attrs={'id':["content-actions"]}),
|
||||
dict(name='img'),
|
||||
#dict(name='img'),
|
||||
]
|
||||
use_embedded_content = False
|
||||
|
||||
|
64
resources/recipes/medscape.recipe
Normal file
64
resources/recipes/medscape.recipe
Normal file
@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python
|
||||
__license__ = 'GPL v3'
|
||||
__author__ = 'Tony Stegall'
|
||||
__copyright__ = '2010, Tony Stegall or Tonythebookworm on mobileread.com'
|
||||
__version__ = '1'
|
||||
__date__ = '01, October 2010'
|
||||
__docformat__ = 'English'
|
||||
|
||||
|
||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
||||
|
||||
class MedScrape(BasicNewsRecipe):
|
||||
|
||||
title = 'MedScape'
|
||||
__author__ = 'Tony Stegall'
|
||||
description = 'Nursing News'
|
||||
language = 'en'
|
||||
timefmt = ' [%a, %d %b, %Y]'
|
||||
needs_subscription = True
|
||||
masthead_url = 'http://images.medscape.com/pi/global/header/sp/bg-sp-medscape.gif'
|
||||
no_stylesheets = True
|
||||
remove_javascript = True
|
||||
conversion_options = {'linearize_tables' : True}
|
||||
extra_css = '''
|
||||
h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;}
|
||||
|
||||
|
||||
p.authors{text-align:right; font-size:small;margin-top:0px;margin-bottom: 0px;}
|
||||
p.postingdate{text-align:right; font-size:small;margin-top:0px;margin-bottom: 0px;}
|
||||
h2{text-align:right; font-size:small;margin-top:0px;margin-bottom: 0px;}
|
||||
|
||||
|
||||
p{font-family:Helvetica,Arial,sans-serif;font-size:small;}
|
||||
'''
|
||||
|
||||
remove_tags = [dict(name='div', attrs={'class':['closewindow2']}),
|
||||
dict(name='div', attrs={'id': ['basicheaderlinks']})
|
||||
]
|
||||
|
||||
def get_browser(self):
|
||||
br = BasicNewsRecipe.get_browser()
|
||||
if self.username is not None and self.password is not None:
|
||||
br.open('https://profreg.medscape.com/px/getlogin.do')
|
||||
br.select_form(name='LoginForm')
|
||||
br['userId'] = self.username
|
||||
br['password'] = self.password
|
||||
br.submit()
|
||||
return br
|
||||
|
||||
feeds = [
|
||||
('MedInfo', 'http://www.medscape.com/cx/rssfeeds/2685.xml'),
|
||||
]
|
||||
|
||||
def print_version(self,url):
|
||||
#the original url is: http://www.medscape.com/viewarticle/728955?src=rss
|
||||
#the print url is: http://www.medscape.com/viewarticle/728955_print
|
||||
print_url = url.partition('?')[0] +'_print'
|
||||
#print 'the printable version is: ',print_url
|
||||
return print_url
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for item in soup.findAll(attrs={'style':True}):
|
||||
del item['style']
|
||||
return soup
|
@ -6,9 +6,9 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import os, re, cStringIO, base64, httplib, subprocess
|
||||
import os, re, cStringIO, base64, httplib, subprocess, hashlib, shutil
|
||||
from subprocess import check_call
|
||||
from tempfile import NamedTemporaryFile
|
||||
from tempfile import NamedTemporaryFile, mkdtemp
|
||||
|
||||
from setup import Command, __version__, installer_name, __appname__
|
||||
|
||||
@ -331,5 +331,19 @@ class UploadToServer(Command):
|
||||
%(__version__, DOWNLOADS), shell=True)
|
||||
check_call('ssh divok /etc/init.d/apache2 graceful',
|
||||
shell=True)
|
||||
tdir = mkdtemp()
|
||||
for installer in installers():
|
||||
if not os.path.exists(installer):
|
||||
continue
|
||||
with open(installer, 'rb') as f:
|
||||
raw = f.read()
|
||||
fingerprint = hashlib.sha512(raw).hexdigest()
|
||||
fname = os.path.basename(installer+'.sha512')
|
||||
with open(os.path.join(tdir, fname), 'wb') as f:
|
||||
f.write(fingerprint)
|
||||
check_call('scp %s/*.sha512 divok:%s/signatures/' % (tdir, DOWNLOADS),
|
||||
shell=True)
|
||||
shutil.rmtree(tdir)
|
||||
|
||||
|
||||
|
||||
|
@ -2,7 +2,7 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
__appname__ = 'calibre'
|
||||
__version__ = '0.7.22'
|
||||
__version__ = '0.7.23'
|
||||
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
||||
|
||||
import re
|
||||
|
@ -259,6 +259,8 @@ class ITUNES(DriverBase):
|
||||
self.report_progress(1.0, _('Updating device metadata listing...'))
|
||||
|
||||
# Add new books to booklists[0]
|
||||
# Charles thinks this should be
|
||||
# for new_book in metadata[0]:
|
||||
for new_book in locations[0]:
|
||||
if DEBUG:
|
||||
self.log.info(" adding '%s' by '%s' to booklists[0]" %
|
||||
@ -1208,6 +1210,10 @@ class ITUNES(DriverBase):
|
||||
except:
|
||||
self.problem_titles.append("'%s' by %s" % (metadata.title, metadata.author[0]))
|
||||
self.log.error(" error scaling '%s' for '%s'" % (metadata.cover,metadata.title))
|
||||
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
return thumb
|
||||
|
||||
if isosx:
|
||||
@ -2400,7 +2406,7 @@ class ITUNES(DriverBase):
|
||||
try:
|
||||
storage_path = os.path.split(cached_book['lib_book'].location().path)
|
||||
if cached_book['lib_book'].location().path.startswith(self.iTunes_media) and \
|
||||
not storage_path[0].startswith(self.calibre_library_path):
|
||||
not storage_path[0].startswith(prefs['library_path']):
|
||||
title_storage_path = storage_path[0]
|
||||
if DEBUG:
|
||||
self.log.info(" removing title_storage_path: %s" % title_storage_path)
|
||||
@ -2452,7 +2458,7 @@ class ITUNES(DriverBase):
|
||||
|
||||
if book:
|
||||
if self.iTunes_media and path.startswith(self.iTunes_media) and \
|
||||
not path.startswith(self.calibre_library_path):
|
||||
not path.startswith(prefs['library_path']):
|
||||
storage_path = os.path.split(path)
|
||||
if DEBUG:
|
||||
self.log.info(" removing '%s' at %s" %
|
||||
|
@ -417,14 +417,16 @@ class DevicePlugin(Plugin):
|
||||
select a specific plugboard. This method is called immediately before
|
||||
add_books and sync_booklists.
|
||||
|
||||
pb_func is a callable with the following signature:
|
||||
pb_func is a callable with the following signature::
|
||||
def pb_func(device_name, format, plugboards)
|
||||
|
||||
You give it the current device name (either the class name or
|
||||
DEVICE_PLUGBOARD_NAME), the format you are interested in (a 'real'
|
||||
format or 'device_db'), and the plugboards (you were given those by
|
||||
set_plugboards, the same place you got this method).
|
||||
|
||||
Return value: None or a single plugboard instance.
|
||||
:return: None or a single plugboard instance.
|
||||
|
||||
'''
|
||||
pass
|
||||
|
||||
|
@ -131,6 +131,7 @@ class InterfaceAction(QObject):
|
||||
Called whenever the current library is changed.
|
||||
|
||||
:param db: The LibraryDatabase corresponding to the current library.
|
||||
|
||||
'''
|
||||
pass
|
||||
|
||||
@ -149,5 +150,6 @@ class InterfaceAction(QObject):
|
||||
|
||||
:return: False to halt the shutdown. You are responsible for telling
|
||||
the user why the shutdown was halted.
|
||||
|
||||
'''
|
||||
return True
|
||||
|
@ -340,10 +340,10 @@ class ChooseLibraryAction(InterfaceAction):
|
||||
m.start_metadata_backup()
|
||||
|
||||
def restore_database(self):
|
||||
info_dialog(self.gui, _('Recover database'),
|
||||
info_dialog(self.gui, _('Recover database'), '<p>'+
|
||||
_(
|
||||
'This command rebuilds your calibre database from the information '
|
||||
'stored by calibre in the OPF files.' + '<p>' +
|
||||
'stored by calibre in the OPF files.<p>'
|
||||
'This function is not currently available in the GUI. You can '
|
||||
'recover your database using the \'calibredb restore_database\' '
|
||||
'command line function.'
|
||||
|
@ -38,7 +38,10 @@ class CustomRecipeModel(QAbstractListModel):
|
||||
return False
|
||||
|
||||
def rowCount(self, *args):
|
||||
try:
|
||||
return len(self.recipe_model.custom_recipe_collection)
|
||||
except:
|
||||
return 0
|
||||
|
||||
def data(self, index, role):
|
||||
if role == Qt.DisplayRole:
|
||||
@ -100,6 +103,8 @@ class UserProfiles(ResizableDialog, Ui_Dialog):
|
||||
|
||||
def break_cycles(self):
|
||||
self.recipe_model = self._model.recipe_model = None
|
||||
self.available_profiles = None
|
||||
self.model = self._model = None
|
||||
|
||||
def remove_selected_items(self):
|
||||
indices = self.available_profiles.selectionModel().selectedRows()
|
||||
|
@ -3,13 +3,14 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
import traceback
|
||||
|
||||
from PyQt4.Qt import QThread, pyqtSignal, Qt, QUrl
|
||||
from PyQt4.Qt import QThread, pyqtSignal, Qt, QUrl, QDialog, QGridLayout, \
|
||||
QLabel, QCheckBox, QDialogButtonBox, QIcon, QPixmap
|
||||
import mechanize
|
||||
|
||||
from calibre.constants import __appname__, __version__, iswindows, isosx
|
||||
from calibre import browser
|
||||
from calibre.utils.config import prefs
|
||||
from calibre.gui2 import config, dynamic, question_dialog, open_url
|
||||
from calibre.gui2 import config, dynamic, open_url
|
||||
|
||||
URL = 'http://status.calibre-ebook.com/latest'
|
||||
|
||||
@ -37,6 +38,53 @@ class CheckForUpdates(QThread):
|
||||
traceback.print_exc()
|
||||
self.sleep(self.INTERVAL)
|
||||
|
||||
class UpdateNotification(QDialog):
|
||||
|
||||
def __init__(self, version, parent=None):
|
||||
QDialog.__init__(self, parent)
|
||||
self.resize(400, 250)
|
||||
self.l = QGridLayout()
|
||||
self.setLayout(self.l)
|
||||
self.logo = QLabel()
|
||||
self.logo.setMaximumWidth(110)
|
||||
self.logo.setPixmap(QPixmap(I('lt.png')).scaled(100, 100,
|
||||
Qt.IgnoreAspectRatio, Qt.SmoothTransformation))
|
||||
self.label = QLabel('<p>'+
|
||||
_('%s has been updated to version <b>%s</b>. '
|
||||
'See the <a href="http://calibre-ebook.com/whats-new'
|
||||
'">new features</a>. Visit the download pa'
|
||||
'ge?')%(__appname__, version))
|
||||
self.label.setOpenExternalLinks(True)
|
||||
self.label.setWordWrap(True)
|
||||
self.setWindowTitle(_('Update available!'))
|
||||
self.setWindowIcon(QIcon(I('lt.png')))
|
||||
self.l.addWidget(self.logo, 0, 0)
|
||||
self.l.addWidget(self.label, 0, 1)
|
||||
self.cb = QCheckBox(
|
||||
_('Show this notification for future updates'), self)
|
||||
self.l.addWidget(self.cb, 1, 0, 1, -1)
|
||||
self.cb.setChecked(config.get('new_version_notification'))
|
||||
self.cb.stateChanged.connect(self.show_future)
|
||||
self.bb = QDialogButtonBox(self)
|
||||
b = self.bb.addButton(_('&Get update'), self.bb.AcceptRole)
|
||||
b.setDefault(True)
|
||||
b.setIcon(QIcon(I('arrow-down.png')))
|
||||
self.bb.addButton(self.bb.Cancel)
|
||||
self.l.addWidget(self.bb, 2, 0, 1, -1)
|
||||
self.bb.accepted.connect(self.accept)
|
||||
self.bb.rejected.connect(self.reject)
|
||||
dynamic.set('update to version %s'%version, False)
|
||||
|
||||
def show_future(self, *args):
|
||||
config.set('new_version_notification', bool(self.cb.isChecked()))
|
||||
|
||||
def accept(self):
|
||||
url = 'http://calibre-ebook.com/download_'+\
|
||||
('windows' if iswindows else 'osx' if isosx else 'linux')
|
||||
open_url(QUrl(url))
|
||||
|
||||
QDialog.accept(self)
|
||||
|
||||
class UpdateMixin(object):
|
||||
|
||||
def __init__(self, opts):
|
||||
@ -53,15 +101,8 @@ class UpdateMixin(object):
|
||||
|
||||
if config.get('new_version_notification') and \
|
||||
dynamic.get('update to version %s'%version, True):
|
||||
if question_dialog(self, _('Update available'),
|
||||
_('%s has been updated to version %s. '
|
||||
'See the <a href="http://calibre-ebook.com/whats-new'
|
||||
'">new features</a>. Visit the download pa'
|
||||
'ge?')%(__appname__, version)):
|
||||
url = 'http://calibre-ebook.com/download_'+\
|
||||
('windows' if iswindows else 'osx' if isosx else 'linux')
|
||||
open_url(QUrl(url))
|
||||
dynamic.set('update to version %s'%version, False)
|
||||
|
||||
self._update_notification__ = UpdateNotification(version,
|
||||
parent=self)
|
||||
self._update_notification__.show()
|
||||
|
||||
|
||||
|
@ -958,7 +958,7 @@ def command_check_library(args, dbpath):
|
||||
|
||||
def restore_database_option_parser():
|
||||
parser = get_parser(_(
|
||||
'''
|
||||
'''\
|
||||
%prog restore_database [options]
|
||||
|
||||
Restore this database from the metadata stored in OPF files in each
|
||||
|
@ -121,7 +121,7 @@ def build_index(books, num, search, sort, order, start, total, url_base, CKEYS):
|
||||
book['id'], fmt)
|
||||
),
|
||||
CLASS('button'))
|
||||
s.tail = u'\u202f' #
|
||||
s.tail = u''
|
||||
last = s
|
||||
data.append(s)
|
||||
|
||||
|
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
Loading…
x
Reference in New Issue
Block a user