2
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
5
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
6
__docformat__ = 'restructuredtext en'
9
from hashlib import sha1
11
from calibre.constants import filesystem_encoding
12
from calibre.ebooks import BOOK_EXTENSIONS
14
def find_folders_under(root, db, add_root=True, # {{{
15
follow_links=False, cancel_callback=lambda : False):
17
Find all folders under the specified root path, ignoring any folders under
18
the library path of db
20
root must be a bytestring in filesystem_encoding
22
If follow_links is True, follow symbolic links. WARNING; this can lead to
25
cancel_callback must be a no argument callable that returns True to cancel
28
assert not isinstance(root, unicode) # root must be in filesystem encoding
30
if isinstance(lp, unicode):
32
lp = lp.encode(filesystem_encoding)
36
lp = os.path.abspath(lp)
38
root = os.path.abspath(root)
41
for dirpath, dirnames, __ in os.walk(root, topdown=True, followlinks=follow_links):
44
for x in list(dirnames):
45
path = os.path.join(dirpath, x)
46
if lp and path.startswith(lp):
48
if lp and dirpath.startswith(lp):
59
class FormatCollection(object): # {{{
61
def __init__(self, parent_folder, formats):
63
for x in set(formats):
64
fmt = os.path.splitext(x)[1].lower()
67
self.path_map[fmt] = x
68
self.parent_folder = None
70
for fmt, path in self.format_map.items():
71
self.hash_map[fmt] = self.hash_of_file(path)
73
def hash_of_file(self, path):
74
with open(path, 'rb') as f:
75
return sha1(f.read()).digest()
79
return frozenset(self.formats.values())
86
for x in self.path_map:
90
return len(self.path_map)
92
def remove(self, fmt):
93
self.hash_map.pop(fmt, None)
94
self.path_map.pop(fmt, None)
96
def matches(self, other):
97
if not self.hashes.intersection(other.hashes):
100
if self.hash_map[fmt] != other.hash_map.get(fmt, False):
104
def merge(self, other):
105
for fmt in list(other):
106
self.path_map[fmt] = other.path_map[fmt]
107
self.hash_map[fmt] = other.hash_map[fmt]
112
def books_in_folder(folder, one_per_folder, # {{{
113
cancel_callback=lambda : False):
114
assert not isinstance(folder, unicode)
116
dirpath = os.path.abspath(folder)
119
for path in os.listdir(dirpath):
120
if cancel_callback():
122
path = os.path.abspath(os.path.join(dirpath, path))
123
if os.path.isdir(path) or not os.access(path, os.R_OK):
125
ext = os.path.splitext(path)[1]
128
ext = ext[1:].lower()
129
if ext not in BOOK_EXTENSIONS and ext != 'opf':
132
return [FormatCollection(folder, formats)]
135
for path in os.listdir(dirpath):
136
if cancel_callback():
138
path = os.path.abspath(os.path.join(dirpath, path))
139
if os.path.isdir(path) or not os.access(path, os.R_OK):
141
ext = os.path.splitext(path)[1]
144
ext = ext[1:].lower()
145
if ext not in BOOK_EXTENSIONS:
148
key = os.path.splitext(path)[0]
149
if not books.has_key(key):
153
return [FormatCollection(folder, x) for x in books.values() if x]
157
def hash_merge_format_collections(collections, cancel_callback=lambda:False):
160
collections = list(collections)
163
if cancel_callback():
168
for j in range(i+1, l):
169
if cancel_callback():