Pull from trunk

This commit is contained in:
Kovid Goyal 2010-08-10 12:55:08 -06:00
commit 74837333f3
19 changed files with 3333 additions and 2909 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

View File

@ -0,0 +1,64 @@
__license__ = 'GPL v3'
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
'''
www.la-razon.com
'''
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe
class LaRazon_Bol(BasicNewsRecipe):
title = 'La Razón - Bolivia'
__author__ = 'Darko Miletic'
description = 'El diario nacional de Bolivia'
publisher = 'Praxsis S.R.L.'
category = 'news, politics, Bolivia'
oldest_article = 1
max_articles_per_feed = 200
no_stylesheets = True
encoding = 'cp1252'
use_embedded_content = False
language = 'es'
publication_type = 'newspaper'
delay = 1
remove_empty_feeds = True
cover_url = strftime('http://www.la-razon.com/portadas/%Y%m%d_LaRazon.jpg')
masthead_url = 'http://www.la-razon.com/imagenes/logo.jpg'
extra_css = """ body{font-family: Arial,Helvetica,sans-serif }
img{margin-bottom: 0.4em}
.noticia-titulo{font-family: Georgia,"Times New Roman",Times,serif}
.lead{font-weight: bold; font-size: 0.8em}
"""
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : language
}
keep_only_tags = [dict(name='div', attrs={'class':['noticia-titulo','noticia-desarrollo']})]
remove_tags = [dict(name=['meta','link','form','iframe','embed','object'])]
remove_attributes = ['width','height']
feeds = [
(u'Editorial' , u'http://www.la-razon.com/rss_editorial.php' )
,(u'Opinión' , u'http://www.la-razon.com/rss_opinion.php' )
,(u'Nacional' , u'http://www.la-razon.com/rss_nacional.php' )
,(u'Economia' , u'http://www.la-razon.com/rss_economia.php' )
,(u'Ciudades' , u'http://www.la-razon.com/rss_ciudades.php' )
,(u'Sociedad' , u'http://www.la-razon.com/rss_sociedad.php' )
,(u'Mundo' , u'http://www.la-razon.com/rss_sociedad.php' )
,(u'La Revista' , u'http://www.la-razon.com/rss_larevista.php' )
,(u'Sociales' , u'http://www.la-razon.com/rss_sociales.php' )
,(u'Mia' , u'http://www.la-razon.com/rss_mia.php' )
,(u'Marcas' , u'http://www.la-razon.com/rss_marcas.php' )
,(u'Escape' , u'http://www.la-razon.com/rss_escape.php' )
,(u'El Financiero' , u'http://www.la-razon.com/rss_financiero.php')
,(u'Tendencias' , u'http://www.la-razon.com/rss_tendencias.php')
]
def preprocess_html(self, soup):
for item in soup.findAll(style=True):
del item['style']
return soup

View File

@ -0,0 +1,63 @@
__license__ = 'GPL v3'
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
'''
www.lostiempos.com
'''
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe
class LosTiempos_Bol(BasicNewsRecipe):
title = 'Los Tiempos - Bolivia'
__author__ = 'Darko Miletic'
description = 'El periódico de mayor circulación en la ciudad de Cochabamba, Bolivia'
publisher = 'Los Tiempos'
category = 'news, politics, Bolivia'
oldest_article = 1
max_articles_per_feed = 200
no_stylesheets = True
encoding = 'cp1252'
use_embedded_content = False
language = 'es'
publication_type = 'newspaper'
delay = 1
remove_empty_feeds = True
cover_url = strftime('http://www.lostiempos.com/media_recortes/%Y/%m/%d/portada_md_1.jpg')
masthead_url = 'http://www.lostiempos.com/img_stat/logo_tiempos_sin_beta.jpg'
extra_css = """ body{font-family: Arial,Helvetica,sans-serif }
img{margin-bottom: 0.4em}
h1,.hora,.breadcum,.pie_foto{font-family: Georgia,"Times New Roman",Times,serif}
.hora,.breadcum,.pie_foto{font-size: small}
.en_gris,.pie_foto{color: #666666}
"""
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : language
}
keep_only_tags = [dict(name='div', attrs={'id':'articulo'})]
remove_tags = [
dict(name=['meta','link','form','iframe','embed','object','hr'])
,dict(attrs={'class':['caja_fonts sin_border_bot','pub']})
]
remove_attributes = ['width','height']
feeds = [
(u'Nacional' , u'http://www.lostiempos.com/rss/lostiempos-nacional.xml' )
,(u'Local' , u'http://www.lostiempos.com/rss/lostiempos-local.xml' )
,(u'Deportes' , u'http://www.lostiempos.com/rss/lostiempos-deportes.xml' )
,(u'Economía' , u'http://www.lostiempos.com/rss/lostiempos-economia.xml' )
,(u'Internacional' , u'http://www.lostiempos.com/rss/lostiempos-internacional.xml' )
,(u'Vida y Futuro' , u'http://www.lostiempos.com/rss/lostiempos-vida-y-futuro.xml' )
,(u'Tragaluz' , u'http://www.lostiempos.com/rss/lostiempos-tragaluz.xml' )
,(u'Opiniones' , u'http://www.lostiempos.com/rss/lostiempos-opiniones.xml' )
]
def preprocess_html(self, soup):
for item in soup.findAll(style=True):
del item['style']
return soup

View File

@ -0,0 +1,34 @@
from calibre.web.feeds.news import BasicNewsRecipe
import re
class YahooNews(BasicNewsRecipe):
title = 'Yahoo News'
__author__ = 'Starson17'
description = 'Yahoo-Science'
language = 'en'
use_embedded_content= False
no_stylesheets = True
linearize_tables = True
oldest_article = 24
remove_javascript = True
remove_empty_feeds = True
max_articles_per_feed = 10
feeds = [#There are dozens of other feeds at http://news.yahoo.com/rss
(u'Top Stories', u'http://rss.news.yahoo.com/rss/topstories'),
(u'Science', u'http://rss.news.yahoo.com/rss/science')
]
keep_only_tags = [dict(name='div', attrs={'id':'yn-story'})]
remove_tags = [dict(name='div', attrs={'class':['hd', 'ft', 'yn-share-social']}),
dict(name='div', attrs={'id':['yn-story-minor-media']})]
preprocess_regexps = [(re.compile(r'<span>Play Video</span>', re.DOTALL),lambda match: '<span></span>')]
extra_css = '''
h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;}
h2{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;}
p{font-family:Arial,Helvetica,sans-serif;font-size:small;}
body{font-family:Helvetica,Arial,sans-serif;font-size:small;}
'''

View File

@ -19,8 +19,8 @@ class ANDROID(USBMS):
VENDOR_ID = {
# HTC
0x0bb4 : { 0x0c02 : [0x100, 0x227], 0x0c01 : [0x100, 0x227], 0x0ff9
: [0x0100, 0x227]},
0x0bb4 : { 0x0c02 : [0x100, 0x0227], 0x0c01 : [0x100, 0x0227], 0x0ff9
: [0x0100, 0x0227, 0x0226]},
# Motorola
0x22b8 : { 0x41d9 : [0x216], 0x2d67 : [0x100], 0x41db : [0x216],

View File

@ -931,7 +931,7 @@ class SaveToDiskAction(object): # {{{
lpath = self.library_view.model().db.library_path.replace('/', os.sep)
if dpath.startswith(lpath):
return error_dialog(self, _('Not allowed'),
_('You are tying to save files into the calibre '
_('You are trying to save files into the calibre '
'library. This can cause corruption of your '
'library. Save to disk is meant to export '
'files from your calibre library elsewhere.'), show=True)

View File

@ -18,7 +18,7 @@ from calibre.gui2 import error_dialog, config, gprefs, \
open_url, open_local_file, \
ALL_COLUMNS, NONE, info_dialog, choose_files, \
warning_dialog, ResizableDialog, question_dialog
from calibre.utils.config import prefs
from calibre.utils.config import prefs, read_raw_tweaks, write_tweaks
from calibre.ebooks import BOOK_EXTENSIONS
from calibre.ebooks.oeb.iterator import is_supported
from calibre.library.server import server_config
@ -514,8 +514,18 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
self.opt_toolbar_text.setCurrentIndex(idx)
self.reset_confirmation_button.clicked.connect(self.reset_confirmation)
deft, curt = read_raw_tweaks()
self.current_tweaks.setPlainText(curt)
self.default_tweaks.setPlainText(deft)
self.restore_tweaks_to_default_button.clicked.connect(self.restore_tweaks_to_default)
self.category_view.setCurrentIndex(self.category_view.model().index_for_name(initial_category))
def restore_tweaks_to_default(self, *args):
deft, curt = read_raw_tweaks()
self.current_tweaks.setPlainText(deft)
def reset_confirmation(self):
from calibre.gui2 import dynamic
for key in dynamic.keys():
@ -687,6 +697,22 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
self.input_order.insertItem(idx-1, self.input_order.takeItem(idx))
self.input_order.setCurrentRow(idx-1)
def set_tweaks(self):
raw = unicode(self.current_tweaks.toPlainText())
raw = re.sub(r'(?m)^#.*fileencoding.*', '# ', raw)
try:
exec raw
except:
import traceback
error_dialog(self, _('Invalid tweaks'),
_('The tweaks you entered are invalid, try resetting the'
' tweaks to default and changing them one by one until'
' you find the invalid setting.'),
det_msg=traceback.format_exc(), show=True)
return False
write_tweaks(raw)
return True
def down_input(self):
idx = self.input_order.currentRow()
if idx < self.input_order.count()-1:
@ -852,6 +878,8 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
return
if not self.add_save.save_settings():
return
if not self.set_tweaks():
return
wl = self.opt_worker_limit.value()
if wl%2 != 0:
wl += 1

View File

@ -719,61 +719,192 @@
<widget class="QWidget" name="page_2">
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>&amp;Maximum number of waiting worker processes (needs restart):</string>
</property>
<property name="buddy">
<cstring>opt_worker_limit</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="opt_worker_limit">
<property name="minimum">
<number>2</number>
</property>
<property name="maximum">
<number>10000</number>
</property>
<property name="singleStep">
<number>2</number>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QPushButton" name="compact_button">
<property name="text">
<string>&amp;Check database integrity</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QPushButton" name="button_osx_symlinks">
<property name="text">
<string>&amp;Install command line tools</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QPushButton" name="button_open_config_dir">
<property name="text">
<string>Open calibre &amp;configuration directory</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="opt_enforce_cpu_limit">
<property name="text">
<string>Limit the max. simultaneous jobs to the available CPU &amp;cores</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QPushButton" name="device_detection_button">
<property name="text">
<string>Debug &amp;device detection</string>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>&amp;Miscellaneous</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_9">
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>&amp;Maximum number of waiting worker processes (needs restart):</string>
</property>
<property name="buddy">
<cstring>opt_worker_limit</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="opt_worker_limit">
<property name="minimum">
<number>2</number>
</property>
<property name="maximum">
<number>10000</number>
</property>
<property name="singleStep">
<number>2</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="opt_enforce_cpu_limit">
<property name="text">
<string>Limit the max. simultaneous jobs to the available CPU &amp;cores</string>
</property>
</widget>
</item>
<item row="2" column="0">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>79</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="0" colspan="2">
<widget class="QPushButton" name="device_detection_button">
<property name="text">
<string>Debug &amp;device detection</string>
</property>
</widget>
</item>
<item row="4" column="0">
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>80</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="0" colspan="2">
<widget class="QPushButton" name="compact_button">
<property name="text">
<string>&amp;Check database integrity</string>
</property>
</widget>
</item>
<item row="6" column="0">
<spacer name="verticalSpacer_7">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>79</height>
</size>
</property>
</spacer>
</item>
<item row="7" column="0" colspan="2">
<widget class="QPushButton" name="button_open_config_dir">
<property name="text">
<string>Open calibre &amp;configuration directory</string>
</property>
</widget>
</item>
<item row="8" column="0">
<spacer name="verticalSpacer_8">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>80</height>
</size>
</property>
</spacer>
</item>
<item row="9" column="0" colspan="2">
<widget class="QPushButton" name="button_osx_symlinks">
<property name="text">
<string>&amp;Install command line tools</string>
</property>
</widget>
</item>
<item row="10" column="0">
<spacer name="verticalSpacer_9">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>79</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>&amp;Tweaks</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QLabel" name="label_18">
<property name="text">
<string>Values for the tweaks are shown below. Edit them to change the behavior of calibre</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_6">
<property name="title">
<string>All available tweaks</string>
</property>
<layout class="QGridLayout" name="gridLayout_11">
<item row="0" column="0">
<widget class="QPlainTextEdit" name="default_tweaks">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_7">
<property name="title">
<string>&amp;Current tweaks</string>
</property>
<layout class="QGridLayout" name="gridLayout_10">
<item row="0" column="0">
<widget class="QPlainTextEdit" name="current_tweaks"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QPushButton" name="restore_tweaks_to_default_button">
<property name="text">
<string>&amp;Restore to defaults</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>

View File

@ -48,17 +48,42 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
select_item = sort
self.table.resizeColumnsToContents()
# set up the signal after the table is filled
# set up the cellChanged signal only after the table is filled
self.table.cellChanged.connect(self.cell_changed)
self.table.setSortingEnabled(True)
# set up sort buttons
self.sort_by_author.setCheckable(True)
self.sort_by_author.setChecked(False)
self.sort_by_author.clicked.connect(self.do_sort_by_author)
self.author_order = 1
self.table.sortByColumn(1, Qt.AscendingOrder)
self.sort_by_author_sort.clicked.connect(self.do_sort_by_author_sort)
self.sort_by_author_sort.setCheckable(True)
self.sort_by_author_sort.setChecked(True)
self.author_sort_order = 1
# set up author sort calc button
self.recalc_author_sort.clicked.connect(self.do_recalc_author_sort)
if select_item is not None:
self.table.setCurrentItem(select_item)
self.table.editItem(select_item)
else:
self.table.setCurrentCell(0, 0)
def do_sort_by_author(self):
self.author_order = 1 if self.author_order == 0 else 0
self.table.sortByColumn(0, self.author_order)
self.sort_by_author.setChecked(True)
self.sort_by_author_sort.setChecked(False)
def do_sort_by_author_sort(self):
self.author_sort_order = 1 if self.author_sort_order == 0 else 0
self.table.sortByColumn(1, self.author_sort_order)
self.sort_by_author.setChecked(False)
self.sort_by_author_sort.setChecked(True)
def accepted(self):
self.result = []
for row in range(0,self.table.rowCount()):
@ -69,6 +94,17 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
if orig_aut != aut or orig_sort != sort:
self.result.append((id, orig_aut, aut, sort))
def do_recalc_author_sort(self):
self.table.cellChanged.disconnect()
for row in range(0,self.table.rowCount()):
item = self.table.item(row, 0)
aut = unicode(item.text()).strip()
c = self.table.item(row, 1)
# Sometimes trailing commas are left by changing between copy algs
c.setText(author_to_author_sort(aut).rstrip(','))
self.table.setFocus(Qt.OtherFocusReason)
self.table.cellChanged.connect(self.cell_changed)
def cell_changed(self, row, col):
if col == 0:
item = self.table.item(row, 0)
@ -79,8 +115,4 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
else:
item = self.table.item(row, 1)
self.table.setCurrentItem(item)
# disable and reenable sorting to force the sort now, so we can scroll
# to the item after it moves
self.table.setSortingEnabled(False)
self.table.setSortingEnabled(True)
self.table.scrollToItem(item)

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>730</width>
<width>768</width>
<height>342</height>
</rect>
</property>
@ -34,17 +34,64 @@
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
<property name="centerButtons">
<bool>true</bool>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="sort_by_author">
<property name="text">
<string>Sort by author</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="sort_by_author_sort">
<property name="text">
<string>Sort by author sort</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="recalc_author_sort">
<property name="toolTip">
<string>Reset all the author sort values to a value automatically generated from the author. Exactly how this value is automatically generated can be controlled via Preferences-&gt;Advanced-&gt;Tweaks</string>
</property>
<property name="text">
<string>Recalculate all author sort values</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
<property name="centerButtons">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>

View File

@ -675,9 +675,7 @@ class Wizard(QWizard):
self.connect(self.library_page, SIGNAL('retranslate()'),
self.retranslate)
self.finish_page = FinishPage()
bt = unicode(self.buttonText(self.FinishButton)).replace('&', '')
t = unicode(self.finish_page.finish_text.text())
self.finish_page.finish_text.setText(t%bt)
self.set_finish_text()
self.kindle_page = KindlePage()
self.stanza_page = StanzaPage()
self.word_player_page = WordPlayerPage()
@ -702,6 +700,7 @@ class Wizard(QWizard):
for pid in self.pageIds():
page = self.page(pid)
page.retranslateUi(page)
self.set_finish_text()
def accept(self):
pages = map(self.page, self.visitedPages())
@ -715,6 +714,13 @@ class Wizard(QWizard):
def completed(self, newloc):
return QWizard.accept(self)
def set_finish_text(self, *args):
bt = unicode(self.buttonText(self.FinishButton)).replace('&', '')
t = unicode(self.finish_page.finish_text.text())
if '%s' in t:
self.finish_page.finish_text.setText(t%bt)
def wizard(parent=None):
w = Wizard(parent)
return w

View File

@ -15,6 +15,7 @@ from calibre import prepare_string_for_xml
# Hackish - ignoring sentences ending or beginning in numbers to avoid
# confusion with decimal points.
lost_cr_pat = re.compile('([a-z])([\.\?!])([A-Z])')
lost_cr_exception_pat = re.compile(r'(Ph\.D)|(D\.Phil)|((Dr|Mr|Mrs|Ms)\.[A-Z])')
def comments_to_html(comments):
'''
@ -51,6 +52,8 @@ def comments_to_html(comments):
return '\n'.join(parts)
# Explode lost CRs to \n\n
comments = lost_cr_exception_pat.sub(lambda m: m.group().replace('.',
'.\r'), comments)
for lost_cr in lost_cr_pat.finditer(comments):
comments = comments.replace(lost_cr.group(),
'%s%s\n\n%s' % (lost_cr.group(1),

View File

@ -317,6 +317,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
'title', 'timestamp', 'uuid', 'pubdate'):
setattr(self, prop, functools.partial(get_property,
loc=self.FIELD_MAP['comments' if prop == 'comment' else prop]))
setattr(self, 'title_sort', functools.partial(get_property,
loc=self.FIELD_MAP['sort']))
def initialize_database(self):
metadata_sqlite = open(P('metadata_sqlite.sql'), 'rb').read()
@ -494,6 +496,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
mi.timestamp = self.timestamp(idx, index_is_id=index_is_id)
mi.pubdate = self.pubdate(idx, index_is_id=index_is_id)
mi.uuid = self.uuid(idx, index_is_id=index_is_id)
mi.title_sort = self.title_sort(idx, index_is_id=index_is_id)
tags = self.tags(idx, index_is_id=index_is_id)
if tags:
mi.tags = [i.strip() for i in tags.split(',')]

View File

@ -177,7 +177,7 @@ def extract(path, dir):
try:
if open_archive_data.OpenResult != 0:
raise UnRARException(_interpret_open_error(open_archive_data.OpenResult, path))
prints('Archive:', path)
#prints('Archive:', path)
#print get_archive_info(open_archive_data.Flags)
header_data = RARHeaderDataEx(CmtBuf=None)
#_libunrar.RARSetCallback(arc_data, callback_func, mode)

View File

@ -277,7 +277,8 @@ In |app|, you would instead use tags to mark genre and read status and then just
Why doesn't |app| have a column for foo?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|app| is designed to have columns for the most frequently and widely used fields. If it does not have a coulmn for your favorite field, you can always add a tag to the book for that piece of information. |app| also supports a general purpose "comments" fields for longer items.
|app| is designed to have columns for the most frequently and widely used fields. In addition, you can add any columns you like. Columns can be added via Preferences->Interface.
Watch the tutorial `UI Power tips <http://calibre-ebook.com/demo#tutorials>`_ to learn how to create your own columns.
How do I move my |app| library from one computer to another?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

File diff suppressed because it is too large Load Diff

View File

@ -703,16 +703,21 @@ if prefs['installation_uuid'] is None:
prefs['installation_uuid'] = str(uuid.uuid4())
# Read tweaks
def read_tweaks():
def read_raw_tweaks():
make_config_dir()
default_tweaks = P('default_tweaks.py', data=True)
tweaks_file = os.path.join(config_dir, 'tweaks.py')
if not os.path.exists(tweaks_file):
with open(tweaks_file, 'wb') as f:
f.write(default_tweaks)
with open(tweaks_file, 'rb') as f:
return default_tweaks, f.read()
def read_tweaks():
default_tweaks, tweaks = read_raw_tweaks()
l, g = {}, {}
try:
exec open(tweaks_file, 'rb') in g, l
exec tweaks in g, l
except:
print 'Failed to load custom tweaks file'
traceback.print_exc()
@ -721,6 +726,13 @@ def read_tweaks():
dl.update(l)
return dl
def write_tweaks(raw):
make_config_dir()
tweaks_file = os.path.join(config_dir, 'tweaks.py')
with open(tweaks_file, 'wb') as f:
f.write(raw)
tweaks = read_tweaks()
def migrate():

View File

@ -194,7 +194,7 @@ class Image(_magick.Image): # {{{
# }}}
def create_canvas(width, height, bgcolor):
def create_canvas(width, height, bgcolor='white'):
canvas = Image()
canvas.create_canvas(int(width), int(height), str(bgcolor))
return canvas