From 02e372769d37f5e8ce549f96488fc304eb12f9b4 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 16 Dec 2009 08:32:21 -0700 Subject: [PATCH 01/23] Improved recipe for Welt --- resources/recipes/welt.recipe | 24 ++++++++++++++++---- src/calibre/ebooks/pdf/reflow.py | 38 +++++++++++++++++++++++++++----- 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/resources/recipes/welt.recipe b/resources/recipes/welt.recipe index b1bf20235d..4c90853c82 100644 --- a/resources/recipes/welt.recipe +++ b/resources/recipes/welt.recipe @@ -15,12 +15,13 @@ class weltDe(BasicNewsRecipe): __author__ = 'Oliver Niesner' use_embedded_content = False timefmt = ' [%d %b %Y]' - max_articles_per_feed = 15 # reduced to this value to prevent too many articles (suggested by Gregory Riker + max_articles_per_feed = 15 + linearize_tables = True no_stylesheets = True remove_stylesheets = True remove_javascript = True - language = 'de' encoding = 'iso-8859-1' + BasicNewsRecipe.summary_length = 200 remove_tags = [dict(id='jumplinks'), @@ -43,10 +44,14 @@ class weltDe(BasicNewsRecipe): dict(id='servicesBox'), dict(id='toggleAdvancedSearch'), dict(id='mainNav'), - dict(id='ratingBox5136466_1'), - dict(id='ratingBox5136466_2'), dict(id='articleInlineMediaBox0'), dict(id='sectionSponsor'), + dict(id='sprucharea'), + dict(id='xmsg_recommendEmail'), + dict(id='xmsg_recommendSms'), + dict(id='xmsg_comment'), + dict(id='additionalNavWrapper'), + dict(id='imagebox'), #dict(id=''), dict(name='span'), dict(name='div', attrs={'class':'printURL'}), @@ -65,10 +70,21 @@ class weltDe(BasicNewsRecipe): dict(name='ul', attrs={'class':'optionsSubNav clear'}), dict(name='li', attrs={'class':'next'}), dict(name='li', attrs={'class':'prev'}), + dict(name='li', attrs={'class':'last'}), + dict(name='table', attrs={'class':'textGallery'}), dict(name='li', attrs={'class':'active'})] remove_tags_after = [dict(id='tw_link_widget')] + extra_css = ''' + h2{font-family:Arial,Helvetica,sans-serif; font-size: x-small; color: #003399;} + a{font-family:Arial,Helvetica,sans-serif; font-size: x-small; font-style:italic;} + .dachzeile p{font-family:Arial,Helvetica,sans-serif; font-size: x-small; } + h1{ font-family:Arial,Helvetica,sans-serif; font-size:x-large; font-weight:bold;} + .artikelTeaser{font-family:Arial,Helvetica,sans-serif; font-size: x-small; font-weight:bold; } + body{font-family:Arial,Helvetica,sans-serif; } + .photo {font-family:Arial,Helvetica,sans-serif; font-size: x-small; color: #666666;} ''' + feeds = [ ('Politik', 'http://welt.de/politik/?service=Rss'), ('Deutsche Dinge', 'http://www.welt.de/deutsche-dinge/?service=Rss'), ('Wirtschaft', 'http://welt.de/wirtschaft/?service=Rss'), diff --git a/src/calibre/ebooks/pdf/reflow.py b/src/calibre/ebooks/pdf/reflow.py index 53be9a23de..72ca7f0d1c 100644 --- a/src/calibre/ebooks/pdf/reflow.py +++ b/src/calibre/ebooks/pdf/reflow.py @@ -78,7 +78,7 @@ class HorizontalBox(object): def append(self, t): self.texts.append(t) - def sort(self): + def sort(self, left_margin, right_margin): self.texts.sort(cmp=lambda x,y: cmp(x.left, y.left)) self.top, self.bottom = sys.maxint, 0 for t in self.texts: @@ -86,6 +86,27 @@ class HorizontalBox(object): self.bottom = max(self.bottom, t.bottom) self.left = self.texts[0].left self.right = self.texts[-1].right + self.gaps = [] + for i, t in enumerate(self.texts[1:]): + gap = Interval(self.texts[i].right, t.left) + if gap.width > 3: + self.gaps.append(gap) + left = Interval(left_margin, self.texts[0].left) + if left.width > 3: + self.gaps.insert(0, left) + right = Interval(self.texts[-1].right, right_margin) + if right.width > 3: + self.gaps.append(right) + + def has_intersection_with(self, gap): + for g in self.gaps: + if g.intersection(gap): + return True + return False + + def identify_columns(self, column_gaps): + self.number_of_columns = len(column_gaps) + 1 + class Page(object): @@ -138,19 +159,24 @@ class Page(object): for hb in self.horizontal_boxes: - hb.sort() + hb.sort(self.left_margin, self.right_margin) self.horizontal_boxes.sort(cmp=lambda x,y: cmp(x.bottom, y.bottom)) def identify_columns(self): def neighborhood(i): - if i == 0: - return self.horizontal_boxes[1:3] - return (self.horizontal_boxes[i-1], self.horizontal_boxes[i+1]) + if i == len(self.horizontal_boxes)-1: + return self.horizontal_boxes[i-2:i] + if i == len(self.horizontal_boxes)-2: + return (self.horizontal_boxes[i-1], self.horizontal_boxes[i+1]) + return self.horizontal_boxes[i+1], self.horizontal_boxes[i+2] for i, hbox in enumerate(self.horizontal_boxes): - pass + n1, n2 = neighborhood(i) + for gap in hbox.gaps: + gap.is_column_gap = n1.has_intersection_with(gap) and \ + n2.has_intersection_with(gap) From 96d90ebd0f0eab5c73bc5d278ee3c54d96b4fa13 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 16 Dec 2009 08:57:07 -0700 Subject: [PATCH 02/23] Driver for Nokia N810 (windows and linux) --- src/calibre/customize/builtins.py | 3 ++- src/calibre/devices/eb600/driver.py | 4 ++-- src/calibre/devices/nokia/driver.py | 18 +++++++++++++++--- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index 1ea76a2189..ed942b5a9a 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -413,7 +413,7 @@ from calibre.devices.nook.driver import NOOK from calibre.devices.prs500.driver import PRS500 from calibre.devices.prs505.driver import PRS505, PRS700 from calibre.devices.android.driver import ANDROID -from calibre.devices.nokia.driver import N770 +from calibre.devices.nokia.driver import N770, N810 from calibre.devices.eslick.driver import ESLICK from calibre.devices.nuut2.driver import NUUT2 from calibre.devices.iriver.driver import IRIVER_STORY @@ -470,6 +470,7 @@ plugins += [ PRS500, ANDROID, N770, + N810, CYBOOK_OPUS, COOL_ER, ESLICK, diff --git a/src/calibre/devices/eb600/driver.py b/src/calibre/devices/eb600/driver.py index 18e86fb238..07217ac78d 100644 --- a/src/calibre/devices/eb600/driver.py +++ b/src/calibre/devices/eb600/driver.py @@ -104,8 +104,8 @@ class GER2(EB600): FORMATS = ['pdf'] - VENDOR_ID = [0xbda] - PRODUCT_ID = [0x703] + VENDOR_ID = [0x3034] + PRODUCT_ID = [0x1795] BCD = [0x132] VENDOR_NAME = 'GANAXA' diff --git a/src/calibre/devices/nokia/driver.py b/src/calibre/devices/nokia/driver.py index e6944de4d9..7bd1dbb28d 100644 --- a/src/calibre/devices/nokia/driver.py +++ b/src/calibre/devices/nokia/driver.py @@ -22,9 +22,9 @@ class N770(USBMS): FORMATS = ['mobi', 'prc', 'epub', 'html', 'zip', 'fb2', 'chm', 'pdb', 'tcr', 'txt', 'rtf'] - VENDOR_ID = [0x111] - PRODUCT_ID = [0x1af] - BCD = [0x134] + VENDOR_ID = [0x421] + PRODUCT_ID = [0x431] + BCD = [0x308] VENDOR_NAME = 'NOKIA' WINDOWS_MAIN_MEM = '770' @@ -33,3 +33,15 @@ class N770(USBMS): EBOOK_DIR_MAIN = 'My Ebooks' SUPPORTS_SUB_DIRS = True + +class N810(N770): + name = 'Nokia 810 Device Interface' + gui_name = 'Nokia 810' + description = _('Communicate with the Nokia Nokia 810 internet tablet.') + + PRODUCT_ID = [0x96] + BCD = [0x316] + + WINDOWS_MAIN_MEM = 'N810' + + MAIN_MEMORY_VOLUME_LABEL = 'N810 Main Memory' From 7d22f36134de6911aea7d407452b76c218557f47 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 16 Dec 2009 08:59:15 -0700 Subject: [PATCH 03/23] New recipe for The Clarion Ledger by cr4zyd --- resources/recipes/clarion_ledger.recipe | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 resources/recipes/clarion_ledger.recipe diff --git a/resources/recipes/clarion_ledger.recipe b/resources/recipes/clarion_ledger.recipe new file mode 100644 index 0000000000..e36cae652e --- /dev/null +++ b/resources/recipes/clarion_ledger.recipe @@ -0,0 +1,20 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +class ClarionLedger(BasicNewsRecipe): + title = u'Clarion Ledger' + oldest_article = 7 + max_articles_per_feed = 100 + no_stylesheets = True + language = 'en' + __author__ = 'cr4zyd' + + feeds = [(u'Local News', u'http://www.clarionledger.com/apps/pbcs.dll/oversikt?Category=RSS01'), (u'Breaking News', u'http://www.clarionledger.com/apps/pbcs.dll/section?Category=RSS'), (u'Sports', u'http://www.clarionledger.com/apps/pbcs.dll/oversikt?Category=RSS02'), (u'Business', u'http://www.clarionledger.com/apps/pbcs.dll/oversikt?Category=RSS03')] + + keep_only_tags = [dict(name='div', attrs={'class':'article-headline'}), + dict(name='div', attrs={'class':'article-bodytext'})] + remove_tags = [dict(name=['img','script','li']), + dict(name='p', attrs={'class':'ratingbyline'}), + dict(name='div', attrs={'class':'article-tools'}), + dict(name='div', attrs={'class':'article-pagination article-pagination-top'}), + dict(name='div', attrs={'class':'article-pagination article-pagination-bottom'}), + dict(name='div', attrs={'class':'articleflex-container'})] From 4b9dd7e410be0f078ec23ecc9cb93b75b725c4e5 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 16 Dec 2009 09:07:22 -0700 Subject: [PATCH 04/23] PML Output: Change \C1 to \C0 --- src/calibre/ebooks/pml/pmlml.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/ebooks/pml/pmlml.py b/src/calibre/ebooks/pml/pmlml.py index ccce95fce6..c8acf2487e 100644 --- a/src/calibre/ebooks/pml/pmlml.py +++ b/src/calibre/ebooks/pml/pmlml.py @@ -232,7 +232,7 @@ class PMLMLizer(object): if self.toc.get(page.href, None): toc_title = self.toc[page.href].get(toc_id, None) if toc_title: - text.append('\\C1="%s"' % toc_title) + text.append('\\C0="%s"' % toc_title) # Process style information that needs holds a single tag # Commented out because every page in an OEB book starts with this style From 5f77f23c616cfbdf748c0ebd713e06d66b09cc3c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 16 Dec 2009 11:42:01 -0700 Subject: [PATCH 05/23] By default the calibre system tray icon is now disabled as users on windows and OSX don't seem to be able to grasp the concept --- src/calibre/gui2/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 7363498319..1faad6c77f 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -52,7 +52,7 @@ def _config(): help=_('Columns to be displayed in the book list')) c.add_opt('autolaunch_server', default=False, help=_('Automatically launch content server on application startup')) c.add_opt('oldest_news', default=60, help=_('Oldest news kept in database')) - c.add_opt('systray_icon', default=True, help=_('Show system tray icon')) + c.add_opt('systray_icon', default=False, help=_('Show system tray icon')) c.add_opt('upload_news_to_device', default=True, help=_('Upload downloaded news to device')) c.add_opt('delete_news_from_library_on_upload', default=False, From 53634e6eae32cf9d5205b535ff0d32d83d5ea314 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 16 Dec 2009 11:42:29 -0700 Subject: [PATCH 06/23] Updated recipe for El Mundo --- resources/recipes/elmundo.recipe | 33 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/resources/recipes/elmundo.recipe b/resources/recipes/elmundo.recipe index 71e9008166..aea60de304 100644 --- a/resources/recipes/elmundo.recipe +++ b/resources/recipes/elmundo.recipe @@ -1,4 +1,3 @@ -#!/usr/bin/env python __license__ = 'GPL v3' __copyright__ = '2009, Darko Miletic ' @@ -19,22 +18,19 @@ class ElMundo(BasicNewsRecipe): no_stylesheets = True use_embedded_content = False encoding = 'iso8859_15' - cover_url = 'http://estaticos02.cache.el-mundo.net/papel/imagenes/v2.0/logoverde.gif' - remove_javascript = True + language = 'es' - html2lrf_options = [ - '--comment', description - , '--category', category - , '--publisher', publisher - ] + conversion_options = { + 'comments' : description + ,'tags' : category + ,'language' : language + ,'publisher' : publisher + } - html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"' + keep_only_tags = [dict(name='div', attrs={'class':'noticia'})] + remove_tags_before = dict(attrs={'class':['titular','antetitulo'] }) + remove_tags_after = dict(name='div' , attrs={'id':['desarrollo_noticia','tamano']}) - - keep_only_tags = [ - dict(name='div', attrs={'id':['bloqueprincipal','noticia']}) - ,dict(name='div', attrs={'class':['contenido_noticia_01']}) - ] remove_tags = [ dict(name='div', attrs={'class':['herramientas','publicidad_google']}) ,dict(name='div', attrs={'id':'modulo_multimedia' }) @@ -44,6 +40,8 @@ class ElMundo(BasicNewsRecipe): feeds = [ (u'Portada' , u'http://rss.elmundo.es/rss/descarga.htm?data2=4' ) + ,(u'Deportes' , u'http://rss.elmundo.es/rss/descarga.htm?data2=14') + ,(u'Economia' , u'http://rss.elmundo.es/rss/descarga.htm?data2=7' ) ,(u'Espana' , u'http://rss.elmundo.es/rss/descarga.htm?data2=8' ) ,(u'Internacional' , u'http://rss.elmundo.es/rss/descarga.htm?data2=9' ) ,(u'Cultura' , u'http://rss.elmundo.es/rss/descarga.htm?data2=6' ) @@ -51,10 +49,3 @@ class ElMundo(BasicNewsRecipe): ,(u'Comunicacion' , u'http://rss.elmundo.es/rss/descarga.htm?data2=26') ,(u'Television' , u'http://rss.elmundo.es/rss/descarga.htm?data2=76') ] - - def preprocess_html(self, soup): - for item in soup.findAll(style=True): - del item['style'] - return soup - - language = 'es' From abedc5be42607db93fd88ca2f2030a1351942eef Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 16 Dec 2009 11:44:37 -0700 Subject: [PATCH 07/23] Fix #4228 (Error getting feed source) From c70adff6bfedbce5043ec0852fc5dca9c68a9ea3 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 16 Dec 2009 12:23:39 -0700 Subject: [PATCH 08/23] Fix #4226 (London Review of Books fails to load completely. An index and table of contents is the only pages in the feed.) --- resources/recipes/lrb.recipe | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/resources/recipes/lrb.recipe b/resources/recipes/lrb.recipe index 8c248b00f1..0076b3e697 100644 --- a/resources/recipes/lrb.recipe +++ b/resources/recipes/lrb.recipe @@ -1,4 +1,3 @@ -#!/usr/bin/env python __license__ = 'GPL v3' __copyright__ = '2008, Darko Miletic ' @@ -12,30 +11,29 @@ class LondonReviewOfBooks(BasicNewsRecipe): title = u'London Review of Books' __author__ = u'Darko Miletic' description = u'Literary review publishing essay-length book reviews and topical articles on politics, literature, history, philosophy, science and the arts by leading writers and thinkers' + category = 'news, literature, England' + publisher = 'London Review of Books' oldest_article = 7 max_articles_per_feed = 100 - language = 'en_GB' - + language = 'en_GB' no_stylesheets = True use_embedded_content = False - encoding = 'cp1252' + encoding = 'utf-8' + conversion_options = { + 'comments' : description + ,'tags' : category + ,'language' : language + ,'publisher' : publisher + } + + keep_only_tags = [dict(name='div' , attrs={'id' :'main'})] remove_tags = [ - dict(name='div' , attrs={'id' :'otherarticles'}) - ,dict(name='div' , attrs={'class':'pagetools' }) - ,dict(name='div' , attrs={'id' :'mainmenu' }) - ,dict(name='div' , attrs={'id' :'precontent' }) - ,dict(name='div' , attrs={'class':'nocss' }) - ,dict(name='span', attrs={'class':'inlineright' }) + dict(name='div' , attrs={'class':['pagetools','issue-nav-controls','nocss']}) + ,dict(name='div' , attrs={'id' :['mainmenu','precontent','otherarticles'] }) + ,dict(name='span', attrs={'class':['inlineright','article-icons']}) + ,dict(name='ul' , attrs={'class':'article-controls'}) + ,dict(name='p' , attrs={'class':'meta-info' }) ] feeds = [(u'London Review of Books', u'http://www.lrb.co.uk/lrbrss.xml')] - - def print_version(self, url): - main, split, rest = url.rpartition('/') - return main + '/print/' + rest - - def postprocess_html(self, soup, first_fetch): - for t in soup.findAll(['table', 'tr', 'td']): - t.name = 'div' - return soup From 225eaab491fe0980acdccc737a23bf3c263acbb7 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 16 Dec 2009 13:07:37 -0700 Subject: [PATCH 09/23] Linux: Preferentially use desktop specific notification daemons --- resources/images/notify.png | Bin 0 -> 3891 bytes setup/installer/linux/freeze.py | 2 +- src/calibre/gui2/notify.py | 111 ++++++++++++++++++++++++++++++++ src/calibre/gui2/status.py | 6 +- 4 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 resources/images/notify.png create mode 100644 src/calibre/gui2/notify.py diff --git a/resources/images/notify.png b/resources/images/notify.png new file mode 100644 index 0000000000000000000000000000000000000000..1ced8ea8c27fccbc1452eb79bef29828d0538fcf GIT binary patch literal 3891 zcmV-356tk1P) zg*-agACFH+#L2yY0u@N$1RxOR%fe>`#Q*^C19^CUbg)1C0k3ZW0swH;E+i7i;s1lW zP$pLZAdvvzA`<5d0gzGv$SzdK6adH=0I*ZDWC{S3003-xd_p1ssto|_^hrJi0NAOM z+!p}Yq8zCR0F40vnJ7mj0zkU}U{!%qECRs70HCZuA}$2Lt^t5qwlYTofV~9(c8*w( z4?ti5fSE!p%m5%b0suoE6U_r4Oaq`W(!b!TUvP!ENC5!A%azTSOVTqGxRuZvck=My z;vwR~Y_URN7by^C3FIQ2mzyIKNaq7g&I|wm8u`(|{y0C7=jP<$=4R(?@ASo@{%i1W zB0eGU-~POe0t5gMPS5Y!U*+Z218~Oyuywy{sapWrRsd+<`CT*H37}dE(0cicc{uz) z9-g64$UGe!3JVMEC1RnyFyo6p|1;rl;ER6t{6HT5+j{T-ahgDxt-zy${c&M#cCJ#6 z=gR~_F>d$gBmT#QfBlXr(c(0*Tr3re@mPttP$EsodAU-NL?OwQ;u7h9GVvdl{RxwI z4FIf$Pry#L2er#=z<%xl0*ek<(slqqe)BDi8VivC5N9+pdG`PSlfU_oKq~;2Moa!tiTSO!5zH77Xo1hL_iEAz&sE_2IPPo3ZWR5 zK^auQI@koYumc*P5t`u;w81er4d>tzT!HIw7Y1M$p28Tsh6w~g$Osc*Av%Z=Vvg7% z&IlKojszlMNHmgwq#)^t6j36@$a16tsX}UzT}UJHEpik&ja)$bklV;0GK&0)yhkyV zfwEBp)B<%txu_o+ipHRG(R4HqU4WLNYtb6C9zB4zqNmYI=yh}eeTt4_fYC7yW{lZk zT#ScBV2M~7CdU?I?5=ix(HVZgM=}{CnA%mPqZa^68Xe5gFH?u96Et<2CC!@_L(8Ns zqt(!wX=iEoXfNq>x(VHb9z~bXm(pwK2kGbOgYq4YG!XMxcgBqf}$J#u<$v z7REAV@mNCEa#jQDENhreVq3EL>`ZnA`x|yIdrVV9bE;;nW|3x{=5fsd4#u(I@HyF> zO3oq94bFQl11&!-vDRv>X03j$H`;pIzS?5#a_tuF>)P*iaGgM%ES>c_Z94aL3A#4A zQM!e?+jYlFJ5+DSzi0S9#6BJCZ5(XZOGfiTj0IRdtf>~ zJ!SgN=>tB-J_4V5pNGDtz9Qc}z9W9tewls;{GR(e`pf-~_`l(K@)q$<1z-We0p$U` zff|9c18V~x1epY-2Q>wa1-k|>3_cY?3<(WcA99m#z!&lx`C~KOXDpi070L*m6G6C?@kiR8rC#65}Q za{}jVnlqf_npBo_W3J`gqPZ95>CVfZcRX1&S&)1jiOPpx423?lIEROmG(H@JAFg?XogQlb;dIZPf{y+kr|S?BlAsGMAqJ{ z&)IR=Ejg5&l$@hd4QZCNE7vf$D7Q~$D=U)?Nn}(WA6d zu22pZOfRS_cv~1-c(_QtNLti0-)8>m`6CO07JR*suu!$(^sg%jfZm#rNxnmV! zm1I@#YM0epR(~oNm0zrItf;Q|utvD%;#W>z)qM4NZQ9!2O1H}G>qzUQ>u#*~S--DJ zy=p<#(1!30tsC);y-IHSJr>wyfLop*ExTdYyk=%U1oZ ztGB+{Cfe4&-FJKQ4uc&PJKpb5^_C@dOYIJXG+^@gCvI%WcHjN%gI&kHifN$EH?V5MBa9S!3!a?Q1C*P)gd*e{( zq0YnH!_D8Bf4B7r>qvPk(mKC&tSzH$pgp0z@92!9ogH2sN4~fJe(y2kV|B+hk5`_c zohUu=`Q(C=R&z?UQbnZ;IU-!xL-sg{9@Vs#J zBKKn3CAUkhJ+3`ResKNaNUvLO>t*-L?N>ambo5Q@JJIjcfBI^`)pOVQ*DhV3dA;w( z>>IakCfyvkCA#(acJ}QTcM9%I++BK)c(44v+WqPW`VZ=VwEnSWz-{38V8CF{!&wjS z4he^z{*?dIhvCvk%tzHDMk9@nogW_?4H~`jWX_Y}r?RIL&&qyQ|9R_ktLNYS;`>X_ zSp3-V3;B!Bzpih+IV&!14d9xAZ#B zl4+C4IPGNLNJ5MdCu%SU(TGa)5cDD_cn}XF2qHP;Ac8pv5;cOjKtS}Cpb5A@Ac!+c zkYs`yqan%cGd=0)o_@W&diAQxL$--aZuyQy)%UCVz7NX5+6=cbJb(aP2bNh_q~|K0 z+tpe3V5AAv|2pKu(pSDb^k(3UZ~A=b*u{}|f829RV9Wa-zxMWh+xO{A7omc~M}Fbx z7oV1z-+$1*aP#h=A6}R_@pZ2qo9$cs;^t>-J@ec(Sy?>;egx`&fzi-+k5+pbo${zj zOG)(8vvOVVjllyHAL*oLMYo^8a^T$m z0=1^%bV>1N2+ah#Q;?R;wmsR_OAqhZi7Ho_^e=E==r1x|HDpqycAWpW}R z9U6>uh)u*mrf=h}@czP@Q_I-V{s61@e{%1&3kv{i3?wmDMcBB7O(a;2=L)p8#0ruG z8qI`M%B55mty~20d_pW0r^D0C9vq`}qDIHE0CQ$k2!& zR-la2%w=85^;CKBV&BZ4Z=z#Mrq^e<^()%Zs7SH6;jK$U_C|>?Se;EyqSQvRRj@Fjc;z4X;%Z6)ZS8!-d=>8cBo5NIIMj*6%yGbpi12aDc!Q*sHI( z0(kWxmDq`~(y;by`PP6d99&miFBgEqYYGSQ{Y%SA zS(1v|Fv^k;BZ}yeXpF>7&{4wD8F>S+))GpMD;(0Ez!wgwz{A8gbvFv&9Kh8y(AqqZXDq zSewZoAAF+yPft14(st}{Poq-vl81Jd^6NK* z^3Z2@i|3vnSNq>u0000bbVXQn zWMOn=I%9HWVRU5xGB7YXEigANGB#8(H##seIx#pcFg7|cFo8S!n*aa+C3HntbYx+4 zWjbwdWNBu305UKzIV~_TEiyDzF*!OlGdeUiEigAaFfjDh6 Date: Wed, 16 Dec 2009 13:39:05 -0700 Subject: [PATCH 10/23] MOBI Input: Ignore \x02 bytes in data stream for cp1252 encoded files --- src/calibre/ebooks/mobi/reader.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/calibre/ebooks/mobi/reader.py b/src/calibre/ebooks/mobi/reader.py index 7d676a230c..20d31d48b4 100644 --- a/src/calibre/ebooks/mobi/reader.py +++ b/src/calibre/ebooks/mobi/reader.py @@ -701,7 +701,9 @@ class MobiReader(object): if self.book_header.ancient and ' Date: Wed, 16 Dec 2009 13:56:02 -0700 Subject: [PATCH 11/23] Implement #4231 (New recipe for Prague Daily Monitor in English) --- resources/images/news/praguemonitor.png | Bin 0 -> 921 bytes resources/recipes/praguemonitor.recipe | 32 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 resources/images/news/praguemonitor.png create mode 100644 resources/recipes/praguemonitor.recipe diff --git a/resources/images/news/praguemonitor.png b/resources/images/news/praguemonitor.png new file mode 100644 index 0000000000000000000000000000000000000000..ae3624876e21e2fadced7c65b8996608450937e7 GIT binary patch literal 921 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzwj^(N7l!{JxM1({$v_d#0*}aI zAngIhZYQ(tK!Rljj_E*J0gT&!&6&%7+_K5kP&oV@qd<*&bRQ0x< zbHVkw+wYg;OB_%-vLN#4p_*%)=X&3C&!6~1EPxCfQXh`8u9|QoIN=Ky!|JI|J5Fl*6mOA@>HqtC_N=`dg#-Re zF>on$r1ZRrl;z&H=gpJy-!&=gReq{(5w75pid*C`<-!fl5K{+d&liD?&W&x+EW!1tBo5mijNN); zdWNO*5tnc0Bla?ENmDm166{{`*lqSF{?$y2-w9o9xFNj4p=*i4$!{vjh}b4PJ&@!dHAN}6~RVUd{23Ji&b)Oe9t%)U@2F@w6-}vwly<& z-s$)szw;;leYl<1#&p|rIe})!2-8bj_giVM?0RK$%uWCIx7xQ`w_EbE@AA~yd{wY9 zWq*E@RBmdHY{N8P{c!Qwmu7MK);sXM3c73f`2B)it5^N_DO#Jo{%@jC`i@1`$7hNd zwyXSpF6;j8Rgb}bHS1r3^HZN%O!=|@{>7iZ+H=D{KVV$^W`}WnS^K4chN>e=dRtyS z{&(oAB!j`G Date: Wed, 16 Dec 2009 14:35:12 -0700 Subject: [PATCH 12/23] More verbose debug messages during splitting --- src/calibre/ebooks/oeb/transforms/flatcss.py | 2 +- src/calibre/ebooks/oeb/transforms/split.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/calibre/ebooks/oeb/transforms/flatcss.py b/src/calibre/ebooks/oeb/transforms/flatcss.py index 4d21c33c83..61226ca4f4 100644 --- a/src/calibre/ebooks/oeb/transforms/flatcss.py +++ b/src/calibre/ebooks/oeb/transforms/flatcss.py @@ -194,7 +194,7 @@ class CSSFlattener(object): def flatten_node(self, node, stylizer, names, styles, psize, left=0): if not isinstance(node.tag, basestring) \ or namespace(node.tag) != XHTML_NS: - return + return tag = barename(node.tag) style = stylizer.style(node) cssdict = style.cssdict() diff --git a/src/calibre/ebooks/oeb/transforms/split.py b/src/calibre/ebooks/oeb/transforms/split.py index 7c1559fda6..52133c91d9 100644 --- a/src/calibre/ebooks/oeb/transforms/split.py +++ b/src/calibre/ebooks/oeb/transforms/split.py @@ -91,7 +91,6 @@ class Split(object): False)) except: pass - page_breaks = set([]) for selector, before in self.page_break_selectors: body = item.data.xpath('//h:body', namespaces=NAMESPACES) @@ -382,6 +381,7 @@ class FlowSplitter(object): p[i:i+1] = new_pres split_point, before = self.find_split_point(root) + self.log.debug('\t\t\tSplit point:', split_point.tag, tree.getpath(split_point)) if split_point is None: raise SplitError(self.item.href, root) @@ -396,6 +396,9 @@ class FlowSplitter(object): '\t\t\tCommitted sub-tree #%d (%d KB)'%( len(self.split_trees), size/1024.)) else: + self.log.debug( + '\t\t\tSplit tree still too large: %d KB' % \ + (size/1024.)) self.split_to_size(t) def find_split_point(self, root): From 3737a934932b2cd848400f8b4188640347a708d9 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 16 Dec 2009 14:54:22 -0700 Subject: [PATCH 13/23] FB2 Input: Fix #4215 (GARBLED TITLES IN EPUB CONVERSION) --- resources/templates/fb2.xsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/templates/fb2.xsl b/resources/templates/fb2.xsl index 3744388aad..0c5a877eab 100644 --- a/resources/templates/fb2.xsl +++ b/resources/templates/fb2.xsl @@ -187,7 +187,7 @@ - + From 40cb9772038e2bf889beb975eee14abeda542a55 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 16 Dec 2009 15:32:21 -0700 Subject: [PATCH 14/23] Fix #4230 (Can't view/convert certain Mobipocket files) --- src/calibre/ebooks/mobi/input.py | 12 +++++++++--- src/calibre/ebooks/mobi/reader.py | 10 ++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/calibre/ebooks/mobi/input.py b/src/calibre/ebooks/mobi/input.py index bc9409b852..487e70c04f 100644 --- a/src/calibre/ebooks/mobi/input.py +++ b/src/calibre/ebooks/mobi/input.py @@ -16,10 +16,16 @@ class MOBIInput(InputFormatPlugin): accelerators): from calibre.ebooks.mobi.reader import MobiReader from lxml import html - mr = MobiReader(stream, log, options.input_encoding, - options.debug_pipeline) parse_cache = {} - mr.extract_content('.', parse_cache) + try: + mr = MobiReader(stream, log, options.input_encoding, + options.debug_pipeline) + mr.extract_content('.', parse_cache) + except: + mr = MobiReader(stream, log, options.input_encoding, + options.debug_pipeline, try_extra_data_fix=True) + mr.extract_content('.', parse_cache) + raw = parse_cache.pop('calibre_raw_mobi_markup', False) if raw: if isinstance(raw, unicode): diff --git a/src/calibre/ebooks/mobi/reader.py b/src/calibre/ebooks/mobi/reader.py index 20d31d48b4..973418204f 100644 --- a/src/calibre/ebooks/mobi/reader.py +++ b/src/calibre/ebooks/mobi/reader.py @@ -108,7 +108,7 @@ class EXTHHeader(object): class BookHeader(object): - def __init__(self, raw, ident, user_encoding, log): + def __init__(self, raw, ident, user_encoding, log, try_extra_data_fix=False): self.log = log self.compression_type = raw[:2] self.records, self.records_size = struct.unpack('>HH', raw[8:12]) @@ -141,7 +141,8 @@ class BookHeader(object): self.codec = 'cp1252' if user_encoding is None else user_encoding log.warn('Unknown codepage %d. Assuming %s' % (self.codepage, self.codec)) - if ident == 'TEXTREAD' or self.length < 0xE4 or 0xE8 < self.length: + if ident == 'TEXTREAD' or self.length < 0xE4 or 0xE8 < self.length \ + or (try_extra_data_fix and self.length == 0xE4): self.extra_flags = 0 else: self.extra_flags, = struct.unpack('>H', raw[0xF2:0xF4]) @@ -229,7 +230,8 @@ class MobiReader(object): PAGE_BREAK_PAT = re.compile(r'(<[/]{0,1}mbp:pagebreak\s*[/]{0,1}>)+', re.IGNORECASE) IMAGE_ATTRS = ('lowrecindex', 'recindex', 'hirecindex') - def __init__(self, filename_or_stream, log, user_encoding=None, debug=None): + def __init__(self, filename_or_stream, log, user_encoding=None, debug=None, + try_extra_data_fix=False): self.log = log self.debug = debug self.embedded_mi = None @@ -284,7 +286,7 @@ class MobiReader(object): self.book_header = BookHeader(self.sections[0][0], self.ident, - user_encoding, self.log) + user_encoding, self.log, try_extra_data_fix=try_extra_data_fix) self.name = self.name.decode(self.book_header.codec, 'replace') def extract_content(self, output_dir, parse_cache): From 3e3959eef4cfa49ac369df5f548d37897fce1f66 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 16 Dec 2009 15:33:21 -0700 Subject: [PATCH 15/23] E-book viewer: Fix regression that could cause the next page action to sometime have no effect at the end of a section --- src/calibre/gui2/viewer/documentview.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/calibre/gui2/viewer/documentview.py b/src/calibre/gui2/viewer/documentview.py index 60807cc800..3b9ec5a4f0 100644 --- a/src/calibre/gui2/viewer/documentview.py +++ b/src/calibre/gui2/viewer/documentview.py @@ -587,20 +587,32 @@ class DocumentView(QWebView): if self.manager is not None: self.manager.next_document() else: + oopos = self.document.ypos + #print '\nOriginal position:', oopos self.document.set_bottom_padding(0) opos = self.document.ypos + #print 'After set padding=0:', self.document.ypos + if opos < oopos: + if self.manager is not None: + self.manager.next_document() + return lower_limit = opos + delta_y # Max value of top y co-ord after scrolling max_y = self.document.height - window_height # The maximum possible top y co-ord if max_y < lower_limit: + #print 'Setting padding to:', lower_limit - max_y self.document.set_bottom_padding(lower_limit - max_y) max_y = self.document.height - window_height lower_limit = min(max_y, lower_limit) + #print 'Scroll to:', lower_limit if lower_limit > opos: self.document.scroll_to(self.document.xpos, lower_limit) actually_scrolled = self.document.ypos - opos + #print 'After scroll pos:', self.document.ypos self.find_next_blank_line(window_height - actually_scrolled) + #print 'After blank line pos:', self.document.ypos if self.manager is not None: self.manager.scrolled(self.scroll_fraction) + #print 'After all:', self.document.ypos def scroll_by(self, x=0, y=0, notify=True): old_pos = self.document.ypos From 611231ea59272ffb671a324fe20df574dbc5eebd Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 17 Dec 2009 10:31:29 -0700 Subject: [PATCH 16/23] Fix #4240 (Can't get goole reader recipe to work) --- resources/recipes/greader.recipe | 2 +- src/calibre/web/fetch/simple.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/resources/recipes/greader.recipe b/resources/recipes/greader.recipe index 31b4ec8b7e..cbf4c0226b 100644 --- a/resources/recipes/greader.recipe +++ b/resources/recipes/greader.recipe @@ -32,6 +32,6 @@ class GoogleReader(BasicNewsRecipe): soup = self.index_to_soup('http://www.google.com/reader/api/0/tag/list') for id in soup.findAll(True, attrs={'name':['id']}): url = id.contents[0] - feeds.append((re.search('/([^/]*)$', url).group(1), + feeds.append((re.search('/([^/]*)$', url).group(1), self.base_url + urllib.quote(url.encode('utf-8')) + self.get_options)) return feeds diff --git a/src/calibre/web/fetch/simple.py b/src/calibre/web/fetch/simple.py index 4957e81b14..4936feb77f 100644 --- a/src/calibre/web/fetch/simple.py +++ b/src/calibre/web/fetch/simple.py @@ -194,7 +194,8 @@ class RecursiveFetcher(object): purl[i] = quote(purl[i]) url = urlparse.urlunparse(purl) try: - with closing(self.browser.open_novisit(url, timeout=self.timeout)) as f: + open_func = getattr(self.browser, 'open_novisit', self.browser.open) + with closing(open_func(url, timeout=self.timeout)) as f: data = response(f.read()+f.read()) data.newurl = f.geturl() except urllib2.URLError, err: From 2c0de47f90dfdbb9410894bb7255ac9290539d9d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 17 Dec 2009 11:27:56 -0700 Subject: [PATCH 17/23] New recipe for boston.com by Darko Miletic --- resources/recipes/boston.com.recipe | 49 +++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 resources/recipes/boston.com.recipe diff --git a/resources/recipes/boston.com.recipe b/resources/recipes/boston.com.recipe new file mode 100644 index 0000000000..125cc4643f --- /dev/null +++ b/resources/recipes/boston.com.recipe @@ -0,0 +1,49 @@ +__license__ = 'GPL v3' +__copyright__ = '2009, Darko Miletic ' +''' +www.boston.com +''' + +from calibre.web.feeds.recipes import BasicNewsRecipe + +class BusinessStandard(BasicNewsRecipe): + title = 'Boston' + __author__ = 'Darko Miletic' + description = 'News from Boston' + oldest_article = 7 + max_articles_per_feed = 100 + no_stylesheets = True + delay = 1 + use_embedded_content = False + encoding = 'cp1252' + publisher = 'Boston' + category = 'news, boston, usa, world' + language = 'en' + + conversion_options = { + 'comments' : description + ,'tags' : category + ,'language' : language + ,'publisher' : publisher + } + + keep_only_tags = [dict(name='div', attrs={'class':'story'})] + remove_tags = [dict(name=['object','link','script','iframe'])] + + feeds = [ + (u'Top Stories' , u'http://feeds.boston.com/boston/topstories' ) + ,(u'Patriots news', u'http://feeds.boston.com/boston/sports/football/patriots') + ,(u'National news', u'http://feeds.boston.com/boston/news/nation' ) + ,(u'World news' , u'http://feeds.boston.com/boston/news/world' ) + ] + + def print_version(self, url): + return url + '?mode=PF' + + def get_article_url(self, article): + rawarticle = article.get('origlink', None) + artls, sep, rsep = rawarticle.rpartition('/?') + if artls == '': + artls = rawarticle.rpartition('?')[0] + return artls + From 283e18c0bc8eb4d833d76492d184e1e4c657316a Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 17 Dec 2009 12:13:54 -0700 Subject: [PATCH 18/23] New recipe for Alberto Montt en dosis diarias by Darko Miletic. Implements #4242 --- resources/recipes/dosisdiarias.recipe | 31 ++++++ src/calibre/devices/__init__.py | 97 ++++++++++++++++++- src/calibre/devices/eb600/driver.py | 6 +- src/calibre/devices/usbms/device.py | 4 +- src/calibre/devices/usbms/driver.py | 2 +- src/calibre/gui2/dialogs/config/__init__.py | 6 ++ src/calibre/gui2/dialogs/config/config.ui | 31 +++--- .../gui2/dialogs/config/device_debug.py | 52 ++++++++++ src/calibre/manual/faq.rst | 19 ++-- 9 files changed, 221 insertions(+), 27 deletions(-) create mode 100644 resources/recipes/dosisdiarias.recipe create mode 100644 src/calibre/gui2/dialogs/config/device_debug.py diff --git a/resources/recipes/dosisdiarias.recipe b/resources/recipes/dosisdiarias.recipe new file mode 100644 index 0000000000..2976428868 --- /dev/null +++ b/resources/recipes/dosisdiarias.recipe @@ -0,0 +1,31 @@ +__license__ = 'GPL v3' +__copyright__ = '2009, Darko Miletic ' +''' +http://www.dosisdiarias.com +''' + +from calibre.web.feeds.recipes import BasicNewsRecipe + +class DosisDiarias(BasicNewsRecipe): + title = 'Alberto Montt en dosis diarias' + __author__ = 'Darko Miletic' + description = 'Mire sin compromiso y si le gusta vuelva' + oldest_article = 5 + max_articles_per_feed = 100 + no_stylesheets = True + use_embedded_content = True + encoding = 'utf-8' + publisher = 'Alberto Montt' + category = 'comic, blog, spanish' + language = 'es' + + conversion_options = { + 'comments' : description + ,'tags' : category + ,'language' : language + ,'publisher' : publisher + } + + remove_tags = [dict(name='div',attrs={'class':'feedflare'})] + + feeds = [(u'Dosis diaria', u'http://feeds.feedburner.com/montt' )] diff --git a/src/calibre/devices/__init__.py b/src/calibre/devices/__init__.py index 874de7c070..e0f0208d9b 100644 --- a/src/calibre/devices/__init__.py +++ b/src/calibre/devices/__init__.py @@ -5,7 +5,9 @@ __copyright__ = '2008, Kovid Goyal ' Device drivers. ''' -import time +import sys, os, time, pprint +from functools import partial +from StringIO import StringIO DAY_MAP = dict(Sun=0, Mon=1, Tue=2, Wed=3, Thu=4, Fri=5, Sat=6) MONTH_MAP = dict(Jan=1, Feb=2, Mar=3, Apr=4, May=5, Jun=6, Jul=7, Aug=8, Sep=9, Oct=10, Nov=11, Dec=12) @@ -24,3 +26,96 @@ def strftime(epoch, zone=time.gmtime): src[0] = INVERSE_DAY_MAP[int(src[0][:-1])]+',' src[2] = INVERSE_MONTH_MAP[int(src[2])] return ' '.join(src) + +def debug(): + from calibre.customize.ui import device_plugins + from calibre.devices.scanner import DeviceScanner + from calibre.constants import iswindows, isosx, __version__ + from calibre import prints + oldo, olde = sys.stdout, sys.stderr + + buf = StringIO() + sys.stdout = sys.stderr = buf + try: + out = partial(prints, file=buf) + out('Version:', __version__) + s = DeviceScanner() + s.scan() + devices = (s.devices) + if not iswindows: + devices = [list(x) for x in devices] + for d in devices: + for i in range(3): + d[i] = hex(i) + out('USB devices on system:') + out(pprint.pformat(devices)) + if iswindows: + if iswindows: + import pythoncom + pythoncom.CoInitialize() + try: + wmi = __import__('wmi', globals(), locals(), [], -1) + drives = [] + out('Drives detected:') + out('\t', '(ID, Partitions, Drive letter)') + for drive in wmi.WMI(find_classes=False).Win32_DiskDrive(): + if drive.Partitions == 0: + continue + try: + partition = drive.associators("Win32_DiskDriveToDiskPartition")[0] + logical_disk = partition.associators('Win32_LogicalDiskToPartition')[0] + prefix = logical_disk.DeviceID+os.sep + drives.append((str(drive.PNPDeviceID), drive.Index, prefix)) + except IndexError: + drives.append((str(drive.PNPDeviceID), 'No mount points found')) + for drive in drives: + out('\t', drive) + finally: + pythoncom.CoUninitialize() + + ioreg = None + if isosx: + from calibre.devices.usbms.device import Device + ioreg = Device.run_ioreg() + connected_devices = [] + for dev in device_plugins(): + out('Looking for', dev.__class__.__name__) + connected = s.is_device_connected(dev, debug=True) + if connected: + connected_devices.append(dev) + + errors = {} + success = False + for dev in connected_devices: + out('Device possibly connected:', dev.__class__.name) + out('Trying to open device...', end=' ') + try: + dev.open() + out('OK') + except: + import traceback + errors[dev] = traceback.format_exc() + out('failed') + continue + success = True + if hasattr(dev, '_main_prefix'): + out('Main memory:', repr(dev._main_prefix)) + out('Total space:', dev.total_space()) + break + if not success and errors: + out('Opening of the following devices failed') + for dev,msg in errors.items(): + out(dev) + out(msg) + out(' ') + + if ioreg is not None: + out(' ') + out('IOREG Output') + out(ioreg) + + return buf.getvalue().decode('utf-8') + finally: + sys.stdout = oldo + sys.stderr = olde + diff --git a/src/calibre/devices/eb600/driver.py b/src/calibre/devices/eb600/driver.py index 28bcd7418e..76789fa675 100644 --- a/src/calibre/devices/eb600/driver.py +++ b/src/calibre/devices/eb600/driver.py @@ -117,7 +117,7 @@ class ITALICA(EB600): name = 'Italica Device Interface' gui_name = 'Italica' - FORMATS = ['epub', 'pdf', 'txt'] + FORMATS = ['epub', 'rtf', 'fb2', 'html', 'prc', 'mobi', 'pdf', 'txt'] VENDOR_NAME = 'ITALICA' WINDOWS_MAIN_MEM = 'EREADER' @@ -125,3 +125,7 @@ class ITALICA(EB600): OSX_MAIN_MEM = 'Italica eReader Media' OSX_CARD_A_MEM = OSX_MAIN_MEM + + MAIN_MEMORY_VOLUME_LABEL = 'Italica Main Memory' + STORAGE_CARD_VOLUME_LABEL = 'Italica Storage Card' + diff --git a/src/calibre/devices/usbms/device.py b/src/calibre/devices/usbms/device.py index 64ce925530..8ae401591e 100644 --- a/src/calibre/devices/usbms/device.py +++ b/src/calibre/devices/usbms/device.py @@ -711,7 +711,9 @@ class Device(DeviceConfig, DevicePlugin): candidates = self.get_main_ebook_dir() if isinstance(candidates, basestring): candidates = [candidates] - candidates = [os.path.join(self._main_prefix, *(x.split('/'))) for x + candidates = [ + ((os.path.join(self._main_prefix, *(x.split('/')))) if x else + self._main_prefix) for x in candidates] existing = [x for x in candidates if os.path.exists(x)] if not existing: diff --git a/src/calibre/devices/usbms/driver.py b/src/calibre/devices/usbms/driver.py index 51b1cc7144..8d2416511c 100644 --- a/src/calibre/devices/usbms/driver.py +++ b/src/calibre/devices/usbms/driver.py @@ -63,7 +63,7 @@ class USBMS(CLI, Device): if isinstance(ebook_dirs, basestring): ebook_dirs = [ebook_dirs] for ebook_dir in ebook_dirs: - ebook_dir = os.path.join(prefix, *(ebook_dir.split('/'))) + ebook_dir = os.path.join(prefix, *(ebook_dir.split('/'))) if ebook_dir else prefix if not os.path.exists(ebook_dir): continue # Get all books in the ebook_dir directory if self.SUPPORTS_SUB_DIRS: diff --git a/src/calibre/gui2/dialogs/config/__init__.py b/src/calibre/gui2/dialogs/config/__init__.py index 2e647781c1..ea9ab1af50 100644 --- a/src/calibre/gui2/dialogs/config/__init__.py +++ b/src/calibre/gui2/dialogs/config/__init__.py @@ -457,6 +457,12 @@ class ConfigDialog(ResizableDialog, Ui_Dialog): self.open_config_dir) self.opt_get_social_metadata.setChecked(config['get_social_metadata']) self.opt_enforce_cpu_limit.setChecked(config['enforce_cpu_limit']) + self.device_detection_button.clicked.connect(self.debug_device_detection) + + def debug_device_detection(self): + from calibre.gui2.dialogs.config.device_debug import DebugDevice + d = DebugDevice(self) + d.exec_() def open_config_dir(self): from calibre.utils.config import config_dir diff --git a/src/calibre/gui2/dialogs/config/config.ui b/src/calibre/gui2/dialogs/config/config.ui index fc7c6b6635..77c1d9eccd 100644 --- a/src/calibre/gui2/dialogs/config/config.ui +++ b/src/calibre/gui2/dialogs/config/config.ui @@ -15,7 +15,7 @@ Preferences - + :/images/config.svg:/images/config.svg @@ -148,7 +148,7 @@ ... - + :/images/mimetypes/dir.svg:/images/mimetypes/dir.svg @@ -285,7 +285,7 @@ ... - + :/images/arrow-up.svg:/images/arrow-up.svg @@ -309,7 +309,7 @@ ... - + :/images/arrow-down.svg:/images/arrow-down.svg @@ -473,7 +473,7 @@ ... - + :/images/arrow-up.svg:/images/arrow-up.svg @@ -497,7 +497,7 @@ ... - + :/images/arrow-down.svg:/images/arrow-down.svg @@ -557,7 +557,7 @@ &Add email - + :/images/plus.svg:/images/plus.svg @@ -584,7 +584,7 @@ &Remove email - + :/images/minus.svg:/images/minus.svg @@ -649,21 +649,21 @@ - + &Check database integrity - + &Install command line tools - + Open calibre &configuration directory @@ -677,6 +677,13 @@ + + + + Debug &device detection + + + @@ -966,7 +973,7 @@ ... - + :/images/document_open.svg:/images/document_open.svg diff --git a/src/calibre/gui2/dialogs/config/device_debug.py b/src/calibre/gui2/dialogs/config/device_debug.py new file mode 100644 index 0000000000..ae4a8e4f45 --- /dev/null +++ b/src/calibre/gui2/dialogs/config/device_debug.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai +from __future__ import with_statement + +__license__ = 'GPL v3' +__copyright__ = '2009, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + + +from PyQt4.Qt import QDialog, QVBoxLayout, QPlainTextEdit, QTimer, \ + QDialogButtonBox, QPushButton, QApplication, QIcon + +class DebugDevice(QDialog): + + def __init__(self, parent=None): + QDialog.__init__(self, parent) + self._layout = QVBoxLayout(self) + self.setLayout(self._layout) + self.log = QPlainTextEdit(self) + self._layout.addWidget(self.log) + self.log.setPlainText(_('Getting debug information')+'...') + self.copy = QPushButton(_('Copy to &clipboard')) + self.copy.setDefault(True) + self.setWindowTitle(_('Debug device detection')) + self.setWindowIcon(QIcon(I('debug.svg'))) + self.copy.clicked.connect(self.copy_to_clipboard) + self.ok = QPushButton('&OK') + self.ok.setAutoDefault(False) + self.ok.clicked.connect(self.accept) + self.bbox = QDialogButtonBox(self) + self.bbox.addButton(self.copy, QDialogButtonBox.ActionRole) + self.bbox.addButton(self.ok, QDialogButtonBox.AcceptRole) + self._layout.addWidget(self.bbox) + self.resize(750, 500) + self.bbox.setEnabled(False) + QTimer.singleShot(1000, self.debug) + + def debug(self): + try: + from calibre.devices import debug + raw = debug() + self.log.setPlainText(raw) + finally: + self.bbox.setEnabled(True) + + def copy_to_clipboard(self): + QApplication.clipboard().setText(self.log.toPlainText()) + +if __name__ == '__main__': + app = QApplication([]) + d = DebugDevice() + d.exec_() diff --git a/src/calibre/manual/faq.rst b/src/calibre/manual/faq.rst index c15cd20fd2..f40b867a64 100644 --- a/src/calibre/manual/faq.rst +++ b/src/calibre/manual/faq.rst @@ -81,7 +81,7 @@ Device Integration What devices does |app| support? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -At the moment |app| has full support for the SONY PRS 300/500/505/600/700, Barnes & Noble Nook, Cybook Gen 3/Opus, Amazon Kindle 1/2/DX, Netronix EB600, Ectaco Jetbook, BeBook/BeBook Mini, Irex Illiad/DR1000, Foxit eSlick, PocketBook 360, Android phones and the iPhone. In addition, using the :guilabel:`Save to disk` function you can use it with any ebook reader that exports itself as a USB disk. +At the moment |app| has full support for the SONY PRS 300/500/505/600/700, Barnes & Noble Nook, Cybook Gen 3/Opus, Amazon Kindle 1/2/DX, Netronix EB600, Ectaco Jetbook, BeBook/BeBook Mini, Irex Illiad/DR1000, Foxit eSlick, PocketBook 360, Italica, various Android phones and the iPhone. In addition, using the :guilabel:`Save to disk` function you can use it with any ebook reader that exports itself as a USB disk. How can I help get my device supported in |app|? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -91,17 +91,14 @@ We just need some information from you: * What e-book formats does your device support? * Is there a special directory on the device in which all e-book files should be placed? - * We also need the output from running the following command in a terminal, both with the device - connected and without:: + * We also need information about your device that |app| will collect automatically. First, if your + device supports SD cards, insert them. Then connect your device. In calibre go to Preferences->Advanced + and click the "Debug device detection" button. This will create some debug output. Copy it to a file + and repeat the process, this time with your device disconnected. + * Send both the above outputs to us with the other information and we will write a device driver for your + device. - calibre-debug -d - - * If your device supports SD cards, run the above command with the cards inserted. - -To run the above command, on Windows you should use the full path to calibre-debug.exe -On OSX, you should go to Preferences->Advanced and click "Install command line tools". - -Once you send us the output for a particular operating system, support for the device +Once you send us the output for a particular operating system, support for the device in that operating system will appear in the next release of |app|. From 0c3e0bc821660a730ae46f11fa169c4202005e61 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 17 Dec 2009 12:19:10 -0700 Subject: [PATCH 19/23] Add button to debug device detection to Preferences->Advanced --- src/calibre/devices/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/devices/__init__.py b/src/calibre/devices/__init__.py index e0f0208d9b..c971c9d79d 100644 --- a/src/calibre/devices/__init__.py +++ b/src/calibre/devices/__init__.py @@ -46,7 +46,7 @@ def debug(): devices = [list(x) for x in devices] for d in devices: for i in range(3): - d[i] = hex(i) + d[i] = hex(d[i]) out('USB devices on system:') out(pprint.pformat(devices)) if iswindows: From b9abaebc52c6b7f0dfe45cc3113c77a696408777 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 17 Dec 2009 16:59:10 -0700 Subject: [PATCH 20/23] Conversion pipeline: Fix --linearize-tables option not removing all table related style information --- src/calibre/ebooks/conversion/plumber.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/calibre/ebooks/conversion/plumber.py b/src/calibre/ebooks/conversion/plumber.py index 30cc42480c..07299aff4e 100644 --- a/src/calibre/ebooks/conversion/plumber.py +++ b/src/calibre/ebooks/conversion/plumber.py @@ -804,6 +804,11 @@ OptionRecommendation(name='language', if line_height < 1e-4: line_height = None + if self.opts.linearize_tables and \ + self.output_plugin.file_type not in ('mobi', 'lrf'): + from calibre.ebooks.oeb.transforms.linearize_tables import LinearizeTables + LinearizeTables()(self.oeb, self.opts) + flattener = CSSFlattener(fbase=fbase, fkey=fkey, lineh=line_height, untable=self.output_plugin.file_type in ('mobi','lit'), @@ -812,10 +817,6 @@ OptionRecommendation(name='language', self.opts.insert_blank_line = oibl self.opts.remove_paragraph_spacing = orps - if self.opts.linearize_tables and \ - self.output_plugin.file_type not in ('mobi', 'lrf'): - from calibre.ebooks.oeb.transforms.linearize_tables import LinearizeTables - LinearizeTables()(self.oeb, self.opts) pr(0.9) self.flush() From fd3838b84c1265408ae29a18396674497442c78f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 17 Dec 2009 16:59:27 -0700 Subject: [PATCH 21/23] ... --- resources/recipes/boston.com.recipe | 2 +- src/calibre/devices/prs500/driver.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/recipes/boston.com.recipe b/resources/recipes/boston.com.recipe index 125cc4643f..b398d7cc1b 100644 --- a/resources/recipes/boston.com.recipe +++ b/resources/recipes/boston.com.recipe @@ -41,7 +41,7 @@ class BusinessStandard(BasicNewsRecipe): return url + '?mode=PF' def get_article_url(self, article): - rawarticle = article.get('origlink', None) + rawarticle = article.get('pheedo_origlink', None) artls, sep, rsep = rawarticle.rpartition('/?') if artls == '': artls = rawarticle.rpartition('?')[0] diff --git a/src/calibre/devices/prs500/driver.py b/src/calibre/devices/prs500/driver.py index 7c506c6bf0..8d2c4cc9d4 100644 --- a/src/calibre/devices/prs500/driver.py +++ b/src/calibre/devices/prs500/driver.py @@ -166,7 +166,7 @@ class PRS500(DeviceConfig, DevicePlugin): try: if not dev.handle: dev.open() - if not dev.in_session: + if not getattr(dev, 'in_session', False): dev.send_validated_command(BeginEndSession(end=False)) dev.in_session = True res = func(*args, **kwargs) From d6c36c0bbbe72e85545edee5ad43d703c363a287 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 17 Dec 2009 18:02:09 -0700 Subject: [PATCH 22/23] Implement #4238 (Recent xPath list) --- src/calibre/gui2/convert/xexp_edit.ui | 37 ++++++++++++++++- src/calibre/gui2/convert/xpath_wizard.py | 15 ++++++- src/calibre/gui2/widgets.py | 53 ++++++++++++++++++++---- 3 files changed, 94 insertions(+), 11 deletions(-) diff --git a/src/calibre/gui2/convert/xexp_edit.ui b/src/calibre/gui2/convert/xexp_edit.ui index 0b11e9c071..1b0196a8a1 100644 --- a/src/calibre/gui2/convert/xexp_edit.ui +++ b/src/calibre/gui2/convert/xexp_edit.ui @@ -6,7 +6,7 @@ 0 0 - 400 + 422 64 @@ -30,7 +30,20 @@ - + + + + 100 + 0 + + + + + 350 + 0 + + + @@ -54,8 +67,28 @@ + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + HistoryLineEdit + QComboBox +
calibre/gui2/widgets.h
+
+
diff --git a/src/calibre/gui2/convert/xpath_wizard.py b/src/calibre/gui2/convert/xpath_wizard.py index ef42a876d3..21c8aded06 100644 --- a/src/calibre/gui2/convert/xpath_wizard.py +++ b/src/calibre/gui2/convert/xpath_wizard.py @@ -70,13 +70,18 @@ class XPathEdit(QWidget, Ui_Edit): if wiz.exec_() == wiz.Accepted: self.edit.setText(wiz.xpath) + def setObjectName(self, *args): + QWidget.setObjectName(self, *args) + if hasattr(self, 'edit'): + self.edit.initialize('xpath_edit_'+unicode(self.objectName())) + def set_msg(self, msg): self.msg.setText(msg) @property def text(self): - return unicode(self.edit.text()) + return unicode(self.edit.currentText()) @property def xpath(self): @@ -95,4 +100,10 @@ class XPathEdit(QWidget, Ui_Edit): return True - +if __name__ == '__main__': + from PyQt4.Qt import QApplication + app = QApplication([]) + w = XPathEdit() + w.setObjectName('test') + w.show() + app.exec_() diff --git a/src/calibre/gui2/widgets.py b/src/calibre/gui2/widgets.py index 7784915b96..9bf904da71 100644 --- a/src/calibre/gui2/widgets.py +++ b/src/calibre/gui2/widgets.py @@ -11,7 +11,7 @@ from PyQt4.Qt import QListView, QIcon, QFont, QLabel, QListWidget, \ QAbstractListModel, QVariant, Qt, SIGNAL, \ QRegExp, QSettings, QSize, QModelIndex, \ QAbstractButton, QPainter, QLineEdit, QComboBox, \ - QMenu, QStringListModel, QCompleter + QMenu, QStringListModel, QCompleter, QStringList from calibre.gui2 import human_readable, NONE, TableView, \ qstring_to_unicode, error_dialog @@ -21,9 +21,11 @@ from calibre import fit_image from calibre.utils.fonts import fontconfig from calibre.ebooks import BOOK_EXTENSIONS from calibre.ebooks.metadata.meta import metadata_from_filename -from calibre.utils.config import prefs +from calibre.utils.config import prefs, XMLConfig from calibre.gui2.progress_indicator import ProgressIndicator as _ProgressIndicator +history = XMLConfig('history') + class ProgressIndicator(QWidget): def __init__(self, *args): @@ -506,16 +508,16 @@ class LineEditECM(object): menu.exec_(event.globalPos()) def upper_case(self): - self.setText(qstring_to_unicode(self.text()).upper()) + self.setText(unicode(self.text()).upper()) def lower_case(self): - self.setText(qstring_to_unicode(self.text()).lower()) + self.setText(unicode(self.text()).lower()) def swap_case(self): - self.setText(qstring_to_unicode(self.text()).swapcase()) + self.setText(unicode(self.text()).swapcase()) def title_case(self): - self.setText(qstring_to_unicode(self.text()).title()) + self.setText(unicode(self.text()).title()) class EnLineEdit(LineEditECM, QLineEdit): @@ -620,7 +622,7 @@ class EnComboBox(QComboBox): self.setLineEdit(EnLineEdit(self)) def text(self): - return qstring_to_unicode(self.currentText()) + return unicode(self.currentText()) def setText(self, text): idx = self.findText(text, Qt.MatchFixedString) @@ -629,6 +631,43 @@ class EnComboBox(QComboBox): idx = 0 self.setCurrentIndex(idx) +class HistoryLineEdit(QComboBox): + + def __init__(self, *args): + QComboBox.__init__(self, *args) + self.setEditable(True) + self.setInsertPolicy(self.NoInsert) + self.setMaxCount(10) + + @property + def store_name(self): + return 'lineedit_history_'+self._name + + def initialize(self, name): + self._name = name + self.addItems(QStringList(history.get(self.store_name, []))) + self.setEditText('') + self.lineEdit().editingFinished.connect(self.save_history) + + def save_history(self): + items = [] + ct = unicode(self.currentText()) + if ct: + items.append(ct) + for i in range(self.count()): + item = unicode(self.itemText(i)) + if item not in items: + items.append(item) + + history.set(self.store_name, items) + + def setText(self, t): + self.setEditText(t) + self.lineEdit().setCursorPosition(0) + + def text(self): + return self.currentText() + class PythonHighlighter(QSyntaxHighlighter): Rules = [] From 1addaff034377abb62806429f1410f76665ab2c8 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 17 Dec 2009 18:07:14 -0700 Subject: [PATCH 23/23] ... --- src/calibre/gui2/convert/xpath_wizard.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/calibre/gui2/convert/xpath_wizard.py b/src/calibre/gui2/convert/xpath_wizard.py index 21c8aded06..e34453e5db 100644 --- a/src/calibre/gui2/convert/xpath_wizard.py +++ b/src/calibre/gui2/convert/xpath_wizard.py @@ -81,7 +81,7 @@ class XPathEdit(QWidget, Ui_Edit): @property def text(self): - return unicode(self.edit.currentText()) + return unicode(self.edit.text()) @property def xpath(self): @@ -107,3 +107,4 @@ if __name__ == '__main__': w.setObjectName('test') w.show() app.exec_() + print w.xpath