diff --git a/resources/images/news/fe_india.png b/resources/images/news/fe_india.png new file mode 100644 index 0000000000..759f2594cd Binary files /dev/null and b/resources/images/news/fe_india.png differ diff --git a/resources/recipes/esquire.recipe b/resources/recipes/esquire.recipe index 96338d0b48..d9c189b473 100644 --- a/resources/recipes/esquire.recipe +++ b/resources/recipes/esquire.recipe @@ -1,7 +1,5 @@ -#!/usr/bin/env python - __license__ = 'GPL v3' -__copyright__ = '2009, Darko Miletic ' +__copyright__ = '2009-2010, Darko Miletic ' ''' www.esquire.com @@ -9,7 +7,6 @@ www.esquire.com from calibre import strftime from calibre.web.feeds.news import BasicNewsRecipe -from calibre.ebooks.BeautifulSoup import Tag class Esquire(BasicNewsRecipe): title = 'Esquire' @@ -22,23 +19,21 @@ class Esquire(BasicNewsRecipe): no_stylesheets = True encoding = 'cp1250' use_embedded_content = False - language = 'en' - - lang = 'en-US' - cover_url = strftime('http://www.esquire.com/cm/esquire/cover-images/%Y_') + strftime('%m').strip('0') + '.jpg' + language = 'en' + publication_type = 'magazine' + masthead_url = 'http://www.esquire.com/cm/shared/site_images/print_this/esquire_logo.gif' conversion_options = { - 'comment' : description - , 'tags' : category - , 'publisher' : publisher - , 'language' : lang - , 'pretty_print' : True + 'comment' : description + , 'tags' : category + , 'publisher' : publisher + , 'language' : language } - keep_only_tags = [dict(name='div', attrs={'id':'content'})] - - remove_tags = [dict(name=['object','link','embed','iframe'])] - + keep_only_tags = [dict(name='div', attrs={'id':['article_header','article_content']})] + remove_tags = [dict(name=['object','link','embed','iframe','base'])] + remove_attributes = ['width','height'] + feeds = [ (u'Style' , u'http://www.esquire.com/style/rss/' ) ,(u'Women' , u'http://www.esquire.com/women/rss/' ) @@ -47,17 +42,7 @@ class Esquire(BasicNewsRecipe): ,(u'Frontpage', u'http://www.esquire.com/rss/' ) ] - - def print_version(self, url): - rest = url.rpartition('?')[0] - article = rest.rpartition('/')[2] - return 'http://www.esquire.com/print-this/' + article - def preprocess_html(self, soup): - soup.html['xml:lang'] = self.lang - soup.html['lang'] = self.lang - mlang = Tag(soup,'meta',[("http-equiv","Content-Language"),("content",self.lang)]) - soup.head.insert(0,mlang) for item in soup.findAll(style=True): del item['style'] return soup diff --git a/resources/recipes/fe_india.recipe b/resources/recipes/fe_india.recipe new file mode 100644 index 0000000000..7b5f380bdf --- /dev/null +++ b/resources/recipes/fe_india.recipe @@ -0,0 +1,46 @@ +__license__ = 'GPL v3' +__copyright__ = '2010, Darko Miletic ' +''' +financialexpress.com +''' + +from calibre.web.feeds.news import BasicNewsRecipe + +class FE_India(BasicNewsRecipe): + title = 'The Financial Express' + __author__ = 'Darko Miletic' + description = 'Financial news from India' + publisher = 'The Indian Express Limited' + category = 'news, politics, finances, India' + oldest_article = 30 + max_articles_per_feed = 200 + no_stylesheets = True + encoding = 'cp1252' + use_embedded_content = False + language = 'en_IN' + remove_empty_feeds = True + masthead_url = 'http://static.expressindia.com/frontend/fe/images/fe_logo.jpg' + publication_type = 'magazine' + extra_css = ' body{font-family: Arial,Helvetica,sans-serif } ' + + conversion_options = { + 'comment' : description + , 'tags' : category + , 'publisher' : publisher + , 'language' : language + } + + keep_only_tags = [dict(attrs={'class':'txt'})] + remove_attributes = ['width','height'] + + feeds = [(u'Articles', u'http://www.expressindia.com/syndications/fe.xml')] + + def print_version(self, url): + article_raw = url.rpartition('/')[0] + article_id = article_raw.rpartition('/')[2] + return 'http://www.financialexpress.com/printer/news/' + article_id + '/' + + def preprocess_html(self, soup): + for item in soup.findAll(style=True): + del item['style'] + return soup diff --git a/src/calibre/customize/profiles.py b/src/calibre/customize/profiles.py index 85eae21b8d..1563f764ca 100644 --- a/src/calibre/customize/profiles.py +++ b/src/calibre/customize/profiles.py @@ -426,7 +426,7 @@ class KoboReaderOutput(OutputProfile): description = _('This profile is intended for the Kobo Reader.') - screen_size = (590, 775) + screen_size = (540, 718) comic_screen_size = (540, 718) dpi = 168.451 fbase = 12 diff --git a/src/calibre/gui2/dialogs/config/__init__.py b/src/calibre/gui2/dialogs/config/__init__.py index 0f66ed5dd4..3073a54774 100644 --- a/src/calibre/gui2/dialogs/config/__init__.py +++ b/src/calibre/gui2/dialogs/config/__init__.py @@ -515,15 +515,15 @@ class ConfigDialog(ResizableDialog, Ui_Dialog): 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.current_tweaks.setPlainText(curt.decode('utf-8')) + self.default_tweaks.setPlainText(deft.decode('utf-8')) 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) + self.current_tweaks.setPlainText(deft.decode('utf-8')) def reset_confirmation(self): @@ -698,8 +698,7 @@ class ConfigDialog(ResizableDialog, Ui_Dialog): self.input_order.setCurrentRow(idx-1) def set_tweaks(self): - raw = unicode(self.current_tweaks.toPlainText()) - raw = re.sub(r'(?m)^#.*fileencoding.*', '# ', raw) + raw = unicode(self.current_tweaks.toPlainText()).encode('utf-8') try: exec raw except: diff --git a/src/calibre/gui2/dialogs/config/create_custom_column.py b/src/calibre/gui2/dialogs/config/create_custom_column.py index 34091d893f..fdf093b6d5 100644 --- a/src/calibre/gui2/dialogs/config/create_custom_column.py +++ b/src/calibre/gui2/dialogs/config/create_custom_column.py @@ -100,11 +100,11 @@ class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn): def accept(self): - col = unicode(self.column_name_box.text()).lower() + col = unicode(self.column_name_box.text()) if not col: return self.simple_error('', _('No lookup name was provided')) - if re.match('^\w*$', col) is None or not col[0].isalpha(): - return self.simple_error('', _('The label must contain only letters, digits and underscores, and start with a letter')) + if re.match('^\w*$', col) is None or not col[0].isalpha() or col.lower() != col: + return self.simple_error('', _('The lookup name must contain only lower case letters, digits and underscores, and start with a letter')) col_heading = unicode(self.column_heading_box.text()) col_type = self.column_types[self.column_type_box.currentIndex()]['datatype'] if col_type == '*text': @@ -130,8 +130,6 @@ class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn): bad_head = True if bad_head: return self.simple_error('', _('The heading %s is already used')%col_heading) - if ':' in col or ' ' in col or col.lower() != col: - return self.simple_error('', _('The lookup name must be lower case and cannot contain ":"s or spaces')) date_format = {} if col_type == 'datetime': diff --git a/src/calibre/library/custom_columns.py b/src/calibre/library/custom_columns.py index 5b459c6d2a..b8e0f8d3b6 100644 --- a/src/calibre/library/custom_columns.py +++ b/src/calibre/library/custom_columns.py @@ -6,7 +6,7 @@ __license__ = 'GPL v3' __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' -import json +import json, re from functools import partial from math import floor @@ -430,6 +430,10 @@ class CustomColumns(object): def create_custom_column(self, label, name, datatype, is_multiple, editable=True, display={}): + if not label: + raise ValueError(_('No label was provided')) + if re.match('^\w*$', label) is None or not label[0].isalpha() or label.lower() != label: + raise ValueError(_('The label must contain only lower case letters, digits and underscores, and start with a letter')) if datatype not in self.CUSTOM_DATA_TYPES: raise ValueError('%r is not a supported data type'%datatype) normalized = datatype not in ('datetime', 'comments', 'int', 'bool', diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index 6a259a655f..36a31b78a2 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -419,7 +419,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): for format in formats: # Get data as string (can't use file as source and target files may be the same) f = self.format(id, format, index_is_id=True, as_file=False) - if not f: + if not f: continue stream = cStringIO.StringIO(f) self.add_format(id, format, stream, index_is_id=True, path=tpath) @@ -430,9 +430,31 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): if current_path and os.path.exists(spath): if self.normpath(spath) != self.normpath(tpath): self.rmtree(spath, permanent=True) - parent = os.path.dirname(spath) + parent = os.path.dirname(spath) if len(os.listdir(parent)) == 0: self.rmtree(parent, permanent=True) + curpath = self.library_path + c1, c2 = current_path.split('/'), path.split('/') + if not self.is_case_sensitive and len(c1) == len(c2): + # On case-insensitive systems, title and author renames that only + # change case don't cause any changes to the directories in the file + # system. This can lead to having the directory names not match the + # title/author, which leads to trouble when libraries are copied to + # a case-sensitive system. The following code fixes this by checking + # each segment. If they are different because of case, then rename + # the segment to some temp file name, then rename it back to the + # correct name. Note that the code above correctly handles files in + # the directories, so no need to do them here. + for oldseg, newseg in zip(c1, c2): + if oldseg.lower() == newseg.lower() and oldseg != newseg: + while True: + # need a temp name in the current segment for renames + tempname = os.path.join(curpath, 'TEMP.%f'%time.time()) + if not os.path.exists(tempname): + break + os.rename(os.path.join(curpath, oldseg), tempname) + os.rename(tempname, os.path.join(curpath, newseg)) + curpath = os.path.join(curpath, newseg) def add_listener(self, listener): '''