mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Improved iTunes orphan detection/handling when book is deleted on device while disconnected from calibre
This commit is contained in:
commit
10b0d7647b
@ -76,7 +76,7 @@ class ITUNES(DevicePlugin):
|
|||||||
supported_platforms = ['osx','windows']
|
supported_platforms = ['osx','windows']
|
||||||
author = 'GRiker'
|
author = 'GRiker'
|
||||||
#: The version of this plugin as a 3-tuple (major, minor, revision)
|
#: The version of this plugin as a 3-tuple (major, minor, revision)
|
||||||
version = (0, 5, 0)
|
version = (0,6,0)
|
||||||
|
|
||||||
OPEN_FEEDBACK_MESSAGE = _(
|
OPEN_FEEDBACK_MESSAGE = _(
|
||||||
'Apple device detected, launching iTunes, please wait ...')
|
'Apple device detected, launching iTunes, please wait ...')
|
||||||
@ -280,7 +280,7 @@ class ITUNES(DevicePlugin):
|
|||||||
|
|
||||||
if self.report_progress is not None:
|
if self.report_progress is not None:
|
||||||
self.report_progress(i+1/book_count, _('%d of %d') % (i+1, book_count))
|
self.report_progress(i+1/book_count, _('%d of %d') % (i+1, book_count))
|
||||||
self._purge_orphans(cached_books)
|
self._purge_orphans(library_books, cached_books)
|
||||||
|
|
||||||
elif iswindows:
|
elif iswindows:
|
||||||
try:
|
try:
|
||||||
@ -316,7 +316,7 @@ class ITUNES(DevicePlugin):
|
|||||||
if self.report_progress is not None:
|
if self.report_progress is not None:
|
||||||
self.report_progress(i+1/book_count,
|
self.report_progress(i+1/book_count,
|
||||||
_('%d of %d') % (i+1, book_count))
|
_('%d of %d') % (i+1, book_count))
|
||||||
self._purge_orphans(cached_books)
|
self._purge_orphans(library_books, cached_books)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
pythoncom.CoUninitialize()
|
pythoncom.CoUninitialize()
|
||||||
@ -324,9 +324,9 @@ class ITUNES(DevicePlugin):
|
|||||||
if self.report_progress is not None:
|
if self.report_progress is not None:
|
||||||
self.report_progress(1.0, _('finished'))
|
self.report_progress(1.0, _('finished'))
|
||||||
self.cached_books = cached_books
|
self.cached_books = cached_books
|
||||||
if DEBUG:
|
# if DEBUG:
|
||||||
self._dump_booklist(booklist, 'returning from books():')
|
# self._dump_booklist(booklist, 'returning from books():')
|
||||||
self._dump_cached_books('returning from books():')
|
# self._dump_cached_books('returning from books():')
|
||||||
return booklist
|
return booklist
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
@ -463,7 +463,7 @@ class ITUNES(DevicePlugin):
|
|||||||
else:
|
else:
|
||||||
# iTunes running, but not connected iPad
|
# iTunes running, but not connected iPad
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info(' self.ejected = True')
|
self.log.info(' iDevice has been ejected')
|
||||||
self.ejected = True
|
self.ejected = True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -782,121 +782,6 @@ class ITUNES(DevicePlugin):
|
|||||||
# self._dump_cached_books('upload_books()')
|
# self._dump_cached_books('upload_books()')
|
||||||
self._dump_update_list('upload_books()')
|
self._dump_update_list('upload_books()')
|
||||||
|
|
||||||
'''
|
|
||||||
if isosx:
|
|
||||||
|
|
||||||
for (i,file) in enumerate(files):
|
|
||||||
path = self.path_template % (metadata[i].title, metadata[i].author[0])
|
|
||||||
|
|
||||||
if self.manual_sync_mode:
|
|
||||||
# Delete existing from Device|Books, add to self.update_list
|
|
||||||
# for deletion from booklist[0] during add_books_to_metadata
|
|
||||||
if path in self.cached_books:
|
|
||||||
self.update_list.append(self.cached_books[path])
|
|
||||||
if DEBUG:
|
|
||||||
self.log.info(" adding '%s' by %s to self.update_list" %
|
|
||||||
(self.cached_books[path]['title'],self.cached_books[path]['author']))
|
|
||||||
|
|
||||||
if DEBUG:
|
|
||||||
self.log.info( " deleting existing '%s'" % (path))
|
|
||||||
self._remove_from_iTunes(self.cached_books[path])
|
|
||||||
if self.manual_sync_mode:
|
|
||||||
dev_book_added = self._remove_from_device(self.cached_books[path])
|
|
||||||
|
|
||||||
|
|
||||||
# Add to iTunes Library|Books
|
|
||||||
fpath = file
|
|
||||||
if getattr(file, 'orig_file_path', None) is not None:
|
|
||||||
fpath = file.orig_file_path
|
|
||||||
elif getattr(file, 'name', None) is not None:
|
|
||||||
fpath = file.name
|
|
||||||
|
|
||||||
if isinstance(file,PersistentTemporaryFile) and self.manual_sync_mode:
|
|
||||||
if DEBUG:
|
|
||||||
self.log.info(" PTF not added to Library|Books")
|
|
||||||
else:
|
|
||||||
added = self.iTunes.add(appscript.mactypes.File(fpath))
|
|
||||||
if DEBUG:
|
|
||||||
self.log.info(" file added to Library|Books")
|
|
||||||
|
|
||||||
dev_book_added = None
|
|
||||||
if self.manual_sync_mode:
|
|
||||||
dev_book_added = self._add_device_book(fpath)
|
|
||||||
|
|
||||||
thumb = None
|
|
||||||
if metadata[i].cover:
|
|
||||||
try:
|
|
||||||
# Use cover data as artwork
|
|
||||||
cover_data = open(metadata[i].cover,'rb')
|
|
||||||
added.artworks[1].data_.set(cover_data.read())
|
|
||||||
|
|
||||||
# Resize for thumb
|
|
||||||
width = metadata[i].thumbnail[0]
|
|
||||||
height = metadata[i].thumbnail[1]
|
|
||||||
im = PILImage.open(metadata[i].cover)
|
|
||||||
im = im.resize((width, height), PILImage.ANTIALIAS)
|
|
||||||
of = cStringIO.StringIO()
|
|
||||||
im.convert('RGB').save(of, 'JPEG')
|
|
||||||
thumb = of.getvalue()
|
|
||||||
|
|
||||||
# Refresh the thumbnail cache
|
|
||||||
if DEBUG:
|
|
||||||
self.log.info( " refreshing cached thumb for '%s'" % metadata[i].title)
|
|
||||||
archive_path = os.path.join(self.cache_dir, "thumbs.zip")
|
|
||||||
zfw = zipfile.ZipFile(archive_path, mode='a')
|
|
||||||
thumb_path = path.rpartition('.')[0] + '.jpg'
|
|
||||||
zfw.writestr(thumb_path, thumb)
|
|
||||||
zfw.close()
|
|
||||||
except:
|
|
||||||
self.problem_titles.append("'%s' by %s" % (metadata[i].title, metadata[i].author[0]))
|
|
||||||
self.log.error("ITUNES.upload_books(): error converting '%s' to thumb for '%s'" % (metadata[i].cover,metadata[i].title))
|
|
||||||
|
|
||||||
# Create a new Book
|
|
||||||
this_book = Book(metadata[i].title, metadata[i].author[0])
|
|
||||||
try:
|
|
||||||
this_book.datetime = parse_date(str(added.date_added())).timetuple()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
this_book.db_id = None
|
|
||||||
this_book.device_collections = []
|
|
||||||
this_book.library_id = added
|
|
||||||
this_book.path = path
|
|
||||||
this_book.size = self._get_device_book_size(fpath, added.size())
|
|
||||||
this_book.thumbnail = thumb
|
|
||||||
this_book.iTunes_id = added
|
|
||||||
|
|
||||||
new_booklist.append(this_book)
|
|
||||||
|
|
||||||
# Populate the iTunes metadata
|
|
||||||
if metadata[i].comments:
|
|
||||||
added.comment.set(strip_tags.sub('',metadata[i].comments))
|
|
||||||
added.description.set("added by calibre %s" % strftime('%Y-%m-%d %H:%M:%S'))
|
|
||||||
added.enabled.set(True)
|
|
||||||
if metadata[i].rating:
|
|
||||||
added.rating.set(metadata[i].rating*10)
|
|
||||||
added.sort_artist.set(metadata[i].author_sort.title())
|
|
||||||
added.sort_name.set(this_book.title_sorter)
|
|
||||||
|
|
||||||
# Set genre from metadata
|
|
||||||
# iTunes grabs the first dc:subject from the opf metadata,
|
|
||||||
# But we can manually override with first tag starting with alpha
|
|
||||||
for tag in metadata[i].tags:
|
|
||||||
if self._is_alpha(tag[0]):
|
|
||||||
added.genre.set(tag)
|
|
||||||
break
|
|
||||||
|
|
||||||
# Add new_book to self.cached_paths
|
|
||||||
self.cached_books[this_book.path] = {
|
|
||||||
'title': this_book.title,
|
|
||||||
'author': this_book.author,
|
|
||||||
'lib_book': added,
|
|
||||||
'dev_book': dev_book_added
|
|
||||||
}
|
|
||||||
|
|
||||||
# Report progress
|
|
||||||
if self.report_progress is not None:
|
|
||||||
self.report_progress(i+1/file_count, _('%d of %d') % (i+1, file_count))
|
|
||||||
'''
|
|
||||||
if isosx:
|
if isosx:
|
||||||
for (i,file) in enumerate(files):
|
for (i,file) in enumerate(files):
|
||||||
path = self.path_template % (metadata[i].title, metadata[i].author[0])
|
path = self.path_template % (metadata[i].title, metadata[i].author[0])
|
||||||
@ -1378,6 +1263,15 @@ class ITUNES(DevicePlugin):
|
|||||||
self.log.info(" %s" % file.name)
|
self.log.info(" %s" % file.name)
|
||||||
self.log.info()
|
self.log.info()
|
||||||
|
|
||||||
|
def _dump_library_books(self, library_books):
|
||||||
|
'''
|
||||||
|
'''
|
||||||
|
if DEBUG:
|
||||||
|
self.log.info("\n library_books:")
|
||||||
|
for book in library_books:
|
||||||
|
self.log.info(" %s" % book)
|
||||||
|
self.log.info()
|
||||||
|
|
||||||
def _dump_update_list(self,header=None):
|
def _dump_update_list(self,header=None):
|
||||||
if header:
|
if header:
|
||||||
msg = '\nself.update_list called from %s' % header
|
msg = '\nself.update_list called from %s' % header
|
||||||
@ -1590,7 +1484,7 @@ class ITUNES(DevicePlugin):
|
|||||||
self.log.info(" ignoring '%s' of type '%s'" % (book.name(), book.kind()))
|
self.log.info(" ignoring '%s' of type '%s'" % (book.name(), book.kind()))
|
||||||
else:
|
else:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info(" adding %-30.30s [%s]" % (book.name(), book.kind()))
|
self.log.info(" adding %-30.30s %-30.30s [%s]" % (book.name(), book.artist(), book.kind()))
|
||||||
device_books.append(book)
|
device_books.append(book)
|
||||||
|
|
||||||
elif iswindows:
|
elif iswindows:
|
||||||
@ -1619,7 +1513,7 @@ class ITUNES(DevicePlugin):
|
|||||||
self.log.info(" ignoring '%s' of type '%s'" % (book.Name, book.KindAsString))
|
self.log.info(" ignoring '%s' of type '%s'" % (book.Name, book.KindAsString))
|
||||||
else:
|
else:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info(" adding %-30.30s [%s]" % (book.Name, book.KindAsString))
|
self.log.info(" adding %-30.30s %-30.30s [%s]" % (book.Name, book.Artist, book.KindAsString))
|
||||||
device_books.append(book)
|
device_books.append(book)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
@ -1716,11 +1610,11 @@ class ITUNES(DevicePlugin):
|
|||||||
if book.location() == appscript.k.missing_value:
|
if book.location() == appscript.k.missing_value:
|
||||||
library_orphans[path] = book
|
library_orphans[path] = book
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info(" found calibre orphan '%s' in Library|Books" % book.name())
|
self.log.info(" found iTunes PTF '%s' in Library|Books" % book.name())
|
||||||
|
|
||||||
library_books[path] = book
|
library_books[path] = book
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info(" adding %-30.30s [%s]" % (book.name(), book.kind()))
|
self.log.info(" adding %-30.30s %-30.30s [%s]" % (book.name(), book.artist(), book.kind()))
|
||||||
else:
|
else:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info(' no Library playlists')
|
self.log.info(' no Library playlists')
|
||||||
@ -1730,9 +1624,6 @@ class ITUNES(DevicePlugin):
|
|||||||
|
|
||||||
elif iswindows:
|
elif iswindows:
|
||||||
lib = None
|
lib = None
|
||||||
# try:
|
|
||||||
# pythoncom.CoInitialize()
|
|
||||||
# self.iTunes = win32com.client.Dispatch("iTunes.Application")
|
|
||||||
for source in self.iTunes.sources:
|
for source in self.iTunes.sources:
|
||||||
if source.Kind == self.Sources.index('Library'):
|
if source.Kind == self.Sources.index('Library'):
|
||||||
lib = source
|
lib = source
|
||||||
@ -1772,16 +1663,14 @@ class ITUNES(DevicePlugin):
|
|||||||
if not book.Location:
|
if not book.Location:
|
||||||
library_orphans[path] = book
|
library_orphans[path] = book
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info(" found calibre orphan '%s' in Library|Books" % book.Name)
|
self.log.info(" found iTunes PTF '%s' in Library|Books" % book.Name)
|
||||||
|
|
||||||
library_books[path] = book
|
library_books[path] = book
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info(" adding %-30.30s [%s]" % (book.Name, book.KindAsString))
|
self.log.info(" adding %-30.30s %-30.30s [%s]" % (book.Name, book.Artist, book.KindAsString))
|
||||||
except:
|
except:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info(" no books in library")
|
self.log.info(" no books in library")
|
||||||
# finally:
|
|
||||||
# pythoncom.CoUninitialize()
|
|
||||||
self.library_orphans = library_orphans
|
self.library_orphans = library_orphans
|
||||||
return library_books
|
return library_books
|
||||||
|
|
||||||
@ -1905,44 +1794,36 @@ class ITUNES(DevicePlugin):
|
|||||||
self.version[0],self.version[1],self.version[2]))
|
self.version[0],self.version[1],self.version[2]))
|
||||||
self.log.info(" iTunes_media: %s" % self.iTunes_media)
|
self.log.info(" iTunes_media: %s" % self.iTunes_media)
|
||||||
|
|
||||||
def _purge_orphans(self,cached_books):
|
def _purge_orphans(self,library_books, cached_books):
|
||||||
'''
|
'''
|
||||||
Scan self.library_orphans for any paths not on device
|
Scan library_books for any paths not on device
|
||||||
Remove any true orphans from iTunes
|
Remove any iTunes orphans originally added by calibre
|
||||||
This occurs when recipes are uploaded in a previous session
|
This occurs when the user deletes a book in iBooks while disconnected
|
||||||
and the book has since been deleted on the device
|
|
||||||
'''
|
'''
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info(" ITUNES._purge_orphans")
|
self.log.info("\n ITUNES._purge_orphans")
|
||||||
|
#self._dump_library_books(library_books)
|
||||||
#self.log.info(" cached_books:\n %s" % "\n ".join(cached_books.keys()))
|
#self.log.info(" cached_books:\n %s" % "\n ".join(cached_books.keys()))
|
||||||
|
|
||||||
orphan_paths = {}
|
for book in library_books:
|
||||||
|
|
||||||
if isosx:
|
if isosx:
|
||||||
for orphan in self.library_orphans:
|
if book not in cached_books and \
|
||||||
path = self.path_template % (self.library_orphans[orphan].name(),
|
str(library_books[book].description()).startswith(self.description_prefix):
|
||||||
self.library_orphans[orphan].artist())
|
|
||||||
orphan_paths[path] = self.library_orphans[orphan]
|
|
||||||
|
|
||||||
# Scan orphan_paths for paths not found in cached_books
|
|
||||||
for orphan in orphan_paths.keys():
|
|
||||||
if orphan not in cached_books:
|
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info(" '%s' not found on device, removing from iTunes" % orphan)
|
self.log.info(" '%s' not found on iDevice, removing from iTunes" % book)
|
||||||
self.iTunes.delete(orphan_paths[orphan])
|
btr = { 'title':library_books[book].name(),
|
||||||
|
'author':library_books[book].artist(),
|
||||||
|
'lib_book':library_books[book]}
|
||||||
|
self._remove_from_iTunes(btr)
|
||||||
elif iswindows:
|
elif iswindows:
|
||||||
for orphan in self.library_orphans:
|
if book not in cached_books and \
|
||||||
path = self.path_template % (self.library_orphans[orphan].Name,
|
library_books[book].Description.startswith(self.description_prefix):
|
||||||
self.library_orphans[orphan].Artist)
|
|
||||||
orphan_paths[path] = self.library_orphans[orphan]
|
|
||||||
|
|
||||||
# Scan orphan_paths for paths not found in cached_books
|
|
||||||
for orphan in orphan_paths.keys():
|
|
||||||
if orphan not in cached_books:
|
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info(" '%s' not found on device, removing from iTunes" % orphan)
|
self.log.info(" '%s' not found on iDevice, removing from iTunes" % book)
|
||||||
orphan_paths[orphan].Delete()
|
btr = { 'title':library_books[book].Name,
|
||||||
|
'author':library_books[book].Artist,
|
||||||
|
'lib_book':library_books[book]}
|
||||||
|
self._remove_from_iTunes(btr)
|
||||||
|
|
||||||
def _remove_existing_copies(self,path,file,metadata):
|
def _remove_existing_copies(self,path,file,metadata):
|
||||||
'''
|
'''
|
||||||
@ -2049,10 +1930,13 @@ class ITUNES(DevicePlugin):
|
|||||||
Assume we're wrapped in a pythoncom
|
Assume we're wrapped in a pythoncom
|
||||||
Windows stores the book under a common author directory, so we just delete the .epub
|
Windows stores the book under a common author directory, so we just delete the .epub
|
||||||
'''
|
'''
|
||||||
|
try:
|
||||||
book = self._find_library_book(cached_book)
|
book = cached_book['lib_book']
|
||||||
if book:
|
|
||||||
path = book.Location
|
path = book.Location
|
||||||
|
except:
|
||||||
|
book = self._find_library_book(cached_book)
|
||||||
|
path = book.Location
|
||||||
|
|
||||||
storage_path = os.path.split(book.Location)
|
storage_path = os.path.split(book.Location)
|
||||||
if book.Location.startswith(self.iTunes_media):
|
if book.Location.startswith(self.iTunes_media):
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
@ -2074,9 +1958,6 @@ class ITUNES(DevicePlugin):
|
|||||||
|
|
||||||
book.Delete()
|
book.Delete()
|
||||||
|
|
||||||
else:
|
|
||||||
self.log.warning(" could not find '%s' in iTunes database" % cached_book['title'])
|
|
||||||
|
|
||||||
def _update_device(self, msg='', wait=True):
|
def _update_device(self, msg='', wait=True):
|
||||||
'''
|
'''
|
||||||
Trigger a sync, wait for completion
|
Trigger a sync, wait for completion
|
||||||
|
@ -801,11 +801,6 @@ class BasicNewsRecipe(Recipe):
|
|||||||
.calibre_navbar {
|
.calibre_navbar {
|
||||||
font-family:monospace;
|
font-family:monospace;
|
||||||
}
|
}
|
||||||
hr {
|
|
||||||
border-color:gray;
|
|
||||||
border-style:solid;
|
|
||||||
border-width:thin;
|
|
||||||
}
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ class TouchscreenNavBarTemplate(Template):
|
|||||||
navbar = DIV(CLASS('calibre_navbar', 'calibre_rescale_100',
|
navbar = DIV(CLASS('calibre_navbar', 'calibre_rescale_100',
|
||||||
style='text-align:'+align))
|
style='text-align:'+align))
|
||||||
if bottom:
|
if bottom:
|
||||||
navbar.append(HR())
|
navbar.append(DIV(style="border-top:1px solid gray;border-bottom:1em solid white"))
|
||||||
text = 'This article was downloaded by '
|
text = 'This article was downloaded by '
|
||||||
p = PT(text, STRONG(__appname__), A(url, href=url), style='text-align:left')
|
p = PT(text, STRONG(__appname__), A(url, href=url), style='text-align:left')
|
||||||
p[0].tail = ' from '
|
p[0].tail = ' from '
|
||||||
@ -136,7 +136,7 @@ class TouchscreenNavBarTemplate(Template):
|
|||||||
|
|
||||||
navbar.iterchildren(reversed=True).next().tail = ' | '
|
navbar.iterchildren(reversed=True).next().tail = ' | '
|
||||||
if not bottom:
|
if not bottom:
|
||||||
navbar.append(HR())
|
navbar.append(DIV(style="border-top:1px solid gray;border-bottom:1em solid white"))
|
||||||
|
|
||||||
self.root = HTML(head, BODY(navbar))
|
self.root = HTML(head, BODY(navbar))
|
||||||
|
|
||||||
@ -193,6 +193,8 @@ class TouchscreenIndexTemplate(Template):
|
|||||||
div = DIV(
|
div = DIV(
|
||||||
masthead_p,
|
masthead_p,
|
||||||
PT(date, style='text-align:center'),
|
PT(date, style='text-align:center'),
|
||||||
|
#DIV(style="border-color:gray;border-top-style:solid;border-width:thin"),
|
||||||
|
DIV(style="border-top:1px solid gray;border-bottom:1em solid white"),
|
||||||
toc)
|
toc)
|
||||||
self.root = HTML(head, BODY(div))
|
self.root = HTML(head, BODY(div))
|
||||||
|
|
||||||
@ -256,9 +258,8 @@ class TouchscreenFeedTemplate(Template):
|
|||||||
head.append(STYLE(extra_css, type='text/css'))
|
head.append(STYLE(extra_css, type='text/css'))
|
||||||
body = BODY(style='page-break-before:always')
|
body = BODY(style='page-break-before:always')
|
||||||
div = DIV(
|
div = DIV(
|
||||||
H2(feed.title,
|
H2(feed.title, CLASS('calibre_feed_title', 'calibre_rescale_160')),
|
||||||
CLASS('calibre_feed_title', 'calibre_rescale_160')),
|
DIV(style="border-top:1px solid gray;border-bottom:1em solid white")
|
||||||
CLASS('calibre_rescale_100')
|
|
||||||
)
|
)
|
||||||
body.append(div)
|
body.append(div)
|
||||||
if getattr(feed, 'image', None):
|
if getattr(feed, 'image', None):
|
||||||
@ -278,6 +279,20 @@ class TouchscreenFeedTemplate(Template):
|
|||||||
if not getattr(article, 'downloaded', False):
|
if not getattr(article, 'downloaded', False):
|
||||||
continue
|
continue
|
||||||
tr = TR()
|
tr = TR()
|
||||||
|
|
||||||
|
if True:
|
||||||
|
div_td = DIV(
|
||||||
|
A(article.title, CLASS('summary_headline','calibre_rescale_120',
|
||||||
|
href=article.url)),
|
||||||
|
style="display:inline-block")
|
||||||
|
if article.author:
|
||||||
|
div_td.append(DIV(article.author,
|
||||||
|
CLASS('summary_byline', 'calibre_rescale_100')))
|
||||||
|
if article.summary:
|
||||||
|
div_td.append(DIV(cutoff(article.text_summary),
|
||||||
|
CLASS('summary_text', 'calibre_rescale_100')))
|
||||||
|
tr.append(TD(div_td))
|
||||||
|
else:
|
||||||
td = TD(
|
td = TD(
|
||||||
A(article.title, CLASS('summary_headline','calibre_rescale_120',
|
A(article.title, CLASS('summary_headline','calibre_rescale_120',
|
||||||
href=article.url))
|
href=article.url))
|
||||||
@ -288,7 +303,9 @@ class TouchscreenFeedTemplate(Template):
|
|||||||
if article.summary:
|
if article.summary:
|
||||||
td.append(DIV(cutoff(article.text_summary),
|
td.append(DIV(cutoff(article.text_summary),
|
||||||
CLASS('summary_text', 'calibre_rescale_100')))
|
CLASS('summary_text', 'calibre_rescale_100')))
|
||||||
|
|
||||||
tr.append(td)
|
tr.append(td)
|
||||||
|
|
||||||
toc.append(tr)
|
toc.append(tr)
|
||||||
div.append(toc)
|
div.append(toc)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user