Skip to content

Improve book listing and deleting#13

Merged
itsthisjustin merged 1 commit intomasterfrom
fix-delete-files
Feb 22, 2026
Merged

Improve book listing and deleting#13
itsthisjustin merged 1 commit intomasterfrom
fix-delete-files

Conversation

@itsthisjustin
Copy link
Collaborator

Books in subfolders now show in device list, deleting removes the book from the list immediately, and newly added books show up immediately

Books in subfolders now show in device list, deleting removes the book from the list immediately, and newly added books show up immediately
@coderabbitai
Copy link

coderabbitai bot commented Feb 22, 2026

📝 Walkthrough

Walkthrough

Modified the books() method in the driver to return a BookList instead of a plain list, implementing recursive directory traversal to collect EPUB files and optionally fetch metadata. Updated related metadata methods with enhanced logging and simplified path-based deletion logic.

Changes

Cohort / File(s) Summary
Books API and Recursive Collection
crosspoint_reader/driver.py
Added BookList import; refactored books() method to return BookList instead of list; introduced _list_files_recursive helper for traversing directories and collecting EPUB files with sizes; changed oncard handling to return empty BookList; updated Book instance construction with title derivation from file paths and optional metadata fetching via temporary EPUB downloads.
Metadata Integration and Management
crosspoint_reader/driver.py
Enhanced add_books_to_metadata with debug logging for location and booklist counts; simplified remove_books_from_metadata to use normalized path-based deletion sets; added warning log when booklists is empty; added logging throughout book-related and metadata flows to trace operations.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Improve book listing and deleting' directly relates to the main changes: recursive directory traversal for book discovery and improved metadata handling for deletions.
Description check ✅ Passed The description is clearly related to the changeset, explaining that books in subfolders now show, deleting removes books immediately, and newly added books appear immediately.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d45aa32 and df6019b.

📒 Files selected for processing (1)
  • crosspoint_reader/driver.py
🧰 Additional context used
🪛 Ruff (0.15.1)
crosspoint_reader/driver.py

[warning] 157-157: Do not catch blind exception: Exception

(BLE001)


[warning] 174-174: Unused method argument: end_session

(ARG002)

🔇 Additional comments (4)
crosspoint_reader/driver.py (4)

174-196: Looks good: immediate in-memory list population.

The recursive listing plus optional metadata hydration is wired cleanly and should satisfy the “show immediately” requirement.


371-382: Removal logic looks solid.

Normalizing both path and lpath before comparison makes the deletion matching robust.


339-352: The code is correct as written. According to Calibre's DevicePlugin API, booklists is always guaranteed to be a 3-tuple of BookList objects, never None. The len(booklists) call on line 341 is safe and will not raise a TypeError. The if booklists: check on line 348 guards against an empty tuple/list, not a None value. No fix is needed.


10-10: Document the minimum supported Calibre version and verify BookList import compatibility.

The calibre.devices.usbms.books.BookList class is available in at least Calibre 5.11.0 and later releases, but the plugin does not declare a minimum version requirement. If the plugin must support older Calibre releases, confirm whether BookList was available at that point, and consider adding a compatibility fallback or explicit version constraint.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crosspoint_reader/driver.py`:
- Around line 152-172: The current _list_files_recursive method swallows all
exceptions from self._http_get_json and returns an empty list, hiding real
errors; change it to let exceptions propagate (or re-raise after logging)
instead of returning results — either remove the try/except around the
self._http_get_json call or, if you want to keep the log, catch Exception as
exc, call self._log(f'[CrossPoint] listing {path} failed: {exc}'), then re-raise
the exception (raise) so callers and the test harness see the failure; keep the
rest of _list_files_recursive logic (including recursion and checks for
isDirectory/isEpub) unchanged.

Comment on lines +152 to +172
def _list_files_recursive(self, path='/'):
"""Return a flat list of (lpath, size) for all EPUB files on device."""
results = []
try:
entries = self._http_get_json('/api/files', params={'path': path})
except Exception as exc:
self._log(f'[CrossPoint] listing {path} failed: {exc}')
return results
for entry in entries:
if entry.get('isDirectory'):
continue
if not entry.get('isEpub'):
continue
name = entry.get('name', '')
if not name:
continue
size = entry.get('size', 0)
lpath = '/' + name if not name.startswith('/') else name
title = os.path.splitext(os.path.basename(name))[0]
if path == '/':
entry_path = '/' + name
else:
entry_path = path + '/' + name
if entry.get('isDirectory'):
results.extend(self._list_files_recursive(entry_path))
elif entry.get('isEpub'):
results.append((entry_path, entry.get('size', 0)))
return results
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don’t swallow listing failures.

Returning an empty list on any exception makes the device appear empty and hides real errors. Let the exception propagate (or re‑raise after logging) so failures surface.

💡 Suggested fix
-        try:
-            entries = self._http_get_json('/api/files', params={'path': path})
-        except Exception as exc:
-            self._log(f'[CrossPoint] listing {path} failed: {exc}')
-            return results
+        try:
+            entries = self._http_get_json('/api/files', params={'path': path})
+        except ControlError as exc:
+            self._log(f'[CrossPoint] listing {path} failed: {exc}')
+            raise
🧰 Tools
🪛 Ruff (0.15.1)

[warning] 157-157: Do not catch blind exception: Exception

(BLE001)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crosspoint_reader/driver.py` around lines 152 - 172, The current
_list_files_recursive method swallows all exceptions from self._http_get_json
and returns an empty list, hiding real errors; change it to let exceptions
propagate (or re-raise after logging) instead of returning results — either
remove the try/except around the self._http_get_json call or, if you want to
keep the log, catch Exception as exc, call self._log(f'[CrossPoint] listing
{path} failed: {exc}'), then re-raise the exception (raise) so callers and the
test harness see the failure; keep the rest of _list_files_recursive logic
(including recursion and checks for isDirectory/isEpub) unchanged.

@itsthisjustin itsthisjustin merged commit cdb9703 into master Feb 22, 2026
1 check passed
@itsthisjustin itsthisjustin deleted the fix-delete-files branch February 22, 2026 23:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant