From 4def2fe4a202656aa4b028d7b667859a46e9c2ee Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 11 Oct 2010 09:45:39 -0600 Subject: [PATCH 1/9] Fix tab order in bulk edit metadata dialog --- resources/content_server/browse/browse.js | 1 - src/calibre/gui2/dialogs/metadata_bulk.ui | 43 ++++++++++++++++++----- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/resources/content_server/browse/browse.js b/resources/content_server/browse/browse.js index 20b85df915..e2a8dc934a 100644 --- a/resources/content_server/browse/browse.js +++ b/resources/content_server/browse/browse.js @@ -105,7 +105,6 @@ function init_sort_combobox() { // }}} - function init() { $("#container").corner("30px"); $("#header").corner("30px"); diff --git a/src/calibre/gui2/dialogs/metadata_bulk.ui b/src/calibre/gui2/dialogs/metadata_bulk.ui index 60e24dbceb..3897d6dbf9 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.ui +++ b/src/calibre/gui2/dialogs/metadata_bulk.ui @@ -263,7 +263,7 @@ 20 - 00 + 0 @@ -357,13 +357,13 @@ from the value in the box - - Change title to title case - Force the title to be in title case. If both this and swap authors are checked, title and author are swapped before the title case is set + + Change title to title case + @@ -486,15 +486,15 @@ Future conversion of these books will use the default settings. - - Enter the what you are looking for, either plain text or a regular expression, depending on the mode - 100 0 + + Enter the what you are looking for, either plain text or a regular expression, depending on the mode + @@ -656,6 +656,14 @@ nothing should be put between the original text and the inserted text true + + + 0 + 0 + 122 + 34 + + @@ -733,14 +741,33 @@ nothing should be put between the original text and the inserted text author_sort rating publisher - tag_editor_button tags + tag_editor_button remove_tags + remove_all_tags series + clear_series autonumber_series + series_numbering_restarts + series_start_number remove_format + remove_conversion_settings swap_title_and_author + change_title_to_title_case button_box + central_widget + search_field + search_mode + search_for + case_sensitive + replace_with + replace_func + destination_field + replace_mode + comma_separated + scrollArea11 + test_text + test_result From 310b5c34b74a24c495359cc2b35c061abd21e580 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 11 Oct 2010 10:18:47 -0600 Subject: [PATCH 2/9] ... --- src/calibre/utils/smtp.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/calibre/utils/smtp.py b/src/calibre/utils/smtp.py index 77914bca3b..b8b46a96cb 100644 --- a/src/calibre/utils/smtp.py +++ b/src/calibre/utils/smtp.py @@ -11,6 +11,7 @@ This module implements a simple commandline SMTP client that supports: import sys, traceback, os from email import encoders +from calibre import isbytestring def create_mail(from_, to, subject, text=None, attachment_data=None, attachment_type=None, attachment_name=None): @@ -26,7 +27,10 @@ def create_mail(from_, to, subject, text=None, attachment_data=None, if text is not None: from email.mime.text import MIMEText - msg = MIMEText(text, 'plain', 'utf-8') + if isbytestring(text): + msg = MIMEText(text) + else: + msg = MIMEText(text, 'plain', 'utf-8') outer.attach(msg) if attachment_data is not None: From 64062c72ab77180b51ab16e404e300ef76260e48 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 11 Oct 2010 18:28:44 +0100 Subject: [PATCH 3/9] Force a database refresh after bulk metadata edit. --- src/calibre/gui2/actions/edit_metadata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/gui2/actions/edit_metadata.py b/src/calibre/gui2/actions/edit_metadata.py index 2a81a1500d..c46d77cd06 100644 --- a/src/calibre/gui2/actions/edit_metadata.py +++ b/src/calibre/gui2/actions/edit_metadata.py @@ -169,7 +169,7 @@ class EditMetadataAction(InterfaceAction): self.gui.tags_view.blockSignals(False) if changed: m = self.gui.library_view.model() - m.resort(reset=False) + m.refresh(reset=False) m.research() self.gui.tags_view.recount() if self.gui.cover_flow: From ef1ffb864c1a5c1bba97f3681c96f813b05a546f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 11 Oct 2010 14:06:23 -0600 Subject: [PATCH 4/9] More shadows :) --- resources/content_server/browse/browse.css | 5 ++++ src/calibre/library/server/opds.py | 30 ++++------------------ src/calibre/library/server/utils.py | 21 +++++++++++++++ 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/resources/content_server/browse/browse.css b/resources/content_server/browse/browse.css index 0f954a8647..f911b72104 100644 --- a/resources/content_server/browse/browse.css +++ b/resources/content_server/browse/browse.css @@ -82,6 +82,10 @@ body { -moz-border-radius: 5px; -webkit-border-radius: 5px; text-shadow: #27211b 1px 1px 1px; + -moz-box-shadow: 5px 5px 5px #222; + -webkit-box-shadow: 5px 5px 5px #ccc; + box-shadow: 5px 5px 5px #ccc; + } #nav-container { @@ -208,6 +212,7 @@ h2.library_name { -moz-box-shadow: 5px 5px 5px #ccc; -webkit-box-shadow: 5px 5px 5px #ccc; box-shadow: 5px 5px 5px #ccc; + text-shadow: #27211b 1px 1px 1px; } diff --git a/src/calibre/library/server/opds.py b/src/calibre/library/server/opds.py index f1aeb583db..16e7d34cbf 100644 --- a/src/calibre/library/server/opds.py +++ b/src/calibre/library/server/opds.py @@ -18,7 +18,7 @@ from calibre.constants import __appname__ from calibre.ebooks.metadata import fmt_sidx from calibre.library.comments import comments_to_html from calibre.library.server import custom_fields_to_display -from calibre.library.server.utils import format_tag_string +from calibre.library.server.utils import format_tag_string, Offsets from calibre import guess_type from calibre.utils.ordered_dict import OrderedDict @@ -321,26 +321,6 @@ class CategoryGroupFeed(NavFeed): self.root.append(CATALOG_GROUP_ENTRY(item, which, base_href, version, updated)) -class OPDSOffsets(object): - - def __init__(self, offset, delta, total): - if offset < 0: - offset = 0 - if offset >= total: - raise cherrypy.HTTPError(404, 'Invalid offset: %r'%offset) - last_allowed_index = total - 1 - last_current_index = offset + delta - 1 - self.offset = offset - self.next_offset = last_current_index + 1 - if self.next_offset > last_allowed_index: - self.next_offset = -1 - self.previous_offset = self.offset - delta - if self.previous_offset < 0: - self.previous_offset = 0 - self.last_offset = last_allowed_index - delta - if self.last_offset < 0: - self.last_offset = 0 - class OPDSServer(object): @@ -374,7 +354,7 @@ class OPDSServer(object): items = [x for x in self.db.data.iterall() if x[idx] in ids] self.sort(items, sort_by, ascending) max_items = self.opts.max_opds_items - offsets = OPDSOffsets(offset, max_items, len(items)) + offsets = Offsets(offset, max_items, len(items)) items = items[offsets.offset:offsets.offset+max_items] updated = self.db.last_modified() cherrypy.response.headers['Last-Modified'] = self.last_modified(updated) @@ -448,7 +428,7 @@ class OPDSServer(object): id_ = 'calibre-category-group-feed:'+category+':'+which max_items = self.opts.max_opds_items - offsets = OPDSOffsets(offset, max_items, len(items)) + offsets = Offsets(offset, max_items, len(items)) items = list(items)[offsets.offset:offsets.offset+max_items] cherrypy.response.headers['Last-Modified'] = self.last_modified(updated) @@ -495,7 +475,7 @@ class OPDSServer(object): if len(items) <= MAX_ITEMS: max_items = self.opts.max_opds_items - offsets = OPDSOffsets(offset, max_items, len(items)) + offsets = Offsets(offset, max_items, len(items)) items = list(items)[offsets.offset:offsets.offset+max_items] ans = CategoryFeed(items, which, id_, updated, version, offsets, page_url, up_url, self.db) @@ -516,7 +496,7 @@ class OPDSServer(object): getattr(y, 'sort', y.name).startswith(x)]) items = [Group(x, y) for x, y in category_groups.items()] max_items = self.opts.max_opds_items - offsets = OPDSOffsets(offset, max_items, len(items)) + offsets = Offsets(offset, max_items, len(items)) items = items[offsets.offset:offsets.offset+max_items] ans = CategoryGroupFeed(items, which, id_, updated, version, offsets, page_url, up_url) diff --git a/src/calibre/library/server/utils.py b/src/calibre/library/server/utils.py index 9a64948a3d..4c286b555b 100644 --- a/src/calibre/library/server/utils.py +++ b/src/calibre/library/server/utils.py @@ -13,6 +13,27 @@ from calibre import strftime as _strftime, prints from calibre.utils.date import now as nowf from calibre.utils.config import tweaks +class Offsets(object): + 'Calculate offsets for a paginated view' + + def __init__(self, offset, delta, total): + if offset < 0: + offset = 0 + if offset >= total: + raise cherrypy.HTTPError(404, 'Invalid offset: %r'%offset) + last_allowed_index = total - 1 + last_current_index = offset + delta - 1 + self.offset = offset + self.next_offset = last_current_index + 1 + if self.next_offset > last_allowed_index: + self.next_offset = -1 + self.previous_offset = self.offset - delta + if self.previous_offset < 0: + self.previous_offset = 0 + self.last_offset = last_allowed_index - delta + if self.last_offset < 0: + self.last_offset = 0 + def expose(func): From 867fb458a27ca0e9e28a6f1955622f4159e0e4b5 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 11 Oct 2010 14:06:55 -0600 Subject: [PATCH 5/9] ... --- resources/content_server/browse/browse.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/content_server/browse/browse.css b/resources/content_server/browse/browse.css index f911b72104..aaaa8d9c86 100644 --- a/resources/content_server/browse/browse.css +++ b/resources/content_server/browse/browse.css @@ -83,8 +83,8 @@ body { -webkit-border-radius: 5px; text-shadow: #27211b 1px 1px 1px; -moz-box-shadow: 5px 5px 5px #222; - -webkit-box-shadow: 5px 5px 5px #ccc; - box-shadow: 5px 5px 5px #ccc; + -webkit-box-shadow: 5px 5px 5px #222; + box-shadow: 5px 5px 5px #222; } From 6e6435913b23284b14fe633caa89af0db1ebfb48 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 11 Oct 2010 15:36:57 -0600 Subject: [PATCH 6/9] Enable drop indicator when dropping on Tag Browser --- src/calibre/gui2/tag_view.py | 187 ++++++++++++++++------------------- 1 file changed, 85 insertions(+), 102 deletions(-) diff --git a/src/calibre/gui2/tag_view.py b/src/calibre/gui2/tag_view.py index 88a9220024..8732aec63d 100644 --- a/src/calibre/gui2/tag_view.py +++ b/src/calibre/gui2/tag_view.py @@ -29,7 +29,7 @@ class TagDelegate(QItemDelegate): # {{{ def paint(self, painter, option, index): item = index.internalPointer() - if item.type != TagTreeItem.TAG: + if True or item.type != TagTreeItem.TAG: QItemDelegate.paint(self, painter, option, index) return r = option.rect @@ -89,7 +89,8 @@ class TagsView(QTreeView): # {{{ self.hidden_categories = config['tag_browser_hidden_categories'] self._model = TagsModel(db, parent=self, hidden_categories=self.hidden_categories, - search_restriction=None) + search_restriction=None, + drag_drop_finished=self.drag_drop_finished) self.sort_by = sort_by self.tag_match = tag_match self.db = db @@ -109,103 +110,6 @@ class TagsView(QTreeView): # {{{ def database_changed(self, event, ids): self.refresh_required.emit() - def dragEnterEvent(self, event): - md = event.mimeData() - if md.hasFormat("application/calibre+from_library"): - event.setDropAction(Qt.CopyAction) - event.accept() - else: - event.ignore() - - def dragMoveEvent(self, event): - allowed = False - idx = self.indexAt(event.pos()) - m = self.model() - p = m.parent(idx) - if idx.isValid() and p.isValid(): - item = m.data(p, Qt.UserRole) - fm = self.db.metadata_for_field(item.category_key) - if item.category_key in \ - ('tags', 'series', 'authors', 'rating', 'publisher') or\ - (fm['is_custom'] and \ - fm['datatype'] in ['text', 'rating', 'series']): - allowed = True - if allowed: - event.acceptProposedAction() - else: - event.ignore() - - def dropEvent(self, event): - idx = self.indexAt(event.pos()) - m = self.model() - p = m.parent(idx) - if idx.isValid() and p.isValid(): - item = m.data(p, Qt.UserRole) - if item.type == TagTreeItem.CATEGORY: - fm = self.db.metadata_for_field(item.category_key) - if item.category_key in \ - ('tags', 'series', 'authors', 'rating', 'publisher') or\ - (fm['is_custom'] and \ - fm['datatype'] in ['text', 'rating', 'series']): - child = m.data(idx, Qt.UserRole) - md = event.mimeData() - mime = 'application/calibre+from_library' - ids = list(map(int, str(md.data(mime)).split())) - self.handle_drop(item, child, ids) - event.accept() - return - event.ignore() - - def handle_drop(self, parent, child, ids): - # print 'Dropped ids:', ids, parent.category_key, child.tag.name - key = parent.category_key - if (key == 'authors' and len(ids) >= 5): - if not confirm('

'+_('Changing the authors for several books can ' - 'take a while. Are you sure?') - +'

', 'tag_browser_drop_authors', self): - return - elif len(ids) > 15: - if not confirm('

'+_('Changing the metadata for that many books ' - 'can take a while. Are you sure?') - +'

', 'tag_browser_many_changes', self): - return - - fm = self.db.metadata_for_field(key) - is_multiple = fm['is_multiple'] - val = child.tag.name - for id in ids: - mi = self.db.get_metadata(id, index_is_id=True) - - # Prepare to ignore the author, unless it is changed. Title is - # always ignored -- see the call to set_metadata - set_authors = False - - # Author_sort cannot change explicitly. Changing the author might - # change it. - mi.author_sort = None # Never will change by itself. - - if key == 'authors': - mi.authors = [val] - set_authors=True - elif fm['datatype'] == 'rating': - mi.set(key, len(val) * 2) - elif fm['is_custom'] and fm['datatype'] == 'series': - mi.set(key, val, extra=1.0) - elif is_multiple: - new_val = mi.get(key, []) - if val in new_val: - # Fortunately, only one field can change, so the continue - # won't break anything - continue - new_val.append(val) - mi.set(key, new_val) - else: - mi.set(key, val) - self.db.set_metadata(id, mi, set_title=False, - set_authors=set_authors, commit=False) - self.db.commit() - self.drag_drop_finished.emit(ids) - @property def match_all(self): return self.tag_match and self.tag_match.currentIndex() > 0 @@ -374,7 +278,8 @@ class TagsView(QTreeView): # {{{ try: self._model = TagsModel(self.db, parent=self, hidden_categories=self.hidden_categories, - search_restriction=self.search_restriction) + search_restriction=self.search_restriction, + drag_drop_finished=self.drag_drop_finished) self.setModel(self._model) except: # The DB must be gone. Set the model to None and hope that someone @@ -469,7 +374,8 @@ class TagTreeItem(object): # {{{ class TagsModel(QAbstractItemModel): # {{{ - def __init__(self, db, parent, hidden_categories=None, search_restriction=None): + def __init__(self, db, parent, hidden_categories=None, + search_restriction=None, drag_drop_finished=None): QAbstractItemModel.__init__(self, parent) # must do this here because 'QPixmap: Must construct a QApplication @@ -487,6 +393,7 @@ class TagsModel(QAbstractItemModel): # {{{ ':user' : QIcon(I('drawer.png')), 'search' : QIcon(I('search.png'))}) self.categories_with_ratings = ['authors', 'series', 'publisher', 'tags'] + self.drag_drop_finished = drag_drop_finished self.icon_state_map = [None, QIcon(I('plus.png')), QIcon(I('minus.png'))] self.db = db @@ -519,6 +426,82 @@ class TagsModel(QAbstractItemModel): # {{{ tag.avg_rating = None TagTreeItem(parent=c, data=tag, icon_map=self.icon_state_map) + def mimeTypes(self): + return ["application/calibre+from_library"] + + def dropMimeData(self, md, action, row, column, parent): + if not md.hasFormat("application/calibre+from_library") or \ + action != Qt.CopyAction: + return False + idx = parent + p = self.parent(idx) + if idx.isValid() and p.isValid(): + item = self.data(p, Qt.UserRole) + fm = self.db.metadata_for_field(item.category_key) + if item.category_key in \ + ('tags', 'series', 'authors', 'rating', 'publisher') or \ + (fm['is_custom'] and \ + fm['datatype'] in ['text', 'rating', 'series']): + child = self.data(idx, Qt.UserRole) + mime = 'application/calibre+from_library' + ids = list(map(int, str(md.data(mime)).split())) + self.handle_drop(item, child, ids) + return True + return False + + + def handle_drop(self, parent, child, ids): + # print 'Dropped ids:', ids, parent.category_key, child.tag.name + key = parent.category_key + if (key == 'authors' and len(ids) >= 5): + if not confirm('

'+_('Changing the authors for several books can ' + 'take a while. Are you sure?') + +'

', 'tag_browser_drop_authors', self.parent()): + return + elif len(ids) > 15: + if not confirm('

'+_('Changing the metadata for that many books ' + 'can take a while. Are you sure?') + +'

', 'tag_browser_many_changes', self.parent()): + return + + fm = self.db.metadata_for_field(key) + is_multiple = fm['is_multiple'] + val = child.tag.name + for id in ids: + mi = self.db.get_metadata(id, index_is_id=True) + + # Prepare to ignore the author, unless it is changed. Title is + # always ignored -- see the call to set_metadata + set_authors = False + + # Author_sort cannot change explicitly. Changing the author might + # change it. + mi.author_sort = None # Never will change by itself. + + if key == 'authors': + mi.authors = [val] + set_authors=True + elif fm['datatype'] == 'rating': + mi.set(key, len(val) * 2) + elif fm['is_custom'] and fm['datatype'] == 'series': + mi.set(key, val, extra=1.0) + elif is_multiple: + new_val = mi.get(key, []) + if val in new_val: + # Fortunately, only one field can change, so the continue + # won't break anything + continue + new_val.append(val) + mi.set(key, new_val) + else: + mi.set(key, val) + self.db.set_metadata(id, mi, set_title=False, + set_authors=set_authors, commit=False) + self.db.commit() + self.drag_drop_finished.emit(ids) + + + def set_search_restriction(self, s): self.search_restriction = s @@ -655,7 +638,7 @@ class TagsModel(QAbstractItemModel): # {{{ return ans def supportedDropActions(self): - return Qt.CopyAction|Qt.MoveAction + return Qt.CopyAction def path_for_index(self, index): ans = [] From 471aac1bc7b5ef9be0cf5000d5c5d185a992ad41 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 11 Oct 2010 15:40:40 -0600 Subject: [PATCH 7/9] More informative error message when NUL file missing on windows --- src/calibre/utils/ipc/launch.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/calibre/utils/ipc/launch.py b/src/calibre/utils/ipc/launch.py index 8d3628d69a..a179f356be 100644 --- a/src/calibre/utils/ipc/launch.py +++ b/src/calibre/utils/ipc/launch.py @@ -14,7 +14,10 @@ from calibre.ptempfile import PersistentTemporaryFile, base_dir if iswindows: import win32process - _windows_null_file = open(os.devnull, 'wb') + try: + _windows_null_file = open(os.devnull, 'wb') + except: + raise RuntimeError('NUL %r file missing in windows'%os.devnull) class Worker(object): ''' From 608d1e1468b3c99104c9674a813d501867d8ee05 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 11 Oct 2010 17:33:01 -0600 Subject: [PATCH 8/9] Forgot white<->yellow workaround when adding borders during comic processing --- src/calibre/ebooks/comic/input.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/ebooks/comic/input.py b/src/calibre/ebooks/comic/input.py index 23f5906a53..04d097ac67 100755 --- a/src/calibre/ebooks/comic/input.py +++ b/src/calibre/ebooks/comic/input.py @@ -94,7 +94,7 @@ class PageProcessor(list): from calibre.utils.magick import PixelWand for i, wand in enumerate(self.pages): pw = PixelWand() - pw.color = 'white' + pw.color = '#ffffff' wand.set_border_color(pw) if self.rotate: From 6e2987ad49dc382fd11e70cf5da811f59fc4b3c8 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 11 Oct 2010 19:03:45 -0600 Subject: [PATCH 9/9] Rolling Stones by Tony Stegall --- resources/images/news/rstones.png | Bin 0 -> 1318 bytes resources/recipes/rstones.recipe | 82 ++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 resources/images/news/rstones.png create mode 100644 resources/recipes/rstones.recipe diff --git a/resources/images/news/rstones.png b/resources/images/news/rstones.png new file mode 100644 index 0000000000000000000000000000000000000000..7f6159c13c3f6e74bcf1258a10a37d71caf9dc46 GIT binary patch literal 1318 zcmZ9Me>l?#9LK*~Y$GvNYv)lm^y7rvW{)2uhHo~lMoTJ|-wj7BWA|X#B}FP^$R+($ z=h1A-QGSFX+DXl2n;ySbS10+kPT7$kx9YFE&+~bIUZ3alJgurGT2VE#suf;be7y}#gN=@FmB8g8Ckntcq?}6hu`gGH!jN%#6{7mIe@vPgJsp3c5 z(mt~|`;$Te69gzAsE0Jb>0K2fL4gundddUBjntnzcy2%u@&3J}%&^_(qs|H`Ps~qw zcVjvs5JBhN{W#$JC~55aJkXa)rRD(M98Lz`5({k}NnV%^>A*ba9%*dIr^%c`LfTR4 zGr4#e@cP3_R=BDzUgZ!5yWY?DxB?d@Tl7GLXL>fBZtqy#Jg=RLsrmR?Uo-JyU?40T zLaBY5X7PgsETG1wBqs+f-A$~JAsdEzdw1*rM;wX?V4a(1_PFuBY9d||V^XZFn@lq* zQi63Yckj0D2^8I8PLTGAg0{0-Y0-P?U&cyItgiD~0&Pq4Mjy~`YiG8kuX%wq1ro}x}k8xZ|{BA>V7TeHkv6|(E2InM998Mq-F(($dR~6}tDRKEYsGzOQ znrdvxM%WE7p*Xq|P7r_?9Bxhj)V&T{?2@_IWzdm&#r<$FG(Cgc^eUn;3O@CZN}QaQ zTKdBDgluR!8RzyBjEBw$`IR70QfRx`)w6S_UvWf@QV4&!S)$QIP^xHe2BkNs_pF~9 zpQ};4Pn`iwk%eLR@gBxDX1R}=xRpqNWL~&=LqS5!*)1N(zcaINCq*3?k?a0v7q?r$ ztcqEQt1F&0f4QJgB_-~gIy)&gMB;^BeQni2J9Gi1-qkZ(>i`cjln4LLfFoX(ZGVhe zDSsTins^{K99v-|Q8kCIY9Il&#d$rhnkO{8cC4+hZ=?lIy2RybXV-MoWO50aCfg)z zd_3Yn&#kT^l<_J4Ch`|0y~o6NMzZFo-qO``ivXk$~(1J?Kwyd`LaTx5+D99A9xDO8Xs3tj>&tkQ+D~dPDT2R{JgJ9~T1<^5DEgRb6Z-TZ$>7?b*AR0hJCe%;iEg&dxclM@>d& z-{}6#mXuwGQlcYLj*_F2kLmyr@dUj6mnH-fT*-Jmnc!%TchW6ZWG?(a!m*_2ICk3q a1R{y-Nctw^Mo!M@1i)_>1FZ87Kk+Z%lt>5w literal 0 HcmV?d00001 diff --git a/resources/recipes/rstones.recipe b/resources/recipes/rstones.recipe new file mode 100644 index 0000000000..fa09701e15 --- /dev/null +++ b/resources/recipes/rstones.recipe @@ -0,0 +1,82 @@ +#!/usr/bin/env python +__license__ = 'GPL v3' +__author__ = 'Tony Stegall' +__copyright__ = '2010, Tony Stegall or Tonythebookworm on mobileread.com' +__version__ = 'v1.01' +__date__ = '07, October 2010' +__description__ = 'Rolling Stones Mag' + +''' +http://www.rollingstone.com +''' + +from calibre.web.feeds.news import BasicNewsRecipe + +class RollingStones(BasicNewsRecipe): + __author__ = 'Tony Stegall' + description = 'Rolling Stones Mag' + cover_url = 'http://gallery.celebritypro.com/data/media/648/kid-rock-rolling-stone-cover.jpg' + masthead_url = 'http://origin.myfonts.com/s/ec/cc-200804/Rolling_Stone-logo.gif' + + + title = 'Rolling Stones Mag' + category = 'Music Reviews, Movie Reviews, entertainment news' + + language = 'en' + timefmt = '[%a, %d %b, %Y]' + + oldest_article = 15 + max_articles_per_feed = 25 + use_embedded_content = False + no_stylesheets = True + + remove_javascript = True + ##################################################################################### + # cleanup section # + ##################################################################################### + keep_only_tags = [ + dict(name='div', attrs={'class':['c65l']}), + dict(name='div', attrs={'id':['col1']}), + + + ] + remove_tags = [ + dict(name='div', attrs={'class': ['storyActions upper','storyActions lowerArticleNav']}), + dict(name='div', attrs={'id': ['comments','related']}), + ] + + + feeds = [ + (u'News', u'http://www.rollingstone.com/siteServices/rss/allNews'), + (u'Blogs', u'http://www.rollingstone.com/siteServices/rss/allBlogs'), + (u'Movie Reviews', u'http://www.rollingstone.com/siteServices/rss/movieReviews'), + (u'Album Reviews', u'http://www.rollingstone.com/siteServices/rss/albumReviews'), + (u'Song Reviews', u'http://www.rollingstone.com/siteServices/rss/songReviews'), + + + ] + + + + def get_article_url(self, article): + return article.get('guid', None) + + + def append_page(self, soup, appendtag, position): + ''' + Some are the articles are multipage so the below function + will get the articles that have + ''' + pager = soup.find('li',attrs={'class':'next'}) + if pager: + nexturl = pager.a['href'] + soup2 = self.index_to_soup(nexturl) + texttag = soup2.find('div', attrs={'id':'storyTextContainer'}) + for it in texttag.findAll(style=True): + del it['style'] + newpos = len(texttag.contents) + self.append_page(soup2,texttag,newpos) + texttag.extract() + appendtag.insert(position,texttag) + +