diff --git a/resources/recipes/people_us_mashup.recipe b/resources/recipes/people_us_mashup.recipe new file mode 100644 index 0000000000..2631ac5184 --- /dev/null +++ b/resources/recipes/people_us_mashup.recipe @@ -0,0 +1,93 @@ +#!/usr/bin/env python +__license__ = 'GPL v3' +''' +''' +from calibre.web.feeds.recipes import BasicNewsRecipe + +class PeopleMag(BasicNewsRecipe): + + title = 'People/US Magazine Mashup' + __author__ = 'BrianG' + language = 'en' + description = 'Headlines from People and US Magazine' + no_stylesheets = True + use_embedded_content = False + oldest_article = 2 + max_articles_per_feed = 50 + + extra_css = ''' + h1{font-family:verdana,arial,helvetica,sans-serif; font-size: large;} + h2{font-family:verdana,arial,helvetica,sans-serif; font-size: small;} + .body-content{font-family:verdana,arial,helvetica,sans-serif; font-size: small;} + .byline {font-size: small; color: #666666; font-style:italic; } + .lastline {font-size: small; color: #666666; font-style:italic;} + .contact {font-size: small; color: #666666;} + .contact p {font-size: small; color: #666666;} + .photoCaption { font-family:verdana,arial,helvetica,sans-serif; font-size:x-small;} + .photoCredit{ font-family:verdana,arial,helvetica,sans-serif; font-size:x-small; color:#666666;} + .article_timestamp{font-size:x-small; color:#666666;} + a {font-family:verdana,arial,helvetica,sans-serif; font-size: x-small;} + ''' + + + keep_only_tags = [ + dict(name='div', attrs={'class': 'panel_news_article_main'}), + dict(name='div', attrs={'class':'article_content'}), + dict(name='div', attrs={'class': 'headline'}), + dict(name='div', attrs={'class': 'post'}), + dict(name='div', attrs={'class': 'packageheadlines'}), + dict(name='div', attrs={'class': 'snap_preview'}), + dict(name='div', attrs={'id': 'articlebody'}) + ] + + remove_tags = [ + dict(name='div', attrs={'class':'share_comments'}), + dict(name='p', attrs={'class':'twitter_facebook'}), + dict(name='div', attrs={'class':'share_comments_bottom'}), + dict(name='h2', attrs={'id':'related_content'}), + dict(name='div', attrs={'class':'next_article'}), + dict(name='div', attrs={'class':'prev_article'}), + dict(name='ul', attrs={'id':'sharebar'}), + dict(name='div', attrs={'class':'sharelinkcont'}), + dict(name='div', attrs={'class':'categories'}), + dict(name='ul', attrs={'class':'categories'}), + dict(name='div', attrs={'id':'promo'}), + dict(name='div', attrs={'class':'linksWrapper'}), + dict(name='p', attrs={'class':'tag tvnews'}), + dict(name='p', attrs={'class':'tag movienews'}), + dict(name='p', attrs={'class':'tag musicnews'}), + dict(name='p', attrs={'class':'tag couples'}), + dict(name='p', attrs={'class':'tag gooddeeds'}), + dict(name='p', attrs={'class':'tag weddings'}), + dict(name='p', attrs={'class':'tag health'}) +] + + + feeds = [ + ('PEOPLE Headlines', 'http://feeds.people.com/people/headlines'), + ('US Headlines', 'http://www.usmagazine.com/celebrity_news/rss') + ] + + def get_article_url(self, article): + ans = article.link + + try: + self.log('Looking for full story link in', ans) + soup = self.index_to_soup(ans) + x = soup.find(text="View All") + + if x is not None: + ans = ans + '?viewAll=y' + self.log('Found full story link', ans) + except: + pass + return ans + + def postprocess_html(self, soup,first): + + for tag in soup.findAll(name='div',attrs={'class':"container_ate_qandatitle"}): + tag.extract() + for tag in soup.findAll(name='br'): + tag.extract() + + return soup diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index c04a200671..e2291aa427 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -464,6 +464,7 @@ plugins += [ IREXDR1000, JETBOOK, SHINEBOOK, + POCKETBOOK360, KINDLE, KINDLE2, KINDLE_DX, @@ -479,7 +480,6 @@ plugins += [ ESLICK, NUUT2, IRIVER_STORY, - POCKETBOOK360, GER2, ITALICA, ECLICTO, diff --git a/src/calibre/devices/eb600/driver.py b/src/calibre/devices/eb600/driver.py index 0e246f5c54..d84f3c3e77 100644 --- a/src/calibre/devices/eb600/driver.py +++ b/src/calibre/devices/eb600/driver.py @@ -16,7 +16,6 @@ Windows PNP strings: ''' from calibre.devices.usbms.driver import USBMS -from calibre.constants import iswindows class EB600(USBMS): @@ -88,17 +87,15 @@ class SHINEBOOK(EB600): @classmethod def can_handle(cls, dev, debug=False): - try: - if not iswindows: - return dev[4] == 'ShineBook' - except: - pass - return True + return dev[4] == 'ShineBook' class POCKETBOOK360(EB600): + # Device info on OS X + # (8069L, 5768L, 272L, u'', u'', u'1.00') + name = 'PocketBook 360 Device Interface' gui_name = 'PocketBook 360' @@ -112,6 +109,10 @@ class POCKETBOOK360(EB600): OSX_MAIN_MEM = 'Philips Mass Storge Media' OSX_CARD_A_MEM = 'Philips Mass Storge Media' + @classmethod + def can_handle(cls, dev, debug=False): + return dev[-1] == '1.00' and not dev[-2] and not dev[-3] + class GER2(EB600): name = 'Ganaxa GeR2 Device Interface' diff --git a/src/calibre/ebooks/pml/pmlml.py b/src/calibre/ebooks/pml/pmlml.py index aa14c560de..4f3d5f23df 100644 --- a/src/calibre/ebooks/pml/pmlml.py +++ b/src/calibre/ebooks/pml/pmlml.py @@ -211,11 +211,7 @@ class PMLMLizer(object): # Are we in a paragraph block? if tag in BLOCK_TAGS or style['display'] in BLOCK_STYLES: - if 'block' not in tag_stack+tags: - tags.append('block') - else: - # Start new block - text.append('\n\n') + tags.append('block') # Process tags that need special processing and that do not have inner # text. Usually these require an argument @@ -293,9 +289,6 @@ class PMLMLizer(object): if tag in SEPARATE_TAGS: text.append('\n\n') - if 'block' not in tag_stack+tags: - text.append('\n\n') - #if style['page-break-after'] == 'always': # text.append('\\p') @@ -305,9 +298,10 @@ class PMLMLizer(object): return text def close_tags(self, tags): - text = [u''] - for i in range(0, len(tags)): - tag = tags.pop() - if tag != 'block': + text = [] + for tag in tags: + if tag == 'block': + text.append('\n\n') + else: text.append('\\%s' % tag) return text diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index 39df62c74e..49f4476188 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -518,6 +518,10 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): ########################### Cover Flow ################################ self.cover_flow = None if CoverFlow is not None: + self.cf_last_updated_at = None + self.cover_flow_sync_timer = QTimer(self) + self.cover_flow_sync_timer.timeout.connect(self.cover_flow_do_sync) + self.cover_flow_sync_flag = True text_height = 40 if config['separate_cover_flow'] else 25 ah = available_height() cfh = ah-100 @@ -528,17 +532,15 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): self.cover_flow.setVisible(False) if not config['separate_cover_flow']: self.library.layout().addWidget(self.cover_flow) - #self.connect(self.cover_flow, SIGNAL('currentChanged(int)'), - # self.sync_cf_to_listview) + self.cover_flow.currentChanged.connect(self.sync_listview_to_cf) #self.connect(self.cover_flow, SIGNAL('itemActivated(int)'), # self.show_book_info) self.connect(self.status_bar.cover_flow_button, SIGNAL('toggled(bool)'), self.toggle_cover_flow) self.connect(self.cover_flow, SIGNAL('stop()'), self.status_bar.cover_flow_button.toggle) - #QObject.connect(self.library_view.selectionModel(), - # SIGNAL('currentRowChanged(QModelIndex, QModelIndex)'), - # self.sync_cf_to_listview) + self.library_view.selectionModel().currentRowChanged.connect( + self.sync_cf_to_listview) self.db_images = DatabaseImages(self.library_view.model()) self.cover_flow.setImages(self.db_images) else: @@ -684,7 +686,9 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): self.connect(d, SIGNAL('finished(int)'), self.uncheck_cover_button) self.cf_dialog = d + self.cover_flow_sync_timer.start(500) else: + self.cover_flow_sync_timer.stop() idx = self.library_view.model().index(self.cover_flow.currentSlide(), 0) if idx.isValid(): sm = self.library_view.selectionModel() @@ -705,7 +709,9 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): #self.status_bar.book_info.book_data.setMaximumHeight(100) #self.status_bar.setMaximumHeight(120) self.library_view.scrollTo(self.library_view.currentIndex()) + self.cover_flow_sync_timer.start(500) else: + self.cover_flow_sync_timer.stop() self.cover_flow.setVisible(False) idx = self.library_view.model().index(self.cover_flow.currentSlide(), 0) if idx.isValid(): @@ -731,14 +737,33 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): if view is self.current_view(): self.search.search_done(ok) - def sync_cf_to_listview(self, index, *args): - if not hasattr(index, 'row') and \ - self.library_view.currentIndex().row() != index: - index = self.library_view.model().index(index, 0) - self.library_view.setCurrentIndex(index) - if hasattr(index, 'row') and self.cover_flow.isVisible() and \ - self.cover_flow.currentSlide() != index.row(): - self.cover_flow.setCurrentSlide(index.row()) + def sync_cf_to_listview(self, current, previous): + if self.cover_flow_sync_flag and self.cover_flow.isVisible() and \ + self.cover_flow.currentSlide() != current.row(): + self.cover_flow.setCurrentSlide(current.row()) + self.cover_flow_sync_flag = True + + def cover_flow_do_sync(self): + self.cover_flow_sync_flag = True + try: + if self.cover_flow.isVisible() and self.cf_last_updated_at is not None and \ + time.time() - self.cf_last_updated_at > 0.5: + self.cf_last_updated_at = None + row = self.cover_flow.currentSlide() + m = self.library_view.model() + index = m.index(row, 0) + if self.library_view.currentIndex().row() != row and index.isValid(): + self.cover_flow_sync_flag = False + sm = self.library_view.selectionModel() + sm.select(index, sm.ClearAndSelect|sm.Rows) + self.library_view.setCurrentIndex(index) + except: + #raise + pass + + + def sync_listview_to_cf(self, row): + self.cf_last_updated_at = time.time() def another_instance_wants_to_talk(self): try: