Anna Schumaker
ad3d4840e8
This function creates a ReaddirThread object to read the directory in a secondary thread. This will let us poll for results without hanging the UI in the case where a music library is on very slow storage (such as NFS). The ReaddirThread will accumulate a list of files that can be polled using the poll_result() function, which will return the files found since the last call to poll_result(). Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
61 lines
1.7 KiB
Python
61 lines
1.7 KiB
Python
# Copyright 2022 (c) Anna Schumaker.
|
|
"""Extra path handling for URIs."""
|
|
import pathlib
|
|
import threading
|
|
import urllib
|
|
|
|
|
|
class ReaddirThread(threading.Thread):
|
|
"""An object to manager asynchronous tree iteration."""
|
|
|
|
def __init__(self, directory: pathlib.Path):
|
|
"""Initialize an IterTreeResult."""
|
|
super().__init__()
|
|
self.root = directory
|
|
self._files = []
|
|
self._lock = threading.Lock()
|
|
self._stop_event = threading.Event()
|
|
|
|
def __read_directory(self, directory: pathlib.Path) -> None:
|
|
if self._stop_event.is_set():
|
|
return
|
|
|
|
for path in directory.iterdir():
|
|
if path.is_dir():
|
|
self.__read_directory(path)
|
|
else:
|
|
with self._lock:
|
|
self._files.append(path)
|
|
|
|
def poll_result(self) -> list[pathlib.Path] | None:
|
|
"""Poll for the result of the IterTreeThread."""
|
|
with self._lock:
|
|
if self.is_alive() or len(self._files):
|
|
files = self._files
|
|
self._files = []
|
|
return files
|
|
return None
|
|
|
|
def run(self) -> None:
|
|
"""Run the IterTreeThread."""
|
|
self.__read_directory(self.root)
|
|
|
|
def stop(self) -> None:
|
|
"""Signal the thread to stop."""
|
|
self._stop_event.set()
|
|
|
|
|
|
def readdir_async(directory: pathlib.Path) -> ReaddirThread:
|
|
"""Iterate through a directory tree asynchronously."""
|
|
if directory.is_dir():
|
|
res = ReaddirThread(directory)
|
|
res.start()
|
|
return res
|
|
|
|
|
|
def from_uri(uri: str) -> pathlib.Path:
|
|
"""Make a path from a uri."""
|
|
if parsed := urllib.parse.urlparse(uri):
|
|
return pathlib.Path(urllib.parse.unquote(parsed.path))
|
|
return pathlib.Path(uri)
|