%PDF- %PDF-
Direktori : /lib/calibre/calibre/library/ |
Current File : //lib/calibre/calibre/library/add_to_library.py |
#!/usr/bin/env python3 __license__ = 'GPL v3' __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>' __docformat__ = 'restructuredtext en' import os from hashlib import sha1 from calibre.ebooks import BOOK_EXTENSIONS def find_folders_under(root, db, add_root=True, # {{{ follow_links=False, cancel_callback=lambda : False): ''' Find all folders under the specified root path, ignoring any folders under the library path of db If follow_links is True, follow symbolic links. WARNING; this can lead to infinite recursion. cancel_callback must be a no argument callable that returns True to cancel the search ''' lp = db.library_path if lp: lp = os.path.abspath(lp) root = os.path.abspath(root) ans = set() for dirpath, dirnames, __ in os.walk(root, topdown=True, followlinks=follow_links): if cancel_callback(): break for x in list(dirnames): path = os.path.join(dirpath, x) if lp and path.startswith(lp): dirnames.remove(x) if lp and dirpath.startswith(lp): continue ans.add(dirpath) if not add_root: ans.remove(root) return ans # }}} class FormatCollection: # {{{ def __init__(self, parent_folder, formats): self.path_map = {} for x in set(formats): fmt = os.path.splitext(x)[1].lower() if fmt: fmt = fmt[1:] self.path_map[fmt] = x self.parent_folder = None self.hash_map = {} for fmt, path in self.format_map.items(): self.hash_map[fmt] = self.hash_of_file(path) def hash_of_file(self, path): with open(path, 'rb') as f: return sha1(f.read()).digest() @property def hashes(self): return frozenset(self.formats.values()) @property def is_empty(self): return len(self) == 0 def __iter__(self): yield from self.path_map def __len__(self): return len(self.path_map) def remove(self, fmt): self.hash_map.pop(fmt, None) self.path_map.pop(fmt, None) def matches(self, other): if not self.hashes.intersection(other.hashes): return False for fmt in self: if self.hash_map[fmt] != other.hash_map.get(fmt, False): return False return True def merge(self, other): for fmt in list(other): self.path_map[fmt] = other.path_map[fmt] self.hash_map[fmt] = other.hash_map[fmt] other.remove(fmt) # }}} def books_in_folder(folder, one_per_folder, # {{{ cancel_callback=lambda : False): dirpath = os.path.abspath(folder) if one_per_folder: formats = set() for path in os.listdir(dirpath): if cancel_callback(): return [] path = os.path.abspath(os.path.join(dirpath, path)) if os.path.isdir(path) or not os.access(path, os.R_OK): continue ext = os.path.splitext(path)[1] if not ext: continue ext = ext[1:].lower() if ext not in BOOK_EXTENSIONS and ext != 'opf': continue formats.add(path) return [FormatCollection(folder, formats)] else: books = {} for path in os.listdir(dirpath): if cancel_callback(): return path = os.path.abspath(os.path.join(dirpath, path)) if os.path.isdir(path) or not os.access(path, os.R_OK): continue ext = os.path.splitext(path)[1] if not ext: continue ext = ext[1:].lower() if ext not in BOOK_EXTENSIONS: continue key = os.path.splitext(path)[0] if key not in books: books[key] = set() books[key].add(path) return [FormatCollection(folder, x) for x in books.values() if x] # }}} def hash_merge_format_collections(collections, cancel_callback=lambda:False): ans = [] collections = list(collections) l = len(collections) for i in range(l): if cancel_callback(): return collections one = collections[i] if one.is_empty: continue for j in range(i+1, l): if cancel_callback(): return collections two = collections[j] if two.is_empty: continue if one.matches(two): one.merge(two) ans.append(one) return ans