53 lines
1.7 KiB
Python
53 lines
1.7 KiB
Python
"""Example for concurrent export of photos using osxphotos.PhotoExporter.export()
|
|
|
|
Note: concurrent export can only be used on Python 3.11 and later due to the way
|
|
python's sqlite3 module is implemented. See https://docs.python.org/3/library/sqlite3.html#sqlite3.threadsafety
|
|
for more information.
|
|
"""
|
|
|
|
import concurrent.futures
|
|
import os
|
|
import time
|
|
|
|
import click
|
|
|
|
import osxphotos
|
|
from osxphotos.cli import echo, query_command, verbose
|
|
|
|
|
|
@query_command()
|
|
@click.option(
|
|
"--workers",
|
|
metavar="WORKERS",
|
|
help="Maximum number of worker threads to use for export. "
|
|
"If not specified, it will default to the number of processors on the machine, multiplied by 5.",
|
|
type=int,
|
|
)
|
|
@click.argument(
|
|
"export_dir",
|
|
type=click.Path(exists=True, file_okay=False, dir_okay=True, writable=True),
|
|
)
|
|
def export(workers, export_dir, photos: list[osxphotos.PhotoInfo], **kwargs):
|
|
"""Export photos to EXPORT_DIR using concurrent export.
|
|
Use --workers to specify the number of worker threads to use.
|
|
|
|
This simple example exports only the original photo and does not export
|
|
edited versions, live photos, etc.
|
|
"""
|
|
workers = workers or os.cpu_count() * 5
|
|
echo(f"Exporting {len(photos)} photos to {export_dir} using {workers} workers")
|
|
start_t = time.perf_counter()
|
|
with concurrent.futures.ThreadPoolExecutor(max_workers=workers) as executor:
|
|
futures = [executor.submit(p.export, export_dir) for p in photos]
|
|
exported = []
|
|
for future in concurrent.futures.as_completed(futures):
|
|
exported.extend(future.result())
|
|
end_t = time.perf_counter()
|
|
echo(
|
|
f"Exported {len(exported)} photos to {export_dir} in {end_t-start_t:.4f} seconds"
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
export()
|