%PDF- %PDF-
Direktori : /usr/lib/calibre/calibre/devices/kobo/ |
Current File : //usr/lib/calibre/calibre/devices/kobo/books.py |
__license__ = 'GPL v3' __copyright__ = '2010-2012, , Timothy Legge <timlegge at gmail.com> and David Forrester <davidfor@internode.on.net>' __docformat__ = 'restructuredtext en' import os, time, sys from functools import cmp_to_key from calibre.constants import preferred_encoding, DEBUG from calibre import isbytestring from calibre.ebooks.metadata.book.base import Metadata from calibre.devices.usbms.books import Book as Book_, CollectionsBookList, none_cmp from calibre.utils.config_base import prefs from calibre.devices.usbms.driver import debug_print from calibre.ebooks.metadata import author_to_author_sort class Book(Book_): def __init__(self, prefix, lpath, title=None, authors=None, mime=None, date=None, ContentType=None, thumbnail_name=None, size=None, other=None): from calibre.utils.date import parse_date # debug_print('Book::__init__ - title=', title) show_debug = title is not None and title.lower().find("xxxxx") >= 0 if other is not None: other.title = title other.published_date = date if show_debug: debug_print("Book::__init__ - title=", title, 'authors=', authors) debug_print("Book::__init__ - other=", other) super().__init__(prefix, lpath, size, other) if title is not None and len(title) > 0: self.title = title if authors is not None and len(authors) > 0: self.authors_from_string(authors) if self.author_sort is None or self.author_sort == "Unknown": self.author_sort = author_to_author_sort(authors) self.mime = mime self.size = size # will be set later if None if ContentType == '6' and date is not None: try: self.datetime = time.strptime(date, "%Y-%m-%dT%H:%M:%S.%f") except: try: self.datetime = time.strptime(date.split('+')[0], "%Y-%m-%dT%H:%M:%S") except: try: self.datetime = time.strptime(date.split('+')[0], "%Y-%m-%d") except: try: self.datetime = parse_date(date, assume_utc=True).timetuple() except: try: self.datetime = time.gmtime(os.path.getctime(self.path)) except: self.datetime = time.gmtime() self.kobo_metadata = Metadata(title, self.authors) self.contentID = None self.current_shelves = [] self.kobo_collections = [] self.can_put_on_shelves = True self.kobo_series = None self.kobo_series_number = None # Kobo stores the series number as string. And it can have a leading "#". self.kobo_series_id = None self.kobo_subtitle = None if thumbnail_name is not None: self.thumbnail = ImageWrapper(thumbnail_name) if show_debug: debug_print("Book::__init__ end - self=", self) debug_print("Book::__init__ end - title=", title, 'authors=', authors) @property def is_sideloaded(self): # If we don't have a content Id, we don't know what type it is. return self.contentID and self.contentID.startswith("file") @property def has_kobo_series(self): return self.kobo_series is not None @property def is_purchased_kepub(self): return self.contentID and not self.contentID.startswith("file") def __str__(self): ''' A string representation of this object, suitable for printing to console ''' ans = ["Kobo metadata:"] def fmt(x, y): ans.append('%-20s: %s'%(str(x), str(y))) if self.contentID: fmt('Content ID', self.contentID) if self.kobo_series: fmt('Kobo Series', self.kobo_series + ' #%s'%self.kobo_series_number) if self.kobo_series_id: fmt('Kobo Series ID', self.kobo_series_id) if self.kobo_subtitle: fmt('Subtitle', self.kobo_subtitle) if self.mime: fmt('MimeType', self.mime) ans.append(str(self.kobo_metadata)) ans = '\n'.join(ans) return super().__str__() + "\n" + ans class ImageWrapper: def __init__(self, image_path): self.image_path = image_path class KTCollectionsBookList(CollectionsBookList): def __init__(self, oncard, prefix, settings): super().__init__(oncard, prefix, settings) self.set_device_managed_collections([]) def get_collections(self, collection_attributes): debug_print("KTCollectionsBookList:get_collections - start - collection_attributes=", collection_attributes) collections = {} ca = [] for c in collection_attributes: ca.append(c.lower()) collection_attributes = ca debug_print("KTCollectionsBookList:get_collections - collection_attributes=", collection_attributes) for book in self: tsval = book.get('title_sort', book.title) if tsval is None: tsval = book.title show_debug = self.is_debugging_title(tsval) or tsval is None if show_debug: # or len(book.device_collections) > 0: debug_print('KTCollectionsBookList:get_collections - tsval=', tsval, "book.title=", book.title, "book.title_sort=", book.title_sort) debug_print('KTCollectionsBookList:get_collections - book.device_collections=', book.device_collections) # debug_print(book) # Make sure we can identify this book via the lpath lpath = getattr(book, 'lpath', None) if lpath is None: continue # If the book is not in the current library, we don't want to use the metadtaa for the collections if book.application_id is None: # debug_print("KTCollectionsBookList:get_collections - Book not in current library") continue # Decide how we will build the collections. The default: leave the # book in all existing collections. Do not add any new ones. attrs = ['device_collections'] if getattr(book, '_new_book', False): if prefs['manage_device_metadata'] == 'manual': # Ensure that the book is in all the book's existing # collections plus all metadata collections attrs += collection_attributes else: # For new books, both 'on_send' and 'on_connect' do the same # thing. The book's existing collections are ignored. Put # the book in collections defined by its metadata. attrs = collection_attributes elif prefs['manage_device_metadata'] == 'on_connect': # For existing books, modify the collections only if the user # specified 'on_connect' attrs = collection_attributes for cat_name in self.device_managed_collections: if cat_name in book.device_collections: if cat_name not in collections: collections[cat_name] = {} if show_debug: debug_print("KTCollectionsBookList:get_collections - Device Managed Collection:", cat_name) if lpath not in collections[cat_name]: collections[cat_name][lpath] = (book, tsval, tsval) if show_debug: debug_print("KTCollectionsBookList:get_collections - Device Managed Collection -added book to cat_name", cat_name) book.device_collections = [] if show_debug: debug_print("KTCollectionsBookList:get_collections - attrs=", attrs) for attr in attrs: attr = attr.strip() if show_debug: debug_print("KTCollectionsBookList:get_collections - attr='%s'"%attr) # If attr is device_collections, then we cannot use # format_field, because we don't know the fields where the # values came from. if attr == 'device_collections': doing_dc = True val = book.device_collections # is a list if show_debug: debug_print("KTCollectionsBookList:get_collections - adding book.device_collections", book.device_collections) # If the book is not in the current library, we don't want to use the metadtaa for the collections elif book.application_id is None or not book.can_put_on_shelves: # debug_print("KTCollectionsBookList:get_collections - Book not in current library") continue else: doing_dc = False ign, val, orig_val, fm = book.format_field_extended(attr) val = book.get(attr, None) if show_debug: debug_print("KTCollectionsBookList:get_collections - not device_collections") debug_print(' ign=', ign, ', val=', val, ' orig_val=', orig_val, 'fm=', fm) debug_print(' val=', val) if not val: continue if isbytestring(val): val = val.decode(preferred_encoding, 'replace') if isinstance(val, (list, tuple)): val = list(val) # debug_print("KTCollectionsBookList:get_collections - val is list=", val) elif fm is not None and fm['datatype'] == 'series': val = [orig_val] elif fm is not None and fm['datatype'] == 'rating': val = [str(orig_val / 2.0)] elif fm is not None and fm['datatype'] == 'text' and fm['is_multiple']: if isinstance(orig_val, (list, tuple)): val = orig_val else: val = [orig_val] if show_debug: debug_print("KTCollectionsBookList:get_collections - val is text and multiple", val) elif fm is not None and fm['datatype'] == 'composite' and fm['is_multiple']: if show_debug: debug_print("KTCollectionsBookList:get_collections - val is compositeand multiple", val) val = [v.strip() for v in val.split(fm['is_multiple']['ui_to_list'])] else: val = [val] if show_debug: debug_print("KTCollectionsBookList:get_collections - val=", val) for category in val: # debug_print("KTCollectionsBookList:get_collections - category=", category) is_series = False if doing_dc: # Attempt to determine if this value is a series by # comparing it to the series name. if category == book.series: is_series = True elif fm is not None and fm['is_custom']: # is a custom field if fm['datatype'] == 'text' and len(category) > 1 and \ category[0] == '[' and category[-1] == ']': continue if fm['datatype'] == 'series': is_series = True else: # is a standard field if attr == 'tags' and len(category) > 1 and \ category[0] == '[' and category[-1] == ']': continue if attr == 'series' or \ ('series' in collection_attributes and book.get('series', None) == category): is_series = True # The category should not be None, but, it has happened. if not category: continue cat_name = str(category).strip(' ,') if cat_name not in collections: collections[cat_name] = {} if show_debug: debug_print("KTCollectionsBookList:get_collections - created collection for cat_name", cat_name) if lpath not in collections[cat_name]: if is_series: if doing_dc: collections[cat_name][lpath] = \ (book, book.get('series_index', sys.maxsize), tsval) else: collections[cat_name][lpath] = \ (book, book.get(attr+'_index', sys.maxsize), tsval) else: collections[cat_name][lpath] = (book, tsval, tsval) if show_debug: debug_print("KTCollectionsBookList:get_collections - added book to collection for cat_name", cat_name) if show_debug: debug_print("KTCollectionsBookList:get_collections - cat_name", cat_name) # Sort collections result = {} for category, lpaths in collections.items(): books = sorted(lpaths.values(), key=cmp_to_key(none_cmp)) result[category] = [x[0] for x in books] # debug_print("KTCollectionsBookList:get_collections - result=", result.keys()) debug_print("KTCollectionsBookList:get_collections - end") return result def set_device_managed_collections(self, collection_names): self.device_managed_collections = collection_names def set_debugging_title(self, title): self.debugging_title = title def is_debugging_title(self, title): if not DEBUG: return False # debug_print("KTCollectionsBookList:is_debugging - title=", title, "self.debugging_title=", self.debugging_title) is_debugging = self.debugging_title is not None and len(self.debugging_title) > 0 and title is not None and ( title.lower().find(self.debugging_title.lower()) >= 0 or len(title) == 0) # debug_print("KTCollectionsBookList:is_debugging - is_debugging=", is_debugging) return is_debugging