From ca59743da075f53834583bab24f74eb1e368d35e Mon Sep 17 00:00:00 2001 From: GRiker Date: Fri, 25 Jun 2010 10:04:26 -0600 Subject: [PATCH 1/7] GwR revisions supporting iTunes async mode --- src/calibre/devices/apple/driver.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/calibre/devices/apple/driver.py b/src/calibre/devices/apple/driver.py index 3b46976ca7..b57822d1eb 100644 --- a/src/calibre/devices/apple/driver.py +++ b/src/calibre/devices/apple/driver.py @@ -2431,24 +2431,24 @@ class ITUNES(DriverBase): if isosx: if lb_added: lb_added.album.set(metadata.title) + lb_added.artist.set(metadata.authors[0]) lb_added.composer.set(metadata.uuid) lb_added.description.set("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S'))) lb_added.enabled.set(True) lb_added.sort_artist.set(metadata.author_sort.title()) lb_added.sort_name.set(this_book.title_sorter) if this_book.format == 'pdf': - lb_added.artist.set(metadata.authors[0]) lb_added.name.set(metadata.title) if db_added: db_added.album.set(metadata.title) + db_added.artist.set(metadata.authors[0]) db_added.composer.set(metadata.uuid) db_added.description.set("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S'))) db_added.enabled.set(True) db_added.sort_artist.set(metadata.author_sort.title()) db_added.sort_name.set(this_book.title_sorter) if this_book.format == 'pdf': - db_added.artist.set(metadata.authors[0]) db_added.name.set(metadata.title) if metadata.comments: @@ -2499,24 +2499,24 @@ class ITUNES(DriverBase): elif iswindows: if lb_added: lb_added.Album = metadata.title + lb_added.Artist = metadata.authors[0] lb_added.Composer = metadata.uuid lb_added.Description = ("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S'))) lb_added.Enabled = True lb_added.SortArtist = (metadata.author_sort.title()) lb_added.SortName = (this_book.title_sorter) if this_book.format == 'pdf': - lb_added.Artist = metadata.authors[0] lb_added.Name = metadata.title if db_added: db_added.Album = metadata.title + db_added.Artist = metadata.authors[0] db_added.Composer = metadata.uuid db_added.Description = ("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S'))) db_added.Enabled = True db_added.SortArtist = (metadata.author_sort.title()) db_added.SortName = (this_book.title_sorter) if this_book.format == 'pdf': - db_added.Artist = metadata.authors[0] db_added.Name = metadata.title if metadata.comments: From 0809d2f6ee1fcaaf734ba68f48b62b16f5f1ea2a Mon Sep 17 00:00:00 2001 From: GRiker Date: Sun, 27 Jun 2010 13:42:12 -0600 Subject: [PATCH 2/7] GwR wip --- resources/recipes/nytimes.recipe | 1 + resources/recipes/nytimes_sub.recipe | 1 + src/calibre/customize/profiles.py | 85 +++++++++++++++++++++------- src/calibre/web/feeds/templates.py | 28 +++++---- 4 files changed, 81 insertions(+), 34 deletions(-) diff --git a/resources/recipes/nytimes.recipe b/resources/recipes/nytimes.recipe index 3e02363f68..4c87b68436 100644 --- a/resources/recipes/nytimes.recipe +++ b/resources/recipes/nytimes.recipe @@ -89,6 +89,7 @@ class NYTimes(BasicNewsRecipe): 'relatedSearchesModule', 'side_tool', 'singleAd', + 'subNavigation clearfix', 'subNavigation tabContent active', 'subNavigation tabContent active clearfix', ]}), diff --git a/resources/recipes/nytimes_sub.recipe b/resources/recipes/nytimes_sub.recipe index f8ad12afe9..cd2b83ae4c 100644 --- a/resources/recipes/nytimes_sub.recipe +++ b/resources/recipes/nytimes_sub.recipe @@ -76,6 +76,7 @@ class NYTimes(BasicNewsRecipe): 'relatedSearchesModule', 'side_tool', 'singleAd', + 'subNavigation clearfix', 'subNavigation tabContent active', 'subNavigation tabContent active clearfix', ]}), diff --git a/src/calibre/customize/profiles.py b/src/calibre/customize/profiles.py index d352ce5de7..4bd679407f 100644 --- a/src/calibre/customize/profiles.py +++ b/src/calibre/customize/profiles.py @@ -275,13 +275,43 @@ class iPadOutput(OutputProfile): # touchscreen_news_css {{{ touchscreen_news_css = u''' /* hr used in articles */ + .article_articles_list { + width:18%; + } + .article_link { + font-style: italic; + } + .article_next { + -webkit-border-top-right-radius:4px; + -webkit-border-bottom-right-radius:4px; + font-style: italic; + width:32%; + } + + .article_prev { + -webkit-border-top-left-radius:4px; + -webkit-border-bottom-left-radius:4px; + font-style: italic; + width:32%; + } + .article_sections_list { + width:18%; + } + .articles_link { + font-weight: bold; + } + .sections_link { + font-weight: bold; + } + + .caption_divider { border:#ccc 1px solid; } .touchscreen_navbar { background:#ccc; - border:#ccc 1px solid; + border:#ccc 0px solid; border-collapse:separate; border-spacing:1px; margin-left: 5%; @@ -295,18 +325,6 @@ class iPadOutput(OutputProfile): font-size:90%; padding: 5px; text-align:center; - } - .touchscreen_navbar td:first-child { - -webkit-border-top-left-radius:4px; - -webkit-border-bottom-left-radius:4px; - } - .touchscreen_navbar td:last-child { - -webkit-border-top-right-radius:4px; - -webkit-border-bottom-right-radius:4px; - } - - .feed_link { - font-style: italic; } /* Index formatting */ @@ -318,12 +336,47 @@ class iPadOutput(OutputProfile): border-top:1px solid gray; } + hr.caption_divider { + border-color:black; + border-style:solid; + border-width:1px; + } + /* Feed summary formatting */ + .feed { + font-family:sans-serif; + font-weight:bold; + font-size:larger; + } + + .feed_link { + font-style: italic; + } + + .feed_next { + -webkit-border-top-right-radius:4px; + -webkit-border-bottom-right-radius:4px; + font-style: italic; + width:40%; + } + + .feed_prev { + -webkit-border-top-left-radius:4px; + -webkit-border-bottom-left-radius:4px; + font-style: italic; + width:40%; + } + .feed_title { text-align: center; font-size: 160%; } + .feed_up { + font-weight: bold; + width:20%; + } + .summary_headline { font-weight:bold; text-align:left; @@ -338,12 +391,6 @@ class iPadOutput(OutputProfile): text-align:left; } - .feed { - font-family:sans-serif; - font-weight:bold; - font-size:larger; - } - ''' # }}} diff --git a/src/calibre/web/feeds/templates.py b/src/calibre/web/feeds/templates.py index df414e2e52..1ea7aea9d4 100644 --- a/src/calibre/web/feeds/templates.py +++ b/src/calibre/web/feeds/templates.py @@ -269,11 +269,11 @@ class TouchscreenFeedTemplate(Template): link = A(CLASS('feed_link'), trim_title(feeds[f-1].title), href = '../feed_%d/index.html' % int(f-1)) - navbar_tr.append(TD(link, width="40%", align="center")) + navbar_tr.append(TD(CLASS('feed_prev'),link)) # Up to Sections - link = A(STRONG('Sections'), href="../index.html") - navbar_tr.append(TD(link,width="20%",align="center")) + link = A('Sections', href="../index.html") + navbar_tr.append(TD(CLASS('feed_up'),link)) # Next Section link = '' @@ -281,7 +281,7 @@ class TouchscreenFeedTemplate(Template): link = A(CLASS('feed_link'), trim_title(feeds[f+1].title), href = '../feed_%d/index.html' % int(f+1)) - navbar_tr.append(TD(link, width="40%", align="center", )) + navbar_tr.append(TD(CLASS('feed_next'),link)) navbar_t.append(navbar_tr) top_navbar = navbar_t bottom_navbar = copy.copy(navbar_t) @@ -354,27 +354,25 @@ class TouchscreenNavBarTemplate(Template): # | Previous if art > 0: - href = '%s../article_%d/index.html'%(prefix, art-1) - navbar_tr.append(TD(A(EM('Previous'),href=href), - width="32%")) + link = A(CLASS('article_link'),'Previous',href='%s../article_%d/index.html'%(prefix, art-1)) + navbar_tr.append(TD(CLASS('article_prev'),link)) else: - navbar_tr.append(TD('', width="32%")) + navbar_tr.append(TD(CLASS('article_prev'),'')) # | Articles | Sections | - href = '%s../index.html#article_%d'%(prefix, art) - navbar_tr.append(TD(A(STRONG('Articles'), href=href),width="18%")) + link = A(CLASS('articles_link'),'Articles', href='%s../index.html#article_%d'%(prefix, art)) + navbar_tr.append(TD(CLASS('article_articles_list'),link)) - href = '%s../../index.html#feed_%d'%(prefix, feed) - navbar_tr.append(TD(A(STRONG('Sections'), href=href),width="18%")) + link = A(CLASS('sections_link'),'Sections', href='%s../../index.html#feed_%d'%(prefix, feed)) + navbar_tr.append(TD(CLASS('article_sections_list'),link)) # | Next next = 'feed_%d'%(feed+1) if art == number_of_articles_in_feed - 1 \ else 'article_%d'%(art+1) up = '../..' if art == number_of_articles_in_feed - 1 else '..' - href = '%s%s/%s/index.html'%(prefix, up, next) - navbar_tr.append(TD(A(EM('Next'),href=href), - width="32%")) + link = A(CLASS('article_link'),'Next', href='%s%s/%s/index.html'%(prefix, up, next)) + navbar_tr.append(TD(CLASS('article_next'),link)) navbar_t.append(navbar_tr) navbar.append(navbar_t) #print "\n%s\n" % etree.tostring(navbar, pretty_print=True) From bb45e881c127bc239354e8a828fd16c99bbf7e65 Mon Sep 17 00:00:00 2001 From: GRiker Date: Tue, 29 Jun 2010 06:58:45 -0600 Subject: [PATCH 3/7] GwR revisions wip --- resources/recipes/nytimes.recipe | 6 +- resources/recipes/nytimes_sub.recipe | 6 +- src/calibre/customize/profiles.py | 3 + src/calibre/devices/apple/driver.py | 170 +++++++++++++++++---------- src/calibre/web/feeds/templates.py | 5 +- 5 files changed, 121 insertions(+), 69 deletions(-) diff --git a/resources/recipes/nytimes.recipe b/resources/recipes/nytimes.recipe index 4c87b68436..a2d5135045 100644 --- a/resources/recipes/nytimes.recipe +++ b/resources/recipes/nytimes.recipe @@ -461,8 +461,10 @@ class NYTimes(BasicNewsRecipe): if mp_off >= 0: c = c[:mp_off] emTag.insert(0, c) - hrTag = Tag(soup, 'hr') - #hrTag['style'] = "margin-top:0em;margin-bottom:0em" + #hrTag = Tag(soup, 'hr') + #hrTag['class'] = 'caption_divider' + hrTag = Tag(soup, 'div') + hrTag['class'] = 'divider' emTag.insert(1, hrTag) caption.replaceWith(emTag) diff --git a/resources/recipes/nytimes_sub.recipe b/resources/recipes/nytimes_sub.recipe index cd2b83ae4c..f4101ca299 100644 --- a/resources/recipes/nytimes_sub.recipe +++ b/resources/recipes/nytimes_sub.recipe @@ -351,8 +351,10 @@ class NYTimes(BasicNewsRecipe): if mp_off >= 0: c = c[:mp_off] emTag.insert(0, c) - hrTag = Tag(soup, 'hr') - #hrTag['style'] = "margin-top:0em;margin-bottom:0em" + #hrTag = Tag(soup, 'hr') + #hrTag['class'] = 'caption_divider' + hrTag = Tag(soup, 'div') + hrTag['class'] = 'divider' emTag.insert(1, hrTag) caption.replaceWith(emTag) diff --git a/src/calibre/customize/profiles.py b/src/calibre/customize/profiles.py index 522a876c05..0db3ce6a15 100644 --- a/src/calibre/customize/profiles.py +++ b/src/calibre/customize/profiles.py @@ -350,6 +350,9 @@ class iPadOutput(OutputProfile): } /* Feed summary formatting */ + .article_summary { + display:inline-block; + } .feed { font-family:sans-serif; font-weight:bold; diff --git a/src/calibre/devices/apple/driver.py b/src/calibre/devices/apple/driver.py index 465c31c976..9914f8a321 100644 --- a/src/calibre/devices/apple/driver.py +++ b/src/calibre/devices/apple/driver.py @@ -20,7 +20,7 @@ from calibre.utils.config import config_dir from calibre.utils.date import isoformat, now, parse_date from calibre.utils.localization import get_lang from calibre.utils.logging import Log -from calibre.utils.zipfile import ZipFile +from calibre.utils.zipfile import ZipFile, safe_replace from PIL import Image as PILImage @@ -38,7 +38,7 @@ if iswindows: class DriverBase(DeviceConfig, DevicePlugin): # Needed for config_widget to work FORMATS = ['epub', 'pdf'] - #SUPPORTS_SUB_DIRS = True + SUPPORTS_SUB_DIRS = True # To enable second checkbox in customize widget @classmethod def _config_base_name(cls): @@ -164,6 +164,7 @@ class ITUNES(DriverBase): # Properties cached_books = {} cache_dir = os.path.join(config_dir, 'caches', 'itunes') + archive_path = os.path.join(cache_dir, "thumbs.zip") description_prefix = "added by calibre" ejected = False iTunes= None @@ -276,10 +277,13 @@ class ITUNES(DriverBase): """ if not oncard: if DEBUG: - self.log.info("ITUNES:books(oncard=%s)" % oncard) + self.log.info("ITUNES:books():") + if self.settings().use_subdirs: + self.log.info(" Cover fetching/caching enabled") + else: + self.log.info(" Cover fetching/caching disabled") # Fetch a list of books from iPod device connected to iTunes - if 'iPod' in self.sources: booklist = BookList(self.log) cached_books = {} @@ -294,7 +298,7 @@ class ITUNES(DriverBase): try: this_book.datetime = parse_date(str(book.date_added())).timetuple() except: - pass + this_book.datetime = time.gmtime() this_book.db_id = None this_book.device_collections = [] this_book.library_id = library_books[this_book.path] if this_book.path in library_books else None @@ -332,7 +336,7 @@ class ITUNES(DriverBase): try: this_book.datetime = parse_date(str(book.DateAdded)).timetuple() except: - pass + this_book.datetime = time.gmtime() this_book.db_id = None this_book.device_collections = [] this_book.library_id = library_books[this_book.path] if this_book.path in library_books else None @@ -538,8 +542,7 @@ class ITUNES(DriverBase): # Repurpose the metadata checkbox cw.opt_read_metadata.setText(_("Use Series as Category in iTunes/iBooks")) # Repurpose the use_subdirs checkbox -# cw.opt_use_subdirs.setText(_("Do not display books in iTunes/iBooks database\n" -# "(shortens load time with very large collections).")) + cw.opt_use_subdirs.setText(_("Cache covers from iTunes/iBooks")) return cw def delete_books(self, paths, end_session=True): @@ -697,21 +700,19 @@ class ITUNES(DriverBase): self.log.info("ITUNES.open()") # Confirm/create thumbs archive - archive_path = os.path.join(self.cache_dir, "thumbs.zip") - if not os.path.exists(self.cache_dir): if DEBUG: self.log.info(" creating thumb cache '%s'" % self.cache_dir) os.makedirs(self.cache_dir) - if not os.path.exists(archive_path): + if not os.path.exists(self.archive_path): self.log.info(" creating zip archive") - zfw = ZipFile(archive_path, mode='w') + zfw = ZipFile(self.archive_path, mode='w') zfw.writestr("iTunes Thumbs Archive",'') zfw.close() else: if DEBUG: - self.log.info(" existing thumb cache at '%s'" % archive_path) + self.log.info(" existing thumb cache at '%s'" % self.archive_path) def remove_books_from_metadata(self, paths, booklists): ''' @@ -728,22 +729,43 @@ class ITUNES(DriverBase): if DEBUG: self.log.info("ITUNES.remove_books_from_metadata()") for path in paths: - self._dump_cached_book(self.cached_books[path], indent=2) + #self._dump_cached_book(self.cached_books[path], indent=2) - # Purge the booklist, self.cached_books + # Purge the booklist, self.cached_books, thumb cache for i,bl_book in enumerate(booklists[0]): if False: - self.log.info(" evaluating '%s'" % bl_book.uuid) + self.log.info(" evaluating '%s' '%s'" % (bl_book,bl_book.uuid)) if bl_book.uuid == self.cached_books[path]['uuid']: # Remove from booklists[0] booklists[0].pop(i) + # Remove from self.cached_books for cb in self.cached_books: if self.cached_books[cb]['uuid'] == self.cached_books[path]['uuid']: self.cached_books.pop(cb) break + + # Remove from thumb cache + thumb_path = path.rpartition('.')[0] + '.jpg' + zf = ZipFile(self.archive_path,'a') + fnames = zf.namelist() + try: + plist = [x for x in fnames if thumb_path in x][0] + except: + plist = None + if plist: + if DEBUG: + self.log.info(" deleting '%s' from cover cache" % (thumb_path)) + zf.delete(thumb_path) + else: + if DEBUG: + self.log.info(" '%s' not found in cover cache") + zf.close() + break + + if False: self._dump_booklist(booklists[0], indent = 2) self._dump_cached_books(indent=2) @@ -848,7 +870,6 @@ class ITUNES(DriverBase): self.log.info("ITUNES.upload_books()") self._dump_files(files, header='upload_books()',indent=2) self._dump_update_list(header='upload_books()',indent=2) - #self.log.info(" self.settings().format_map: %s" % self.settings().format_map) if isosx: for (i,file) in enumerate(files): @@ -862,7 +883,10 @@ class ITUNES(DriverBase): new_booklist.append(this_book) self._update_iTunes_metadata(metadata[i], db_added, lb_added, this_book) - # Add new_book to self.cached_paths + # Add new_book to self.cached_books + if DEBUG: + self.log.info(" adding '%s' by '%s' ['%s'] to self.cached_books" % + ( metadata[i].title, metadata[i].author, metadata[i].uuid)) self.cached_books[this_book.path] = { 'author': metadata[i].author, 'dev_book': db_added, @@ -1177,14 +1201,13 @@ class ITUNES(DriverBase): # Refresh the thumbnail cache if DEBUG: - self.log.info( " refreshing cached thumb for '%s'" % metadata.title) - archive_path = os.path.join(self.cache_dir, "thumbs.zip") - zfw = ZipFile(archive_path, mode='a') + self.log.info( " refreshing cached thumb for '%s'" % metadata.title) + zfw = ZipFile(self.archive_path, mode='a') thumb_path = path.rpartition('.')[0] + '.jpg' zfw.writestr(thumb_path, thumb) except: self.problem_titles.append("'%s' by %s" % (metadata.title, metadata.author[0])) - self.log.error(" error converting '%s' to thumb for '%s'" % (metadata.cover,metadata.title)) + self.log.error(" error converting '%s' to thumb for '%s'" % (metadata.cover,metadata.title)) finally: zfw.close() @@ -1250,7 +1273,8 @@ class ITUNES(DriverBase): plist = None if plist: if DEBUG: - self.log.info(" deleting %s from %s" % (pl_name,fpath)) + self.log.info(" _delete_iTunesMetadata_plist():") + self.log.info(" deleting '%s'\n from '%s'" % (pl_name,fpath)) zf.delete(pl_name) zf.close() @@ -1639,52 +1663,67 @@ class ITUNES(DriverBase): as of iTunes 9.2, iBooks 1.1, can't set artwork for PDF files via automation ''' - archive_path = os.path.join(self.cache_dir, "thumbs.zip") + # self.settings().use_subdirs is a repurposed DeviceConfig field + # We're using it to skip fetching/caching covers to speed things up + if not self.settings().use_subdirs: + return None + thumb_path = book_path.rpartition('.')[0] + '.jpg' format = book_path.rpartition('.')[2].lower() try: - zfr = ZipFile(archive_path) + zfr = ZipFile(self.archive_path) thumb_data = zfr.read(thumb_path) - zfr.close() + if thumb_data == '\x00\x00': + if DEBUG: + self.log.info(" ITUNES._generate_thumbnail()\n returning None for '%s'" % book.name()) + zfr.close() + return None except: - zfw = ZipFile(archive_path, mode='a') + zfw = ZipFile(self.archive_path, mode='a') else: return thumb_data - self.log.info(" ITUNES._generate_thumbnail()") + self.log.info(" ITUNES._generate_thumbnail():") if isosx: if format == 'epub': + # Fetch the artwork try: - if False: - self.log.info(" fetching artwork from %s\n %s" % (book_path,book)) - # Resize the cover data = book.artworks[1].raw_data().data - #self._dump_hex(data[:256]) + except: + # If no artwork, write an empty marker to cache + if DEBUG: + self.log.error(" error reading artwork from '%s'" % book.name()) + zfw.writestr(thumb_path, '\x00\x00') + zfw.close() + return None + + # Generate a thumb + try: img_data = cStringIO.StringIO(data) im = PILImage.open(img_data) scaled, width, height = fit_image(im.size[0],im.size[1], 60, 80) im = im.resize((int(width),int(height)), PILImage.ANTIALIAS) - img_data.close() thumb = cStringIO.StringIO() im.convert('RGB').save(thumb,'JPEG') thumb_data = thumb.getvalue() thumb.close() - - # Cache the tagged thumb if DEBUG: self.log.info(" generated thumb for '%s', caching" % book.name()) - zfw.writestr(thumb_path, thumb_data) - zfw.close() - return thumb_data except: - self.log.error(" error generating thumb for '%s'" % book.name()) - try: - zfw.close() - except: - pass - return None + if DEBUG: + self.log.error(" error generating thumb for '%s', caching empty marker" % book.name()) + self._dump_hex(data[:32]) + thumb_data = '\x00\x00' + finally: + # Cache the tagged thumb + zfw.writestr(thumb_path, thumb_data) + img_data.close() + zfw.close() + + return thumb_data + else: if DEBUG: self.log.info(" unable to generate PDF thumbs") @@ -1692,9 +1731,12 @@ class ITUNES(DriverBase): elif iswindows: + # Fetch the artwork if not book.Artwork.Count: if DEBUG: self.log.info(" no artwork available for '%s'" % book.Name) + zfw.writestr(thumb_path, '\x00\x00') + zfw.close() return None if format == 'epub': @@ -1711,20 +1753,20 @@ class ITUNES(DriverBase): thumb_data = thumb.getvalue() os.remove(tmp_thumb) thumb.close() - - # Cache the tagged thumb if DEBUG: self.log.info(" generated thumb for '%s', caching" % book.Name) + + except: + if DEBUG: + self.log.error(" error generating thumb for '%s', caching empty marker" % book.Name) + self._dump_hex(data[:32]) + thumb_data = '\x00\x00' + finally: + # Cache the tagged thumb zfw.writestr(thumb_path, thumb_data) zfw.close() - return thumb_data - except: - self.log.error(" error generating thumb for '%s'" % book.Name) - try: - zfw.close() - except: - pass - return None + + return thumb_data else: if DEBUG: self.log.info(" unable to generate PDF thumbs") @@ -2205,9 +2247,9 @@ class ITUNES(DriverBase): if DEBUG: self.log.info( " deleting library book '%s'" % metadata.title) break - else: - if DEBUG: - self.log.info(" '%s' not found in cached_books" % metadata.title) + else: + if DEBUG: + self.log.info(" '%s' not found in cached_books" % metadata.title) def _remove_from_device(self, cached_book): ''' @@ -2269,7 +2311,7 @@ class ITUNES(DriverBase): except: # We get here if there was an error with .location().path if DEBUG: - self.log.info(" '%s' not found in iTunes" % cached_book['title']) + self.log.info(" '%s' not in iTunes storage" % cached_book['title']) try: self.iTunes.delete(cached_book['lib_book']) @@ -2298,7 +2340,7 @@ class ITUNES(DriverBase): try: os.remove(path) except: - self.log.warning(" could not find '%s' in iTunes storage" % path) + self.log.warning(" '%s' not in iTunes storage" % path) try: os.rmdir(storage_path[0]) self.log.info(" removed folder '%s'" % storage_path[0]) @@ -2633,7 +2675,11 @@ class ITUNES_ASYNC(ITUNES): """ if not oncard: if DEBUG: - self.log.info("ITUNES_ASYNC:books(oncard=%s)" % oncard) + self.log.info("ITUNES_ASYNC:books()") + if self.settings().use_subdirs: + self.log.info(" Cover fetching/caching enabled") + else: + self.log.info(" Cover fetching/caching disabled") # Fetch a list of books from iTunes @@ -2650,7 +2696,7 @@ class ITUNES_ASYNC(ITUNES): try: this_book.datetime = parse_date(str(library_books[book].date_added())).timetuple() except: - pass + this_book.datetime = time.gmtime() this_book.db_id = None this_book.device_collections = [] #this_book.library_id = library_books[this_book.path] if this_book.path in library_books else None @@ -2689,7 +2735,7 @@ class ITUNES_ASYNC(ITUNES): try: this_book.datetime = parse_date(str(library_books[book].DateAdded)).timetuple() except: - pass + this_book.datetime = time.gmtime() this_book.db_id = None this_book.device_collections = [] this_book.library_id = library_books[book] diff --git a/src/calibre/web/feeds/templates.py b/src/calibre/web/feeds/templates.py index 1ea7aea9d4..4f26a35a02 100644 --- a/src/calibre/web/feeds/templates.py +++ b/src/calibre/web/feeds/templates.py @@ -319,10 +319,9 @@ class TouchscreenFeedTemplate(Template): continue tr = TR() - div_td = DIV( + div_td = DIV(CLASS('article_summary'), A(article.title, CLASS('summary_headline','calibre_rescale_120', - href=article.url)), - style="display:inline-block") + href=article.url))) if article.author: div_td.append(DIV(article.author, CLASS('summary_byline', 'calibre_rescale_100'))) From 7beba1d6867ad11e7b8f99175057df337bdb1d5b Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 29 Jun 2010 08:00:15 -0600 Subject: [PATCH 4/7] No longer mark connect to iTunes as experimental --- src/calibre/gui2/device.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index 584796231a..c5e042d3e3 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -495,7 +495,7 @@ class DeviceMenu(QMenu): # {{{ self.connect_to_folder_action = mitem mitem = self.addAction(QIcon(I('devices/itunes.png')), - _('Connect to iTunes (EXPERIMENTAL)')) + _('Connect to iTunes')) mitem.setEnabled(True) mitem.triggered.connect(lambda x : self.connect_to_itunes.emit()) self.connect_to_itunes_action = mitem From 35245e15fbe2f128522036cec8822597f8936b24 Mon Sep 17 00:00:00 2001 From: GRiker Date: Tue, 29 Jun 2010 15:36:48 -0600 Subject: [PATCH 5/7] GwR wip --- src/calibre/devices/apple/driver.py | 383 +++++++++++++++++----------- 1 file changed, 230 insertions(+), 153 deletions(-) diff --git a/src/calibre/devices/apple/driver.py b/src/calibre/devices/apple/driver.py index 941517cfa3..6c9235c0d4 100644 --- a/src/calibre/devices/apple/driver.py +++ b/src/calibre/devices/apple/driver.py @@ -172,7 +172,7 @@ class ITUNES(DriverBase): library_orphans = None log = Log() manual_sync_mode = False - path_template = 'iTunes/%s - %s.epub' + path_template = 'iTunes/%s - %s.%s' problem_titles = [] problem_msg = None report_progress = None @@ -256,7 +256,7 @@ class ITUNES(DriverBase): (new_book.title, new_book.author)) booklists[0].append(new_book) - if DEBUG: + if False: self._dump_booklist(booklists[0],header='after',indent=2) self._dump_cached_books(header='after',indent=2) @@ -294,7 +294,8 @@ class ITUNES(DriverBase): book_count = float(len(device_books)) for (i,book) in enumerate(device_books): this_book = Book(book.name(), book.artist()) - this_book.path = self.path_template % (book.name(), book.artist()) + format = 'pdf' if book.kind().startswith('PDF') else 'epub' + this_book.path = self.path_template % (book.name(), book.artist(),format) try: this_book.datetime = parse_date(str(book.date_added())).timetuple() except: @@ -332,7 +333,8 @@ class ITUNES(DriverBase): book_count = float(len(device_books)) for (i,book) in enumerate(device_books): this_book = Book(book.Name, book.Artist) - this_book.path = self.path_template % (book.Name, book.Artist) + format = 'pdf' if book.KindAsString.startswith('PDF') else 'epub' + this_book.path = self.path_template % (book.Name, book.Artist,format) try: this_book.datetime = parse_date(str(book.DateAdded)).timetuple() except: @@ -729,42 +731,61 @@ class ITUNES(DriverBase): if DEBUG: self.log.info("ITUNES.remove_books_from_metadata()") for path in paths: - #self._dump_cached_book(self.cached_books[path], indent=2) + if DEBUG: + self._dump_cached_book(self.cached_books[path], indent=2) + self.log.info(" looking for '%s' by '%s' (%s)" % + (self.cached_books[path]['title'], + self.cached_books[path]['author'], + self.cached_books[path]['uuid'])) # Purge the booklist, self.cached_books, thumb cache for i,bl_book in enumerate(booklists[0]): if False: - self.log.info(" evaluating '%s' '%s'" % (bl_book,bl_book.uuid)) - if bl_book.uuid == self.cached_books[path]['uuid']: - # Remove from booklists[0] - booklists[0].pop(i) + self.log.info(" evaluating '%s' by '%s' (%s)" % + (bl_book.title, bl_book.author,bl_book.uuid)) + found = False + if bl_book.uuid == self.cached_books[path]['uuid']: + if False: + self.log.info(" matched with uuid") + booklists[0].pop(i) + found = True + elif bl_book.title == self.cached_books[path]['title'] and \ + bl_book.author[0] == self.cached_books[path]['author']: + if False: + self.log.info(" matched with title + author") + booklists[0].pop(i) + found = True + + if found: # Remove from self.cached_books for cb in self.cached_books: if self.cached_books[cb]['uuid'] == self.cached_books[path]['uuid']: self.cached_books.pop(cb) break - # Remove from thumb cache + # Remove from thumb from thumb cache thumb_path = path.rpartition('.')[0] + '.jpg' zf = ZipFile(self.archive_path,'a') fnames = zf.namelist() try: - plist = [x for x in fnames if thumb_path in x][0] + thumb = [x for x in fnames if thumb_path in x][0] except: - plist = None - if plist: + thumb = None + if thumb: if DEBUG: self.log.info(" deleting '%s' from cover cache" % (thumb_path)) zf.delete(thumb_path) else: if DEBUG: - self.log.info(" '%s' not found in cover cache") + self.log.info(" '%s' not found in cover cache" % thumb_path) zf.close() break - - +# else: +# if DEBUG: +# self.log.error(" unable to find '%s' by '%s' (%s)" % +# (bl_book.title, bl_book.author,bl_book.uuid)) if False: self._dump_booklist(booklists[0], indent = 2) @@ -874,7 +895,7 @@ class ITUNES(DriverBase): if isosx: for (i,file) in enumerate(files): format = file.rpartition('.')[2].lower() - path = self.path_template % (metadata[i].title, metadata[i].author[0]) + path = self.path_template % (metadata[i].title, metadata[i].author[0],format) self._remove_existing_copy(path, metadata[i]) fpath = self._get_fpath(file, metadata[i], format, update_md=True) db_added, lb_added = self._add_new_copy(fpath, metadata[i]) @@ -907,7 +928,7 @@ class ITUNES(DriverBase): for (i,file) in enumerate(files): format = file.rpartition('.')[2].lower() - path = self.path_template % (metadata[i].title, metadata[i].author[0]) + path = self.path_template % (metadata[i].title, metadata[i].author[0],format) self._remove_existing_copy(path, metadata[i]) fpath = self._get_fpath(file, metadata[i],format, update_md=True) db_added, lb_added = self._add_new_copy(fpath, metadata[i]) @@ -1121,7 +1142,7 @@ class ITUNES(DriverBase): thumb = None if metadata.cover: - if (format == 'epub'): + if format == 'epub': # Pre-shrink cover # self.MAX_COVER_WIDTH, self.MAX_COVER_HEIGHT try: @@ -1210,7 +1231,9 @@ class ITUNES(DriverBase): self.log.error(" error converting '%s' to thumb for '%s'" % (metadata.cover,metadata.title)) finally: zfw.close() - + else: + if DEBUG: + self.log.info(" no cover defined in metadata for '%s'" % metadata.title) return thumb def _create_new_book(self,fpath, metadata, path, db_added, lb_added, thumb, format): @@ -1219,8 +1242,9 @@ class ITUNES(DriverBase): if DEBUG: self.log.info(" ITUNES._create_new_book()") - this_book = Book(metadata.title, metadata.author[0]) - + #this_book = Book(metadata.title, metadata.author[0]) + this_book = Book(metadata.title, ' & '.join(metadata.author)) + this_book.datetime = time.gmtime() this_book.db_id = None this_book.device_collections = [] this_book.format = format @@ -1236,13 +1260,13 @@ class ITUNES(DriverBase): try: this_book.datetime = parse_date(str(lb_added.date_added())).timetuple() except: - this_book.datetime = time.gmtime() + pass elif db_added: this_book.size = self._get_device_book_size(fpath, db_added.size()) try: this_book.datetime = parse_date(str(db_added.date_added())).timetuple() except: - this_book.datetime = time.gmtime() + pass elif iswindows: if lb_added: @@ -1250,13 +1274,13 @@ class ITUNES(DriverBase): try: this_book.datetime = parse_date(str(lb_added.DateAdded)).timetuple() except: - this_book.datetime = time.gmtime() + pass elif db_added: this_book.size = self._get_device_book_size(fpath, db_added.Size) try: this_book.datetime = parse_date(str(db_added.DateAdded)).timetuple() except: - this_book.datetime = time.gmtime() + pass return this_book @@ -1524,27 +1548,45 @@ class ITUNES(DriverBase): if iswindows: dev_books = self._get_device_books_playlist() if DEBUG: - self.log.info(" ITUNES._find_device_book(uuid)") - self.log.info(" searching for %s ('%s' by %s)" % - (search['uuid'], search['title'], search['author'])) + self.log.info(" ITUNES._find_device_book()") + self.log.info(" searching for '%s' by '%s' (%s)" % + (search['title'], search['author'],search['uuid'])) attempts = 9 while attempts: # Try by uuid - only one hit - hits = dev_books.Search(search['uuid'],self.SearchField.index('All')) - if hits: - hit = hits[0] - self.log.info(" found '%s' by %s (%s)" % (hit.Name, hit.Artist, hit.Composer)) - return hit + if 'uuid' in search and search['uuid']: + if DEBUG: + self.log.info(" searching by uuid '%s' ..." % search['uuid']) + hits = dev_books.Search(search['uuid'],self.SearchField.index('All')) + if hits: + hit = hits[0] + self.log.info(" found '%s' by %s (%s)" % (hit.Name, hit.Artist, hit.Composer)) + return hit # Try by author - there could be multiple hits - hits = dev_books.Search(search['author'],self.SearchField.index('Artists')) + if search['author']: + if DEBUG: + self.log.info(" searching by author '%s' ..." % search['author']) + hits = dev_books.Search(search['author'],self.SearchField.index('Artists')) + if hits: + for hit in hits: + if hit.Name == search['title']: + if DEBUG: + self.log.info(" found '%s' by %s (%s)" % (hit.Name, hit.Artist, hit.Composer)) + return hit + + # Search by title if no author available + if DEBUG: + self.log.info(" searching by title '%s' ..." % search['title']) + hits = dev_books.Search(search['title'],self.SearchField.index('All')) if hits: for hit in hits: if hit.Name == search['title']: if DEBUG: - self.log.info(" found '%s' by %s (%s)" % (hit.Name, hit.Artist, hit.Composer)) + self.log.info(" found '%s'" % (hit.Name)) return hit + # PDF just sent, title not updated yet, look for export pattern # PDF metadata was rewritten at export as 'safe(title) - safe(author)' if search['format'] == 'pdf': title = re.sub(r'[^0-9a-zA-Z ]', '_', search['title']) @@ -1577,12 +1619,14 @@ class ITUNES(DriverBase): if iswindows: if DEBUG: self.log.info(" ITUNES._find_library_book()") + ''' if 'uuid' in search: self.log.info(" looking for '%s' by %s (%s)" % (search['title'], search['author'], search['uuid'])) else: self.log.info(" looking for '%s' by %s" % (search['title'], search['author'])) + ''' for source in self.iTunes.sources: if source.Kind == self.Sources.index('Library'): @@ -1607,10 +1651,11 @@ class ITUNES(DriverBase): if DEBUG: self.log.error(" no Books playlist found") + attempts = 9 while attempts: # Find book whose Album field = search['uuid'] - if 'uuid' in search: + if 'uuid' in search and search['uuid']: if DEBUG: self.log.info(" searching by uuid '%s' ..." % search['uuid']) hits = lib_books.Search(search['uuid'],self.SearchField.index('All')) @@ -1620,16 +1665,30 @@ class ITUNES(DriverBase): self.log.info(" found '%s' by %s (%s)" % (hit.Name, hit.Artist, hit.Composer)) return hit + # Search by author if known + if search['author']: + if DEBUG: + self.log.info(" searching by author '%s' ..." % search['author']) + hits = lib_books.Search(search['author'],self.SearchField.index('Artists')) + if hits: + for hit in hits: + if hit.Name == search['title']: + if DEBUG: + self.log.info(" found '%s' by %s (%s)" % (hit.Name, hit.Artist, hit.Composer)) + return hit + + # Search by title if no author available if DEBUG: - self.log.info(" searching by author '%s' ..." % search['author']) - hits = lib_books.Search(search['author'],self.SearchField.index('Artists')) + self.log.info(" searching by title '%s' ..." % search['title']) + hits = lib_books.Search(search['title'],self.SearchField.index('All')) if hits: for hit in hits: if hit.Name == search['title']: if DEBUG: - self.log.info(" found '%s' by %s (%s)" % (hit.Name, hit.Artist, hit.Composer)) + self.log.info(" found '%s'" % (hit.Name)) return hit + # PDF just sent, title not updated yet, look for export pattern # PDF metadata was rewritten at export as 'safe(title) - safe(author)' if search['format'] == 'pdf': title = re.sub(r'[^0-9a-zA-Z ]', '_', search['title']) @@ -1666,112 +1725,114 @@ class ITUNES(DriverBase): # self.settings().use_subdirs is a repurposed DeviceConfig field # We're using it to skip fetching/caching covers to speed things up if not self.settings().use_subdirs: - return None + thumb_data = None + return thumb_data thumb_path = book_path.rpartition('.')[0] + '.jpg' format = book_path.rpartition('.')[2].lower() + if isosx: + title = book.name() + elif iswindows: + title = book.Name try: zfr = ZipFile(self.archive_path) thumb_data = zfr.read(thumb_path) - if thumb_data == '\x00\x00': - if DEBUG: - self.log.info(" ITUNES._generate_thumbnail()\n returning None for '%s'" % book.name()) + if thumb_data == 'None': + if False: + self.log.info(" ITUNES._generate_thumbnail()\n returning None from cover cache for '%s'" % title) zfr.close() return None except: zfw = ZipFile(self.archive_path, mode='a') else: + if False: + self.log.info(" returning thumb from cache for '%s'" % title) return thumb_data - self.log.info(" ITUNES._generate_thumbnail():") + if DEBUG: + self.log.info(" ITUNES._generate_thumbnail():") if isosx: - if format == 'epub': - # Fetch the artwork - try: - data = book.artworks[1].raw_data().data - except: - # If no artwork, write an empty marker to cache - if DEBUG: - self.log.error(" error reading artwork from '%s'" % book.name()) - zfw.writestr(thumb_path, '\x00\x00') - zfw.close() - return None - # Generate a thumb - try: - img_data = cStringIO.StringIO(data) - im = PILImage.open(img_data) - scaled, width, height = fit_image(im.size[0],im.size[1], 60, 80) - im = im.resize((int(width),int(height)), PILImage.ANTIALIAS) - - thumb = cStringIO.StringIO() - im.convert('RGB').save(thumb,'JPEG') - thumb_data = thumb.getvalue() - thumb.close() - if DEBUG: - self.log.info(" generated thumb for '%s', caching" % book.name()) - except: - if DEBUG: - self.log.error(" error generating thumb for '%s', caching empty marker" % book.name()) - self._dump_hex(data[:32]) - thumb_data = '\x00\x00' - finally: - # Cache the tagged thumb - zfw.writestr(thumb_path, thumb_data) - img_data.close() - zfw.close() - - return thumb_data - - else: + # Fetch the artwork from iTunes + try: + data = book.artworks[1].raw_data().data + except: + # If no artwork, write an empty marker to cache if DEBUG: - self.log.info(" unable to generate PDF thumbs") - return None - - elif iswindows: - - # Fetch the artwork - if not book.Artwork.Count: - if DEBUG: - self.log.info(" no artwork available for '%s'" % book.Name) - zfw.writestr(thumb_path, '\x00\x00') + self.log.error(" error fetching iTunes artwork for '%s'" % title) + zfw.writestr(thumb_path, 'None') zfw.close() return None - if format == 'epub': - # Save the cover from iTunes - try: - tmp_thumb = os.path.join(tempfile.gettempdir(), "thumb.%s" % self.ArtworkFormat[book.Artwork.Item(1).Format]) - book.Artwork.Item(1).SaveArtworkToFile(tmp_thumb) - # Resize the cover - im = PILImage.open(tmp_thumb) - scaled, width, height = fit_image(im.size[0],im.size[1], 60, 80) - im = im.resize((int(width),int(height)), PILImage.ANTIALIAS) - thumb = cStringIO.StringIO() - im.convert('RGB').save(thumb,'JPEG') - thumb_data = thumb.getvalue() - os.remove(tmp_thumb) - thumb.close() - if DEBUG: - self.log.info(" generated thumb for '%s', caching" % book.Name) + # Generate a thumb + try: + img_data = cStringIO.StringIO(data) + im = PILImage.open(img_data) + scaled, width, height = fit_image(im.size[0],im.size[1], 60, 80) + im = im.resize((int(width),int(height)), PILImage.ANTIALIAS) - except: - if DEBUG: - self.log.error(" error generating thumb for '%s', caching empty marker" % book.Name) - self._dump_hex(data[:32]) - thumb_data = '\x00\x00' - finally: - # Cache the tagged thumb - zfw.writestr(thumb_path, thumb_data) - zfw.close() - - return thumb_data - else: + thumb = cStringIO.StringIO() + im.convert('RGB').save(thumb,'JPEG') + thumb_data = thumb.getvalue() + thumb.close() + if False: + self.log.info(" generated thumb for '%s', caching" % title) + # Cache the tagged thumb + zfw.writestr(thumb_path, thumb_data) + except: if DEBUG: - self.log.info(" unable to generate PDF thumbs") + self.log.error(" error generating thumb for '%s', caching empty marker" % book.name()) + self._dump_hex(data[:32]) + thumb_data = None + # Cache the empty cover + zfw.writestr(thumb_path, 'None') + finally: + img_data.close() + zfw.close() + + return thumb_data + + + elif iswindows: + if not book.Artwork.Count: + if DEBUG: + self.log.info(" no artwork available for '%s'" % book.Name) + zfw.writestr(thumb_path, 'None') + zfw.close() return None + # Fetch the artwork from iTunes + + try: + tmp_thumb = os.path.join(tempfile.gettempdir(), "thumb.%s" % self.ArtworkFormat[book.Artwork.Item(1).Format]) + book.Artwork.Item(1).SaveArtworkToFile(tmp_thumb) + # Resize the cover + im = PILImage.open(tmp_thumb) + scaled, width, height = fit_image(im.size[0],im.size[1], 60, 80) + im = im.resize((int(width),int(height)), PILImage.ANTIALIAS) + thumb = cStringIO.StringIO() + im.convert('RGB').save(thumb,'JPEG') + thumb_data = thumb.getvalue() + os.remove(tmp_thumb) + thumb.close() + if False: + self.log.info(" generated thumb for '%s', caching" % book.Name) + # Cache the tagged thumb + zfw.writestr(thumb_path, thumb_data) + except: + if DEBUG: + self.log.error(" error generating thumb for '%s', caching empty marker" % book.Name) + self._dump_hex(data[:32]) + thumb_data = None + # Cache the empty cover + zfw.writestr(thumb_path,'None') + + finally: + zfw.close() + + return thumb_data + def _get_device_book_size(self, file, compressed_size): ''' Calculate the exploded size of file @@ -1952,7 +2013,8 @@ class ITUNES(DriverBase): self.log.info(" ignoring '%s' of type '%s'" % (book.name(), book.kind())) else: # Collect calibre orphans - remnants of recipe uploads - path = self.path_template % (book.name(), book.artist()) + format = 'pdf' if book.kind().startswith('PDF') else 'epub' + path = self.path_template % (book.name(), book.artist(),format) if str(book.description()).startswith(self.description_prefix): try: if book.location() == appscript.k.missing_value: @@ -1965,7 +2027,8 @@ class ITUNES(DriverBase): library_books[path] = book if DEBUG: - self.log.info(" %-30.30s %-30.30s %-40.40s [%s]" % (book.name(), book.artist(), book.album(), book.kind())) + self.log.info(" %-30.30s %-30.30s %-40.40s [%s]" % + (book.name(), book.artist(), book.album(), book.kind())) else: if DEBUG: self.log.info(' no Library playlists') @@ -2007,7 +2070,8 @@ class ITUNES(DriverBase): if DEBUG: self.log.info(" ignoring %-30.30s of type '%s'" % (book.Name, book.KindAsString)) else: - path = self.path_template % (book.Name, book.Artist) + format = 'pdf' if book.KindAsString.startswith('PDF') else 'epub' + path = self.path_template % (book.Name, book.Artist,format) # Collect calibre orphans if book.Description.startswith(self.description_prefix): @@ -2222,7 +2286,9 @@ class ITUNES(DriverBase): # Delete existing from Device|Books, add to self.update_list # for deletion from booklist[0] during add_books_to_metadata for book in self.cached_books: - if self.cached_books[book]['uuid'] == metadata.uuid: + if self.cached_books[book]['uuid'] == metadata.uuid and \ + self.cached_books[book]['title'] == metadata.title and \ + self.cached_books[book]['author'] == metadata.authors[0]: self.update_list.append(self.cached_books[book]) self._remove_from_device(self.cached_books[book]) if DEBUG: @@ -2239,9 +2305,9 @@ class ITUNES(DriverBase): # Delete existing from Library|Books, add to self.update_list # for deletion from booklist[0] during add_books_to_metadata for book in self.cached_books: - if (self.cached_books[book]['uuid'] == metadata.uuid) or \ - (self.cached_books[book]['title'] == metadata.title and \ - self.cached_books[book]['author'] == metadata.authors[0]): + if self.cached_books[book]['uuid'] == metadata.uuid and \ + self.cached_books[book]['title'] == metadata.title and \ + self.cached_books[book]['author'] == metadata.authors[0]: self.update_list.append(self.cached_books[book]) self._remove_from_iTunes(self.cached_books[book]) if DEBUG: @@ -2257,18 +2323,20 @@ class ITUNES(DriverBase): ''' self.log.info(" ITUNES._remove_from_device()") if isosx: - if False: - self.log.info(" deleting %s" % cached_book['dev_book']) + if DEBUG: + self.log.info(" deleting '%s' from iDevice" % cached_book['title']) cached_book['dev_book'].delete() elif iswindows: - dev_pl = self._get_device_books_playlist() - hits = dev_pl.Search(cached_book['uuid'],self.SearchField.index('All')) - if hits: - hit = hits[0] - if False: - self.log.info(" deleting '%s' by %s (%s)" % (hit.Name, hit.Artist, hit.Album)) + hit = self._find_device_book(cached_book) + if hit: + if DEBUG: + self.log.info(" deleting '%s' from iDevice" % cached_book['title']) hit.Delete() + else: + if DEBUG: + self.log.warning(" unable to remove '%s' by '%s' (%s) from device" % + (cached_book['title'],cached_book['author'],cached_book['uuid'])) def _remove_from_iTunes(self, cached_book): ''' @@ -2329,7 +2397,8 @@ class ITUNES(DriverBase): path = book.Location except: book = self._find_library_book(cached_book) - path = book.Location + if book: + path = book.Location if book: if self.iTunes_media and path.startswith(self.iTunes_media): @@ -2479,7 +2548,8 @@ class ITUNES(DriverBase): if isosx: if lb_added: lb_added.album.set(metadata.title) - lb_added.artist.set(metadata.authors[0]) + #lb_added.artist.set(metadata.authors[0]) + lb_added.artist.set(' & '.join(metadata.authors)) lb_added.composer.set(metadata.uuid) lb_added.description.set("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S'))) lb_added.enabled.set(True) @@ -2490,7 +2560,8 @@ class ITUNES(DriverBase): if db_added: db_added.album.set(metadata.title) - db_added.artist.set(metadata.authors[0]) + #db_added.artist.set(metadata.authors[0]) + db_added.artist.set(' & '.join(metadata.authors)) db_added.composer.set(metadata.uuid) db_added.description.set("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S'))) db_added.enabled.set(True) @@ -2547,7 +2618,8 @@ class ITUNES(DriverBase): elif iswindows: if lb_added: lb_added.Album = metadata.title - lb_added.Artist = metadata.authors[0] + #lb_added.Artist = metadata.authors[0] + lb_added.Artist = ' & '.join(metadata.authors) lb_added.Composer = metadata.uuid lb_added.Description = ("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S'))) lb_added.Enabled = True @@ -2558,7 +2630,8 @@ class ITUNES(DriverBase): if db_added: db_added.Album = metadata.title - db_added.Artist = metadata.authors[0] + #db_added.Artist = metadata.authors[0] + db_added.Artist = ' & '.join(metadata.authors) db_added.Composer = metadata.uuid db_added.Description = ("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S'))) db_added.Enabled = True @@ -2690,9 +2763,11 @@ class ITUNES_ASYNC(ITUNES): library_books = self._get_library_books() book_count = float(len(library_books)) for (i,book) in enumerate(library_books): + format = 'pdf' if library_books[book].kind().startswith('PDF') else 'epub' this_book = Book(library_books[book].name(), library_books[book].artist()) this_book.path = self.path_template % (library_books[book].name(), - library_books[book].artist()) + library_books[book].artist(), + format) try: this_book.datetime = parse_date(str(library_books[book].date_added())).timetuple() except: @@ -2716,7 +2791,7 @@ class ITUNES_ASYNC(ITUNES): 'lib_book':library_books[book], 'dev_book':None, 'uuid': library_books[book].composer(), - #'format': 'pdf' if book.KindAsString.startswith('PDF') else 'epub' + 'format': format } if self.report_progress is not None: @@ -2730,8 +2805,10 @@ class ITUNES_ASYNC(ITUNES): book_count = float(len(library_books)) for (i,book) in enumerate(library_books): this_book = Book(library_books[book].Name, library_books[book].Artist) + format = 'pdf' if library_books[book].KindAsString.startswith('PDF') else 'epub' this_book.path = self.path_template % (library_books[book].Name, - library_books[book].Artist) + library_books[book].Artist, + format) try: this_book.datetime = parse_date(str(library_books[book].DateAdded)).timetuple() except: @@ -2752,7 +2829,7 @@ class ITUNES_ASYNC(ITUNES): 'author':library_books[book].Artist, 'lib_book':library_books[book], 'uuid': library_books[book].Composer, - 'format': 'pdf' if library_books[book].KindAsString.startswith('PDF') else 'epub' + 'format': format } if self.report_progress is not None: @@ -2773,13 +2850,6 @@ class ITUNES_ASYNC(ITUNES): else: return BookList(self.log) - def unmount_device(self): - ''' - ''' - if DEBUG: - self.log.info("ITUNES_ASYNC:unmount_device()") - self.connected = False - def eject(self): ''' Un-mount / eject the device from the OS. This does not check if there @@ -2845,6 +2915,13 @@ class ITUNES_ASYNC(ITUNES): self.problem_msg = None self.update_list = [] + def unmount_device(self): + ''' + ''' + if DEBUG: + self.log.info("ITUNES_ASYNC:unmount_device()") + self.connected = False + class BookList(list): ''' A list of books. Each Book object must have the fields: From 9b9176866562d4f63380a27ddaec63effffb96d6 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 29 Jun 2010 21:29:31 -0600 Subject: [PATCH 6/7] Upgrade podofo to 0.8.1 from 0.7.0 --- setup/installer/linux/freeze.py | 2 +- setup/installer/osx/app/main.py | 5 ++- setup/installer/windows/notes.rst | 47 ++++++++++++++++++++++-- setup/installer/windows/wix-template.xml | 10 +---- src/calibre/utils/podofo/podofo.cpp | 7 +++- 5 files changed, 55 insertions(+), 16 deletions(-) diff --git a/setup/installer/linux/freeze.py b/setup/installer/linux/freeze.py index 7353134393..08237b83fa 100644 --- a/setup/installer/linux/freeze.py +++ b/setup/installer/linux/freeze.py @@ -46,7 +46,7 @@ class LinuxFreeze(Command): '/usr/lib/libsqlite3.so.0', '/usr/lib/libsqlite3.so.0', '/usr/lib/libmng.so.1', - '/usr/lib/libpodofo.so.0.6.99', + '/usr/lib/libpodofo.so.0.8.1', '/lib/libz.so.1', '/lib/libuuid.so.1', '/usr/lib/libtiff.so.3', diff --git a/setup/installer/osx/app/main.py b/setup/installer/osx/app/main.py index 5b01c8503c..c95be6752c 100644 --- a/setup/installer/osx/app/main.py +++ b/setup/installer/osx/app/main.py @@ -265,6 +265,9 @@ class Py2App(object): @flush def get_local_dependencies(self, path_to_lib): for x in self.get_dependencies(path_to_lib): + if x.startswith('libpodofo'): + yield x, x + continue for y in (SW+'/lib/', '/usr/local/lib/', SW+'/qt/lib/', '/opt/local/lib/', '/Library/Frameworks/Python.framework/', SW+'/freetype/lib/'): @@ -397,7 +400,7 @@ class Py2App(object): @flush def add_podofo(self): info('\nAdding PoDoFo') - pdf = join(SW, 'lib', 'libpodofo.0.6.99.dylib') + pdf = join(SW, 'lib', 'libpodofo.0.8.1.dylib') self.install_dylib(pdf) @flush diff --git a/setup/installer/windows/notes.rst b/setup/installer/windows/notes.rst index 0fdecda27c..cd02c80d2e 100644 --- a/setup/installer/windows/notes.rst +++ b/setup/installer/windows/notes.rst @@ -162,9 +162,50 @@ SET(WANT_LIB64 FALSE) SET(PODOFO_BUILD_SHARED TRUE) SET(PODOFO_BUILD_STATIC FALSE) -cp build/podofo-0.7.0/build/src/Release/podofo.dll bin/ -cp build/podofo-0.7.0/build/src/Release/podofo.lib lib/ -cp build/podofo-0.7.0/build/src/Release/podofo.exp lib/ +cp build/podofo/build/src/Release/podofo.dll bin/ +cp build/podofo/build/src/Release/podofo.lib lib/ +cp build/podofo/build/src/Release/podofo.exp lib/ + +cp build/podofo/build/podofo_config.h include/podofo/ +cp -r build/podofo/src/* include/podofo/ + +The following patch was required to get it to compile: + +Index: src/PdfImage.cpp +=================================================================== +--- src/PdfImage.cpp (revision 1261) ++++ src/PdfImage.cpp (working copy) +@@ -627,7 +627,7 @@ + + long lLen = static_cast(pInfo->rowbytes * height); + char* pBuffer = static_cast(malloc(sizeof(char) * lLen)); +- png_bytep pRows[height]; ++ png_bytepp pRows = static_cast(malloc(sizeof(png_bytep)*height)); + for(int y=0; y(pBuffer + (y * pInfo->rowbytes)); +@@ -672,6 +672,7 @@ + this->SetImageData( width, height, pInfo->bit_depth, &stream ); + + free(pBuffer); ++ free(pRows); + } + #endif // PODOFO_HAVE_PNG_LIB + +Index: src/PdfFiltersPrivate.cpp +=================================================================== +--- src/PdfFiltersPrivate.cpp (revision 1261) ++++ src/PdfFiltersPrivate.cpp (working copy) +@@ -1019,7 +1019,7 @@ + /* + * Prepare for input from a memory buffer. + */ +-GLOBAL(void) ++void + jpeg_memory_src (j_decompress_ptr cinfo, const JOCTET * buffer, size_t bufsize) + { + my_src_ptr src; + ImageMagick -------------- diff --git a/setup/installer/windows/wix-template.xml b/setup/installer/windows/wix-template.xml index 17976783aa..37dd8b25a8 100644 --- a/setup/installer/windows/wix-template.xml +++ b/setup/installer/windows/wix-template.xml @@ -153,18 +153,10 @@ - - - + - - - - - - diff --git a/src/calibre/utils/podofo/podofo.cpp b/src/calibre/utils/podofo/podofo.cpp index 8766b709c9..d88e71628d 100644 --- a/src/calibre/utils/podofo/podofo.cpp +++ b/src/calibre/utils/podofo/podofo.cpp @@ -164,7 +164,7 @@ podofo_convert_pystring(PyObject *py) { Py_UNICODE* u = PyUnicode_AS_UNICODE(py); PyObject *u8 = PyUnicode_EncodeUTF8(u, PyUnicode_GET_SIZE(py), "replace"); if (u8 == NULL) { PyErr_NoMemory(); return NULL; } - pdf_utf8 *s8 = (pdf_utf8 *)PyString_AS_STRING(u8); + pdf_utf8 *s8 = reinterpret_cast(PyString_AS_STRING(u8)); PdfString *ans = new PdfString(s8); Py_DECREF(u8); if (ans == NULL) PyErr_NoMemory(); @@ -219,9 +219,10 @@ podofo_PDFDoc_setter(podofo_PDFDoc *self, PyObject *val, int field) { PyErr_SetString(PyExc_Exception, "You must first load a PDF Document"); return -1; } - PdfString *s = podofo_convert_pystring(val); if (s == NULL) return -1; + + switch (field) { case 0: info->SetTitle(*s); break; @@ -240,7 +241,9 @@ podofo_PDFDoc_setter(podofo_PDFDoc *self, PyObject *val, int field) { return -1; } + self->doc->set_info(info); + return 0; } From 0f57a804c9b8d1eb1cacf012df6fc5545315a58d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 30 Jun 2010 08:58:40 -0600 Subject: [PATCH 7/7] Fix #6036 (Updated recipe for Akter and new recipe for news portal Alo! in serbian) --- resources/images/news/alo_novine.png | Bin 0 -> 753 bytes resources/recipes/akter.recipe | 6 +-- resources/recipes/alo_novine.recipe | 65 +++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 resources/images/news/alo_novine.png create mode 100644 resources/recipes/alo_novine.recipe diff --git a/resources/images/news/alo_novine.png b/resources/images/news/alo_novine.png new file mode 100644 index 0000000000000000000000000000000000000000..569ea16fce589fe91ccdea9d4802b5882e743a61 GIT binary patch literal 753 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b zK-vS0-A-oPfdtD69Mgd`SU*F|v9*U87?`9yT^vI!PM1#h_7_eRX`4Uur9p|8^pb~Z z(W|&aSVUA}{xR-%s&|aN%KA@QyoHt9DTP@vPDqtQ(LwrXYp3}f*3Po3RL#!=8G=Eq^~oj2`nP2h4~euj{k2XR`i6*V%qH!%d1$ll&$ z;j!E?wDOCM>ywi_497khrO%$dfia2oNLBp&6;f?G^uiq1tXQS-?rqhLlc!ZT@;!2r zt$Jf-?rI^q_+Cc9iMnqFudl!F`^ItnQATs~b)hePzL%I>78Wd3cVovbHw)RJkEHKxEe=Wfn%wd@J2;Tg4eT zc)tisc~&j3v-Vg1F0OL&Zo7gaXZsc2rC}dAx41MN*sxwTDMVY6;DY zE?7J5qPkk(8JUAKBb$DJrTL?#UrJqc~jp# ziDjsAdw=+v86)S9@9%6UsVL9#eRY3-qHOw#TV}^DaaTQi#%OUqZ9`w5fqT5=;(O)a zT&j2%wf=8C`2SeUp`9h}Z2y?IWZaaFdMf?_m}FE-Tq8