diff --git a/app/gui.py b/app/gui.py index 48aca66..08272d7 100644 --- a/app/gui.py +++ b/app/gui.py @@ -136,7 +136,7 @@ class CoverLoader(QObject): def run(self): from concurrent.futures import ThreadPoolExecutor, as_completed - pool = ThreadPoolExecutor(max_workers=8) + pool = ThreadPoolExecutor(max_workers=6) futures = { pool.submit(load_cover, it): i for i, it in enumerate(self.items) @@ -1634,7 +1634,7 @@ class StoreCoverLoader(QObject): def run(self): from concurrent.futures import ThreadPoolExecutor, as_completed - pool = ThreadPoolExecutor(max_workers=8) + pool = ThreadPoolExecutor(max_workers=6) futures = { pool.submit(load_cover, it, 8, self.quick): row for row, it in self.tasks @@ -5954,8 +5954,24 @@ class MainWindow(QMainWindow): event.accept() +def _raise_nofile_limit(): + """Raise the soft file-descriptor limit to the hard limit. + + Cover/metadata loading opens many short-lived sockets, and each worker + QThread's GLib event dispatcher creates a wakeup pipe. On systems with a + 1024 soft limit this aborts the process with GLib's "Too many open files". + """ + try: + import resource + _soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE) + resource.setrlimit(resource.RLIMIT_NOFILE, (hard, hard)) + except Exception: # noqa: BLE001 - best effort, never block startup + pass + + def main(): logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)-7s %(name)-14s %(message)s") + _raise_nofile_limit() init_db() # migrate legacy on-share DB/covers to local storage, then schema # Auto-ingest any missing DATs so scanning matches against the catalog # even on a fresh/reset database (no manual `python -m app.ingest` step).