mirror of
https://github.com/crosspoint-reader/calibre-plugins.git
synced 2026-04-29 10:26:59 -07:00
Merge pull request #13 from crosspoint-reader/fix-delete-files
This commit is contained in:
+38
-67
@@ -7,7 +7,7 @@ import urllib.request
|
||||
from calibre.devices.errors import ControlError
|
||||
from calibre.devices.interface import DevicePlugin
|
||||
from calibre.devices.usbms.deviceconfig import DeviceConfig
|
||||
from calibre.devices.usbms.books import Book
|
||||
from calibre.devices.usbms.books import Book, BookList
|
||||
from calibre.ebooks.metadata.book.base import Metadata
|
||||
|
||||
from . import ws_client
|
||||
@@ -149,23 +149,36 @@ class CrossPointDevice(DeviceConfig, DevicePlugin):
|
||||
def save_settings(self, config_widget):
|
||||
config_widget.save()
|
||||
|
||||
def books(self, oncard=None, end_session=True):
|
||||
if oncard is not None:
|
||||
return []
|
||||
entries = self._http_get_json('/api/files', params={'path': '/'})
|
||||
books = []
|
||||
fetch_metadata = PREFS['fetch_metadata']
|
||||
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
|
||||
|
||||
def books(self, oncard=None, end_session=True):
|
||||
if oncard is not None:
|
||||
return BookList(None, None, None)
|
||||
file_list = self._list_files_recursive('/')
|
||||
bl = BookList(None, None, None)
|
||||
fetch_metadata = PREFS['fetch_metadata']
|
||||
for lpath, size in file_list:
|
||||
title = os.path.splitext(os.path.basename(lpath))[0]
|
||||
meta = Metadata(title, [])
|
||||
if fetch_metadata:
|
||||
try:
|
||||
@@ -179,8 +192,8 @@ class CrossPointDevice(DeviceConfig, DevicePlugin):
|
||||
except Exception as exc:
|
||||
self._log(f'[CrossPoint] metadata read failed for {lpath}: {exc}')
|
||||
book = Book('', lpath, size=size, other=meta)
|
||||
books.append(book)
|
||||
return books
|
||||
bl.add_book(book, replace_metadata=True)
|
||||
return bl
|
||||
|
||||
def sync_booklists(self, booklists, end_session=True):
|
||||
# No on-device metadata sync supported.
|
||||
@@ -324,6 +337,8 @@ class CrossPointDevice(DeviceConfig, DevicePlugin):
|
||||
return paths
|
||||
|
||||
def add_books_to_metadata(self, locations, metadata, booklists):
|
||||
self._log(f'[CrossPoint] add_books_to_metadata: {len(locations)} locations, '
|
||||
f'{len(booklists)} booklists')
|
||||
metadata = iter(metadata)
|
||||
for location in locations:
|
||||
info = next(metadata)
|
||||
@@ -332,10 +347,10 @@ class CrossPointDevice(DeviceConfig, DevicePlugin):
|
||||
book = Book('', lpath, size=length, other=info)
|
||||
if booklists:
|
||||
booklists[0].add_book(book, replace_metadata=True)
|
||||
self._log(f'[CrossPoint] added to booklist: {lpath}')
|
||||
else:
|
||||
self._log(f'[CrossPoint] WARNING: booklists empty, could not add {lpath}')
|
||||
|
||||
def add_books_to_metadata(self, locations, metadata, booklists):
|
||||
# No on-device catalog to update yet.
|
||||
return
|
||||
|
||||
def delete_books(self, paths, end_session=True):
|
||||
for path in paths:
|
||||
@@ -353,62 +368,18 @@ class CrossPointDevice(DeviceConfig, DevicePlugin):
|
||||
p = '/' + p
|
||||
return p
|
||||
|
||||
def norm_name(p):
|
||||
if not p:
|
||||
return ''
|
||||
name = os.path.basename(p)
|
||||
try:
|
||||
import unicodedata
|
||||
name = unicodedata.normalize('NFKC', name)
|
||||
except Exception:
|
||||
pass
|
||||
name = name.replace('\u2019', "'").replace('\u2018', "'")
|
||||
return name.casefold()
|
||||
|
||||
device_names = set()
|
||||
try:
|
||||
entries = self._http_get_json('/api/files', params={'path': '/'})
|
||||
on_device = set()
|
||||
for entry in entries:
|
||||
if entry.get('isDirectory'):
|
||||
continue
|
||||
name = entry.get('name', '')
|
||||
if not name:
|
||||
continue
|
||||
on_device.add(norm(name))
|
||||
on_device.add(norm('/' + name))
|
||||
device_names.add(norm_name(name))
|
||||
self._log(f'[CrossPoint] on-device list: {sorted(on_device)}')
|
||||
except Exception as exc:
|
||||
self._log(f'[CrossPoint] refresh list failed: {exc}')
|
||||
on_device = None
|
||||
deleted = set(norm(p) for p in paths)
|
||||
self._log(f'[CrossPoint] deleted paths: {sorted(deleted)}')
|
||||
|
||||
removed = 0
|
||||
for bl in booklists:
|
||||
for book in tuple(bl):
|
||||
bpath = norm(getattr(book, 'path', ''))
|
||||
blpath = norm(getattr(book, 'lpath', ''))
|
||||
self._log(f'[CrossPoint] book paths: {bpath} | {blpath}')
|
||||
should_remove = False
|
||||
if on_device is not None:
|
||||
if device_names:
|
||||
if norm_name(bpath) not in device_names and norm_name(blpath) not in device_names:
|
||||
should_remove = True
|
||||
elif bpath and bpath not in on_device and blpath and blpath not in on_device:
|
||||
should_remove = True
|
||||
else:
|
||||
for path in paths:
|
||||
target = norm(path)
|
||||
target_name = os.path.basename(target)
|
||||
if target == bpath or target == blpath:
|
||||
should_remove = True
|
||||
elif target_name and (os.path.basename(bpath) == target_name or os.path.basename(blpath) == target_name):
|
||||
should_remove = True
|
||||
if should_remove:
|
||||
if bpath in deleted or blpath in deleted:
|
||||
bl.remove_book(book)
|
||||
removed += 1
|
||||
if removed:
|
||||
self._log(f'[CrossPoint] removed {removed} items from device list')
|
||||
self._log(f'[CrossPoint] removed {removed} items from device list')
|
||||
|
||||
def get_file(self, path, outfile, end_session=True, this_book=None, total_books=None):
|
||||
url = self._http_base() + '/download'
|
||||
|
||||
Reference in New Issue
Block a user