Merge branch 'master' into feature/send-to-root

This commit is contained in:
Antoine Vidal
2026-04-20 13:11:48 -04:00
committed by GitHub
3 changed files with 51 additions and 8 deletions
+7
View File
@@ -5,6 +5,7 @@ from qt.core import (
QDialogButtonBox,
QFormLayout,
QHBoxLayout,
QLabel,
QLineEdit,
QPlainTextEdit,
QPushButton,
@@ -50,6 +51,12 @@ class CrossPointConfigWidget(QWidget):
layout.addRow('Host', self.host)
layout.addRow('Port', self.port)
notice = QLabel('Host and port settings are fallback values used only when the device is not auto-discoverable by UDP broadcast.')
notice.setWordWrap(True)
notice.setStyleSheet('color: gray; font-style: italic;')
layout.addRow('', notice)
layout.addRow('Upload path', self.path)
layout.addRow('Chunk size', self.chunk_size)
layout.addRow('', self.debug)
+21 -8
View File
@@ -21,7 +21,7 @@ class CrossPointDevice(DeviceConfig, DevicePlugin):
description = 'CrossPoint Reader wireless device'
supported_platforms = ['windows', 'osx', 'linux']
author = 'CrossPoint Reader'
version = (0, 2, 0)
version = (0, 1, 3)
# Invalid USB vendor info to avoid USB scans matching.
VENDOR_ID = [0xFFFF]
@@ -136,7 +136,8 @@ class CrossPointDevice(DeviceConfig, DevicePlugin):
def _http_post_form(self, path, data, timeout=5):
url = self._http_base() + path
body = urllib.parse.urlencode(data).encode('utf-8')
req = urllib.request.Request(url, data=body, method='POST')
req = urllib.request.Request(url, data=body, method='POST',
headers={'Content-Type': 'application/x-www-form-urlencoded'})
try:
with urllib.request.urlopen(req, timeout=timeout) as resp:
return resp.status, resp.read().decode('utf-8', 'ignore')
@@ -250,7 +251,8 @@ class CrossPointDevice(DeviceConfig, DevicePlugin):
"""
url = self._http_base() + '/mkdir'
body = urllib.parse.urlencode({'name': name, 'path': path}).encode('utf-8')
req = urllib.request.Request(url, data=body, method='POST')
req = urllib.request.Request(url, data=body, method='POST',
headers={'Content-Type': 'application/x-www-form-urlencoded'})
try:
with urllib.request.urlopen(req, timeout=5) as resp:
resp.read()
@@ -353,11 +355,22 @@ class CrossPointDevice(DeviceConfig, DevicePlugin):
def delete_books(self, paths, end_session=True):
for path in paths:
status, body = self._http_post_form('/delete', {'path': path, 'type': 'file'})
if status != 200:
raise ControlError(desc=f'Delete failed for {path}: {body}')
self._log(f'[CrossPoint] deleted {path}')
import json as _json
self._log(f'[CrossPoint] deleting {len(paths)} books: {paths}')
url = self._http_base() + '/delete'
# Server expects form field 'paths' containing a JSON array string
body = urllib.parse.urlencode({'paths': _json.dumps(list(paths))}).encode('utf-8')
req = urllib.request.Request(url, data=body, method='POST',
headers={'Content-Type': 'application/x-www-form-urlencoded'})
try:
with urllib.request.urlopen(req, timeout=10) as resp:
self._log(f'[CrossPoint] delete OK: {resp.status}')
except urllib.error.HTTPError as exc:
err_body = exc.read().decode('utf-8', 'ignore') if exc.fp else ''
self._log(f'[CrossPoint] delete error {exc.code}: {err_body}')
raise ControlError(desc=f'Delete failed: {exc.code} {err_body}')
except Exception as exc:
raise ControlError(desc=f'Delete failed: {exc}')
def remove_books_from_metadata(self, paths, booklists):
def norm(p):
+23
View File
@@ -189,6 +189,21 @@ def _broadcast_from_host(host):
return '.'.join(parts)
def _local_broadcast_addrs():
addrs = set()
try:
for info in socket.getaddrinfo(socket.gethostname(), None, socket.AF_INET):
ip = info[4][0]
if ip.startswith('127.'):
continue
bcast = _broadcast_from_host(ip)
if bcast:
addrs.add(bcast)
except Exception:
pass
return addrs
def discover_device(timeout=2.0, debug=False, logger=None, extra_hosts=None):
ports = [8134, 54982, 48123, 39001, 44044, 59678]
local_port = 0
@@ -210,6 +225,11 @@ def discover_device(timeout=2.0, debug=False, logger=None, extra_hosts=None):
pass
targets = []
for bcast in _local_broadcast_addrs():
_log(logger, debug, f'[CrossPoint WS] discovery subnet broadcast {bcast}')
for port in ports:
targets.append((bcast, port))
# 255.255.255.255 as fallback — works on Linux/Windows, silently fails on macOS
for port in ports:
targets.append(('255.255.255.255', port))
for host in extra_hosts or []:
@@ -240,6 +260,9 @@ def discover_device(timeout=2.0, debug=False, logger=None, extra_hosts=None):
text = data.decode('utf-8', 'ignore')
except Exception:
continue
if not text.startswith('crosspoint'):
_log(logger, debug, f'[CrossPoint WS] discovery ignoring non-crosspoint response: {text}')
continue
semi = text.find(';')
port = 81
if semi != -1: