Skip to content

Commit 0b25338

Browse files
committed
fix: bug #5 #6 #7
1 parent 6de8f90 commit 0b25338

3 files changed

Lines changed: 78 additions & 29 deletions

File tree

epub_browser/library.py

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,17 @@ def add_book(self, epub_path):
9292

9393
# 存储书籍信息
9494
book_info = processor.get_book_info()
95+
96+
# 如果同一路径之前已有旧记录,先清理旧记录
97+
# (用于处理覆盖同名 EPUB 文件的情况,旧 hash 与新 hash 不同)
98+
origin_path = book_info['origin_file_path']
99+
if origin_path in self.file2hash:
100+
old_hash = self.file2hash[origin_path]
101+
new_hash = book_info['hash']
102+
if old_hash != new_hash and old_hash in self.books:
103+
print(f"[Add] Replacing old version: {self.books[old_hash]['title']} (hash: {old_hash})")
104+
self.remove_book(old_hash)
105+
95106
self.books[book_info['hash']] = {
96107
'temp_dir': book_info['temp_dir'],
97108
'title': book_info['title'],
@@ -102,7 +113,7 @@ def add_book(self, epub_path):
102113
'processor': processor,
103114
'origin_file_path': book_info['origin_file_path']
104115
}
105-
self.file2hash[book_info['origin_file_path']] = book_info['hash']
116+
self.file2hash[origin_path] = book_info['hash']
106117

107118
# print(f"Successfully added book: {book_info['title']} (Hash: {book_info['hash']})")
108119
return True, book_info
@@ -240,7 +251,8 @@ def create_library_home(self):
240251
cur_tags = book_info['tags']
241252
if cur_tags:
242253
for cur_tag in cur_tags:
243-
all_tags.add(cur_tag)
254+
if isinstance(cur_tag, str) and cur_tag.strip():
255+
all_tags.add(cur_tag.strip())
244256

245257
library_html += f"""
246258
<div class="container">
@@ -276,7 +288,7 @@ def create_library_home(self):
276288
<div class="tag-cloud-item active" data-id="All">All</div>
277289
<div class="tag-cloud-item" data-id="NoTag">NoTag</div>
278290
"""
279-
for tag in sorted(all_tags):
291+
for tag in sorted(t for t in all_tags if isinstance(t, str) and t.strip()):
280292
library_html += f"""<div class="tag-cloud-item" data-id="{tag}">{tag}</div>"""
281293
library_html += """
282294
</div>
@@ -505,12 +517,20 @@ def move_book(self, book_hash):
505517
def remove_book(self, book_hash):
506518
book_path = os.path.join(self.base_directory, "book")
507519
cur_path = os.path.join(book_path, book_hash)
520+
521+
# Clean up file2hash mapping
522+
if book_hash in self.books:
523+
origin_path = self.books[book_hash].get('origin_file_path')
524+
if origin_path and origin_path in self.file2hash:
525+
del self.file2hash[origin_path]
526+
508527
if os.path.exists(cur_path):
509528
try:
510529
shutil.rmtree(cur_path)
511-
self.books.pop(book_hash)
512530
except Exception as e:
513531
print(f"remove {cur_path} failed, err: {e}")
532+
533+
self.books.pop(book_hash, None)
514534

515535
def reorganize_files(self):
516536
"""按照 href 的格式组织目录"""

epub_browser/watch.py

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,27 @@ def _handle_move_source(self, src_path, book_hash, book_info):
183183
def _handle_move_destination(self, dest_path):
184184
"""处理移动操作目标文件的后台任务"""
185185
try:
186-
print(f"[{str(datetime.now())}][Move] Wait for 3 seconds to allow the file to stabilize before adding it: {dest_path}")
187-
time.sleep(3) # 等待文件稳定
188-
print(f"[{str(datetime.now())}][Move] Processing destination addition: {dest_path}")
186+
# Wait for the file to stabilize (rclone/WebDAV uploads may need extra time)
187+
print(f"[{str(datetime.now())}][Move] Waiting for file to stabilize: {dest_path}")
188+
stable = False
189+
last_size = -1
190+
for attempt in range(10): # up to ~5 seconds of stabilization
191+
if not os.path.exists(dest_path):
192+
print(f"[{str(datetime.now())}][Move] File not found, waiting: {dest_path}")
193+
time.sleep(0.5)
194+
continue
195+
current_size = os.path.getsize(dest_path)
196+
if current_size == last_size and current_size > 0:
197+
stable = True
198+
break
199+
last_size = current_size
200+
time.sleep(0.5)
201+
202+
if not stable:
203+
print(f"[{str(datetime.now())}][Move] File did not stabilize, skipping: {dest_path}")
204+
return
205+
206+
print(f"[{str(datetime.now())}][Move] File stabilized ({last_size} bytes), processing: {dest_path}")
189207
with self.library_lock:
190208
ok, book_info = self.library.add_book(dest_path)
191209
if ok:
@@ -200,27 +218,38 @@ def _handle_move_destination(self, dest_path):
200218
sys.stderr.flush()
201219

202220
def on_moved(self, event):
203-
if not event.is_directory and event.src_path.endswith('.epub'):
204-
print(f"[{str(datetime.now())}][Move] EPUB file detected: from {event.src_path} to {event.dest_path}")
205-
# 处理源文件删除(如果存在)
206-
if event.src_path in self.library.file2hash:
207-
book_hash = self.library.file2hash[event.src_path]
208-
if book_hash in self.library.books:
209-
book_info = self.library.books[book_hash]
210-
# 提交源文件处理到线程池
211-
task_id = f"move_src_{event.src_path}"
212-
self._submit_task(task_id, self._handle_move_source, event.src_path, book_hash, book_info)
213-
214-
# 处理目标文件添加
215-
if event.dest_path.endswith('.epub'):
216-
if (not os.path.basename(event.dest_path).startswith(".")) and (not self.has_hidden_component(event.dest_path)):
217-
dest_path = event.dest_path
218-
if (os.path.basename(dest_path).startswith(".")) or (self.has_hidden_component(dest_path)):
219-
print(f"[{str(datetime.now())}][Move] Hidden file will not be processed: {dest_path}")
220-
return
221-
# 提交目标文件处理到线程池
222-
task_id = f"move_dest_{dest_path}"
223-
self._submit_task(task_id, self._handle_move_destination, dest_path)
221+
if event.is_directory:
222+
return
223+
224+
dest_is_epub = event.dest_path.endswith('.epub')
225+
src_is_epub = event.src_path.endswith('.epub')
226+
227+
# Handle .partial → .epub rename (common with rclone/WebDAV uploads)
228+
if not src_is_epub and dest_is_epub:
229+
# e.g. file.epub..partial → file.epub
230+
if not os.path.basename(event.dest_path).startswith(".") and not self.has_hidden_component(event.dest_path):
231+
print(f"[{str(datetime.now())}][Move] EPUB file detected (partial rename): from {event.src_path} to {event.dest_path}")
232+
task_id = f"move_dest_{event.dest_path}"
233+
self._submit_task(task_id, self._handle_move_destination, event.dest_path)
234+
return
235+
236+
if not src_is_epub:
237+
return
238+
239+
print(f"[{str(datetime.now())}][Move] EPUB file detected: from {event.src_path} to {event.dest_path}")
240+
# Handle source deletion (if existed)
241+
if event.src_path in self.library.file2hash:
242+
book_hash = self.library.file2hash[event.src_path]
243+
if book_hash in self.library.books:
244+
book_info = self.library.books[book_hash]
245+
task_id = f"move_src_{event.src_path}"
246+
self._submit_task(task_id, self._handle_move_source, event.src_path, book_hash, book_info)
247+
248+
# Handle destination addition
249+
if dest_is_epub:
250+
if not os.path.basename(event.dest_path).startswith(".") and not self.has_hidden_component(event.dest_path):
251+
task_id = f"move_dest_{event.dest_path}"
252+
self._submit_task(task_id, self._handle_move_destination, event.dest_path)
224253

225254
def shutdown(self):
226255
"""关闭线程池"""

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
setup(
88
name="epub-browser", # 在PyPI上显示的项目名称
9-
version="1.9.1", # 初始版本号
9+
version="1.9.2", # 初始版本号
1010
author="dfface", # 作者名
1111
author_email="dfface@sina.com", # 作者邮箱
1212
keywords="epub reader html export browser convert calibre-web calibre kindle web server local",

0 commit comments

Comments
 (0)