Ejemplo n.º 1
0
 def delete_single_book(self, path):
     try:
         tp = self.thumbpath_from_filepath(path)
         if tp:
             try:
                 os.remove(tp)
             except EnvironmentError as err:
                 if err.errno != errno.ENOENT:
                     prints(u'Failed to delete thumbnail for {!r} at {!r} with error: {}'.format(path, tp, err))
     except Exception:
         import traceback
         traceback.print_exc()
     USBMS.delete_single_book(self, path)
Ejemplo n.º 2
0
 def delete_single_book(self, path):
     try:
         tp = self.thumbpath_from_filepath(path)
         if tp:
             try:
                 os.remove(tp)
             except EnvironmentError as err:
                 if err.errno != errno.ENOENT:
                     prints(u'Failed to delete thumbnail for {!r} at {!r} with error: {}'.format(path, tp, err))
     except Exception:
         import traceback
         traceback.print_exc()
     USBMS.delete_single_book(self, path)
Ejemplo n.º 3
0
 def books(self, oncard=None, end_session=True):
     debug_print('PRS505: starting fetching books for card', oncard)
     bl = USBMS.books(self, oncard=oncard, end_session=end_session)
     c = self.initialize_XML_cache()
     c.update_booklist(bl, {'carda':1, 'cardb':2}.get(oncard, 0))
     debug_print('PRS505: finished fetching books for card', oncard)
     return bl
Ejemplo n.º 4
0
 def books(self, oncard=None, end_session=True):
     debug_print('PRS505: starting fetching books for card', oncard)
     bl = USBMS.books(self, oncard=oncard, end_session=end_session)
     c = self.initialize_XML_cache()
     c.update_booklist(bl, {'carda': 1, 'cardb': 2}.get(oncard, 0))
     debug_print('PRS505: finished fetching books for card', oncard)
     return bl
Ejemplo n.º 5
0
    def sync_booklists(self, booklists, end_session=True):
        debug_print('PRS505: started sync_booklists')
        c = self.initialize_XML_cache()
        blists = {}
        for i in c.paths:
            try:
                if booklists[i] is not None:
                    blists[i] = booklists[i]
            except IndexError:
                pass
        opts = self.settings()
        if opts.extra_customization:
            collections = [
                x.strip() for x in opts.extra_customization[
                    self.OPT_COLLECTIONS].split(',')
            ]
        else:
            collections = []
        debug_print('PRS505: collection fields:', collections)
        pb = None
        if self.plugboard_func:
            pb = self.plugboard_func(self.__class__.__name__, 'device_db',
                                     self.plugboards)
        debug_print('PRS505: use plugboards', pb)
        c.update(blists, collections, pb)
        c.write()

        if opts.extra_customization[self.OPT_REFRESH_COVERS]:
            debug_print('PRS505: uploading covers in sync_booklists')
            for idx, bl in blists.items():
                prefix = self._card_a_prefix if idx == 1 else \
                                self._card_b_prefix if idx == 2 \
                                    else self._main_prefix
                for book in bl:
                    try:
                        p = os.path.join(prefix, book.lpath)
                        self._upload_cover(
                            os.path.dirname(p),
                            os.path.splitext(os.path.basename(p))[0], book, p)
                    except:
                        debug_print('FAILED to upload cover', prefix,
                                    book.lpath)
        else:
            debug_print('PRS505: NOT uploading covers in sync_booklists')

        USBMS.sync_booklists(self, booklists, end_session=end_session)
        debug_print('PRS505: finished sync_booklists')
Ejemplo n.º 6
0
    def sync_booklists(self, booklists, end_session=True):
        debug_print("PRST1: starting sync_booklists")

        opts = self.settings()
        if opts.extra_customization:
            collections = [x.strip() for x in opts.extra_customization[self.OPT_COLLECTIONS].split(",")]
        else:
            collections = []
        debug_print("PRST1: collection fields:", collections)

        if booklists[0] is not None:
            self.update_device_database(booklists[0], collections, None)
        if len(booklists) > 1 and booklists[1] is not None:
            self.update_device_database(booklists[1], collections, "carda")

        USBMS.sync_booklists(self, booklists, end_session=end_session)
        debug_print("PRST1: finished sync_booklists")
Ejemplo n.º 7
0
    def sync_booklists(self, booklists, end_session=True):
        debug_print('PRS505: started sync_booklists')
        c = self.initialize_XML_cache()
        blists = {}
        for i in c.paths:
            try:
                if booklists[i] is not None:
                    blists[i] = booklists[i]
            except IndexError:
                pass
        opts = self.settings()
        if opts.extra_customization:
            collections = [x.strip() for x in
                    opts.extra_customization[self.OPT_COLLECTIONS].split(',')]
        else:
            collections = []
        debug_print('PRS505: collection fields:', collections)
        pb = None
        if self.plugboard_func:
            pb = self.plugboard_func(self.__class__.__name__,
                                     'device_db', self.plugboards)
        debug_print('PRS505: use plugboards', pb)
        c.update(blists, collections, pb)
        c.write()

        if opts.extra_customization[self.OPT_REFRESH_COVERS]:
            debug_print('PRS505: uploading covers in sync_booklists')
            for idx,bl in blists.items():
                prefix = self._card_a_prefix if idx == 1 else \
                                self._card_b_prefix if idx == 2 \
                                    else self._main_prefix
                for book in bl:
                    try:
                        p = os.path.join(prefix, book.lpath)
                        self._upload_cover(os.path.dirname(p),
                                          os.path.splitext(os.path.basename(p))[0],
                                          book, p)
                    except:
                        debug_print('FAILED to upload cover',
                                prefix, book.lpath)
        else:
            debug_print('PRS505: NOT uploading covers in sync_booklists')

        USBMS.sync_booklists(self, booklists, end_session=end_session)
        debug_print('PRS505: finished sync_booklists')
Ejemplo n.º 8
0
    def sync_booklists(self, booklists, end_session=True):
        debug_print('PRST1: starting sync_booklists')

        opts = self.settings()
        if opts.extra_customization:
            collections = [x.strip() for x in
                    opts.extra_customization[self.OPT_COLLECTIONS].split(',')]
        else:
            collections = []
        debug_print('PRST1: collection fields:', collections)

        if booklists[0] is not None:
            self.update_device_database(booklists[0], collections, None)
        if len(booklists) > 1 and booklists[1] is not None:
            self.update_device_database(booklists[1], collections, 'carda')

        USBMS.sync_booklists(self, booklists, end_session=end_session)
        debug_print('PRST1: finished sync_booklists')
Ejemplo n.º 9
0
 def create_upload_path(self, path, mdata, fname, create_dirs=True):
     is_news = mdata.tags and _('News') in mdata.tags
     subdir = 'Magazines' if is_news else 'Books'
     path = os.path.join(path, subdir)
     return USBMS.create_upload_path(self,
                                     path,
                                     mdata,
                                     fname,
                                     create_dirs=create_dirs)
Ejemplo n.º 10
0
 def delete_single_book(self, path):
     try:
         tp1 = self.thumbpath_from_filepath(path)
         if tp1:
             tp2 = os.path.join(self.amazon_cover_bug_cache_dir(),
                                os.path.basename(tp1))
             for tp in (tp1, tp2):
                 try:
                     os.remove(tp)
                 except EnvironmentError as err:
                     if err.errno != errno.ENOENT:
                         prints(
                             'Failed to delete thumbnail for {!r} at {!r} with error: {}'
                             .format(path, tp, err))
     except Exception:
         import traceback
         traceback.print_exc()
     USBMS.delete_single_book(self, path)
Ejemplo n.º 11
0
 def __init__(self, path):
     if not os.path.isdir(path):
         raise OSError('Path is not a folder')
     path = USBMS.normalize_path(path)
     if path.endswith(os.sep):
         self._main_prefix = path
     else:
         self._main_prefix = path + os.sep
     self.booklist_class = BookList
     self.is_connected = True
Ejemplo n.º 12
0
 def __init__(self, path):
     if not os.path.isdir(path):
         raise IOError, 'Path is not a folder'
     path = USBMS.normalize_path(path)
     if path.endswith(os.sep):
         self._main_prefix = path
     else:
         self._main_prefix = path + os.sep
     self.booklist_class = BookList
     self.is_connected = True
Ejemplo n.º 13
0
 def books(self, oncard=None, end_session=True):
     bl = USBMS.books(self, oncard=oncard, end_session=end_session)
     # Read collections information
     collections = os.path.join(self._main_prefix, 'system', 'collections.json')
     if os.access(collections, os.R_OK):
         try:
             self.kindle_update_booklist(bl, collections)
         except:
             import traceback
             traceback.print_exc()
     return bl
Ejemplo n.º 14
0
 def books(self, oncard=None, end_session=True):
     bl = USBMS.books(self, oncard=oncard, end_session=end_session)
     # Read collections information
     collections = os.path.join(self._main_prefix, 'system', 'collections.json')
     if os.access(collections, os.R_OK):
         try:
             self.kindle_update_booklist(bl, collections)
         except:
             import traceback
             traceback.print_exc()
     return bl
Ejemplo n.º 15
0
    def delete_single_book(self, path):
        if path.replace('\\', '/').endswith('.sdr/assets/metadata.kfx'):
            kfx_path = get_kfx_path(path)
            if DEBUG:
                prints('Kindle driver: Attempting to delete kfx: %r -> %r' % (path, kfx_path))
            if os.path.exists(kfx_path):
                os.unlink(kfx_path)
            sdr_path = kfx_path.rpartition('.')[0] + '.sdr'
            if os.path.exists(sdr_path):
                shutil.rmtree(sdr_path)
            try:
                os.removedirs(os.path.dirname(kfx_path))
            except Exception:
                pass

        else:
            return USBMS.delete_single_book(self, path)
Ejemplo n.º 16
0
 def delete_single_book(self, path):
     USBMS.delete_single_book(self, path)
Ejemplo n.º 17
0
 def delete_single_book(self, path):
     USBMS.delete_single_book(self, path)
Ejemplo n.º 18
0
 def create_upload_path(self, path, mdata, fname, create_dirs=True):
     is_news = mdata.tags and _('News') in mdata.tags
     subdir = 'Magazines' if is_news else 'Books'
     path = os.path.join(path, subdir)
     return USBMS.create_upload_path(self, path, mdata, fname,
             create_dirs=create_dirs)
Ejemplo n.º 19
0
 def initialize(self):
     self.plugin_needs_delayed_initialization = True
     USBMS.initialize(self)
Ejemplo n.º 20
0
 def initialize(self):
     self.plugin_needs_delayed_initialization = True
     USBMS.initialize(self)
Ejemplo n.º 21
0
    def books(self, oncard=None, end_session=True):
        import sqlite3 as sqlite

        dummy_bl = BookList(None, None, None)

        if (
                (oncard == 'carda' and not self._card_a_prefix) or
                (oncard and oncard != 'carda')
            ):
            self.report_progress(1.0, _('Getting list of books on device...'))
            return dummy_bl

        prefix = self._card_a_prefix if oncard == 'carda' else self._main_prefix

        # Let parent driver get the books
        self.booklist_class.rebuild_collections = self.rebuild_collections
        bl = USBMS.books(self, oncard=oncard, end_session=end_session)

        dbpath = self.normalize_path(prefix + DBPATH)
        debug_print("SQLite DB Path: " + dbpath)

        with closing(sqlite.connect(dbpath)) as connection:
            # Replace undecodable characters in the db instead of erroring out
            connection.text_factory = lambda x: unicode(x, "utf-8", "replace")

            cursor = connection.cursor()
            # Query collections
            query = '''
                SELECT books._id, collection.title
                    FROM collections
                    LEFT OUTER JOIN books
                    LEFT OUTER JOIN collection
                    WHERE collections.content_id = books._id AND
                    collections.collection_id = collection._id
                '''
            cursor.execute(query)

            bl_collections = {}
            for i, row in enumerate(cursor):
                bl_collections.setdefault(row[0], [])
                bl_collections[row[0]].append(row[1])

            # collect information on offsets, but assume any
            # offset we already calculated is correct
            if self.device_offset is None:
                query = 'SELECT file_path, modified_date FROM books'
                cursor.execute(query)

                time_offsets = {}
                for i, row in enumerate(cursor):
                    try:
                        comp_date = int(os.path.getmtime(self.normalize_path(prefix + row[0])) * 1000);
                    except (OSError, IOError, TypeError):
                        # In case the db has incorrect path info
                        continue
                    device_date = int(row[1]);
                    offset = device_date - comp_date
                    time_offsets.setdefault(offset, 0)
                    time_offsets[offset] = time_offsets[offset] + 1

                try:
                    device_offset = max(time_offsets,key = lambda a: time_offsets.get(a))
                    debug_print("Device Offset: %d ms"%device_offset)
                    self.device_offset = device_offset
                except ValueError:
                    debug_print("No Books To Detect Device Offset.")

            for idx, book in enumerate(bl):
                query = 'SELECT _id, thumbnail FROM books WHERE file_path = ?'
                t = (book.lpath,)
                cursor.execute (query, t)

                for i, row in enumerate(cursor):
                    book.device_collections = bl_collections.get(row[0], None)
                    thumbnail = row[1]
                    if thumbnail is not None:
                        thumbnail = self.normalize_path(prefix + thumbnail)
                        book.thumbnail = ImageWrapper(thumbnail)

            cursor.close()

        return bl
Ejemplo n.º 22
0
 def formats_to_scan_for(self):
     ans = USBMS.formats_to_scan_for(self) | {'azw3'}
     return ans
Ejemplo n.º 23
0
 def formats_to_scan_for(self):
     ans = USBMS.formats_to_scan_for(self) | {'azw3'}
     return ans
Ejemplo n.º 24
0
    def books(self, oncard=None, end_session=True):
        import sqlite3 as sqlite

        dummy_bl = BookList(None, None, None)

        if (
                (oncard == 'carda' and not self._card_a_prefix) or
                (oncard and oncard != 'carda')
            ):
            self.report_progress(1.0, _('Getting list of books on device...'))
            return dummy_bl

        prefix = self._card_a_prefix if oncard == 'carda' else self._main_prefix

        # Let parent driver get the books
        self.booklist_class.rebuild_collections = self.rebuild_collections
        bl = USBMS.books(self, oncard=oncard, end_session=end_session)

        dbpath = self.normalize_path(prefix + DBPATH)
        debug_print("SQLite DB Path: " + dbpath)

        with closing(sqlite.connect(dbpath)) as connection:
            # Replace undecodable characters in the db instead of erroring out
            connection.text_factory = lambda x: unicode(x, "utf-8", "replace")

            cursor = connection.cursor()
            # Query collections
            query = '''
                SELECT books._id, collection.title
                    FROM collections
                    LEFT OUTER JOIN books
                    LEFT OUTER JOIN collection
                    WHERE collections.content_id = books._id AND
                    collections.collection_id = collection._id
                '''
            cursor.execute(query)

            bl_collections = {}
            for i, row in enumerate(cursor):
                bl_collections.setdefault(row[0], [])
                bl_collections[row[0]].append(row[1])

            # collect information on offsets, but assume any
            # offset we already calculated is correct
            if self.device_offset is None:
                query = 'SELECT file_path, modified_date FROM books'
                cursor.execute(query)

                time_offsets = {}
                for i, row in enumerate(cursor):
                    try:
                        comp_date = int(os.path.getmtime(self.normalize_path(prefix + row[0])) * 1000)
                    except (OSError, IOError, TypeError):
                        # In case the db has incorrect path info
                        continue
                    device_date = int(row[1])
                    offset = device_date - comp_date
                    time_offsets.setdefault(offset, 0)
                    time_offsets[offset] = time_offsets[offset] + 1

                try:
                    device_offset = max(time_offsets, key=lambda a: time_offsets.get(a))
                    debug_print("Device Offset: %d ms"%device_offset)
                    self.device_offset = device_offset
                except ValueError:
                    debug_print("No Books To Detect Device Offset.")

            for idx, book in enumerate(bl):
                query = 'SELECT _id, thumbnail FROM books WHERE file_path = ?'
                t = (book.lpath,)
                cursor.execute(query, t)

                for i, row in enumerate(cursor):
                    book.device_collections = bl_collections.get(row[0], None)
                    thumbnail = row[1]
                    if thumbnail is not None:
                        thumbnail = self.normalize_path(prefix + thumbnail)
                        book.thumbnail = ImageWrapper(thumbnail)

            cursor.close()

        return bl
Ejemplo n.º 25
0
    def _fetch_annotations(self):
        self._log_location("Start!!!!")

        count_bookmark_query = ('''
            SELECT COUNT(*) AS num_bookmarks FROM Tags t
            WHERE TagID = 102 AND VAL IS NOT 'bookmark'
            AND ItemID IN (SELECT OID from Items WHERE State = 0)
            ''')

        books_metadata_query = ('''
            SELECT b.OID AS book_oid, i.format, p.Path || f.filename AS filepath, Title, Authors FROM Books b
            LEFT JOIN (SELECT MAX(OID), BookID, PathID, Name AS filename FROM Files GROUP BY BookID) f ON b.OID = f.BookID
            LEFT JOIN (SELECT ItemID, Val AS format FROM Tags WHERE TagID = 17) i ON b.OID = i.ItemID
            LEFT JOIN Paths p ON p.OID = PathID
            WHERE b.OID IN (SELECT DISTINCT ParentID FROM Items WHERE TypeID = 4 ORDER BY ParentID)
            GROUP BY b.OID
            ORDER BY b.OID
            ''')

        # For 104 (highlight_txt) either use json_extract(text), or import JSON using python
        # as notes edited in the PB notes app loose their Begin/End JSON fields.
        annotation_data_query = ('''
            SELECT i.OID AS item_oid, i.TimeAlt, t.TagID, t.Val FROM Items i
            LEFT JOIN Tags t ON i.OID=t.ItemID
            WHERE ParentID = ? AND State = 0
            ORDER BY i.OID, t.TagID
            ''')

        def get_device_path_from_id(id_):
            paths = []
            for x in ('memory', 'card_a', 'card_b'):
                x = getattr(self.opts.gui, x + '_view').model()
                paths += x.paths_for_db_ids(set([id_]), as_map=True)[id_]
            return paths[0].path if paths else None

        # Modified.
        def generate_annotation_paths(ids, mode="default"):
            path_map = {}
            for id in ids:
                fullpath = get_device_path_from_id(id)
                if not fullpath:
                    continue

                if mode == "default":
                    pbmainroot = "/mnt/ext1/"
                    pbcardroot = "/mnt/ext2/"

                if self.device._main_prefix in fullpath:
                    path_map[os.path.join(
                        pbmainroot,
                        os.path.relpath(fullpath,
                                        start=self.device._main_prefix))] = id
                elif self.device._card_a_prefix in fullpath:
                    path_map[os.path.join(
                        pbcardroot,
                        os.path.relpath(
                            fullpath, start=self.device._card_a_prefix))] = id
                elif fullpath.startswith(('/var/', '/tmp/')):
                    continue
                else:
                    self._log("Path not matched: %s" % (fullpath))

            return path_map

        def generate_title_map(ids, db):
            title_map = {}
            for id in ids:
                title = db.get_metadata(id, index_is_id=True).title
                if title:
                    title_map[title] = {}
                    title_map[title]['book_id'] = id
                    title_map[title]['authors'] = db.get_metadata(
                        id, index_is_id=True).format_authors()
                else:
                    continue

            return title_map

        # Get DB location (only stock or default profile)
        self._log("Getting DB location")
        locations = [
            os.path.join(self.device._main_prefix, 'system/config/books.db'),
            os.path.join(self.device._main_prefix,
                         'system/profiles/default/config/books.db')
        ]
        paths = [path for path in locations if os.path.exists(path)]
        if paths:
            db_location = USBMS.normalize_path(paths[0])
        else:
            self._log(
                "No DB found. Currently only supports default profiles, with DB based notes. Stopping"
            )
            return

        # Borrowed from Kobo
        db = self.opts.gui.library_view.model().db
        if not self.onDeviceIds:
            self.onDeviceIds = set(
                db.search_getting_ids('ondevice:True',
                                      None,
                                      sort_results=False,
                                      use_virtual_library=False))

        if len(self.onDeviceIds) == 0:
            return
        self._log("_fetch_annotations - onDeviceIds={0}".format(
            self.onDeviceIds))

        path_map = generate_annotation_paths(self.onDeviceIds)
        title_map = generate_title_map(self.onDeviceIds, db)

        # Start fetching annotations
        from contextlib import closing
        import apsw
        with closing(apsw.Connection(db_location)) as connection:
            self.opts.pb.set_label(_("Fetch annotations from database"))
            #connection.setrowtrace(self.row_factory)

            cursor = connection.cursor()
            cursor.execute(count_bookmark_query)
            try:
                result = next(cursor)
                count_bookmarks = result[0]
            except StopIteration:
                count_bookmarks = 0
            self._log(
                "_fetch_annotations - Total number of bookmarks={0}".format(
                    count_bookmarks))
            self._log("_fetch_annotations - About to get annotations")
            self._read_database_annotations(connection,
                                            books_metadata_query,
                                            annotation_data_query,
                                            path_map,
                                            title_map,
                                            fetchbookmarks=False)
            self._log("_fetch_annotations - Finished getting annotations")

        self._log_location("Finish!!!!")