1414# ' not exist.
1515# ' @param overwrite If `FALSE` (default), skip files that already exist
1616# ' in `dest_dir`.
17+ # ' @param workers Number of parallel download workers. `1` (default) runs
18+ # ' sequentially. Values greater than 1 use [furrr::future_map_dfr()] with
19+ # ' [future::multisession] — requires `furrr` and `future` packages.
1720# ' @return A tibble with columns `airp_id`, `url`, `dest`, and `success`.
1821# '
1922# ' @details
2831# ' Photos with missing (`NA` or empty) URLs are skipped and reported as
2932# ' `success = FALSE` in the output.
3033# '
34+ # ' When `workers > 1`, a [future::multisession] plan is set for the
35+ # ' duration of the call and restored on exit. Each download is independent
36+ # ' so parallelism is safe.
37+ # '
3138# ' @examples
3239# ' centroids <- sf::st_read(system.file("testdata/photo_centroids.gpkg", package = "fly"))
3340# '
3845# '
3946# ' @export
4047fly_fetch <- function (photos_sf , type = " thumbnail" ,
41- dest_dir = " photos" , overwrite = FALSE ) {
48+ dest_dir = " photos" , overwrite = FALSE ,
49+ workers = 1 ) {
4250 type <- match.arg(type , c(" thumbnail" , " flight_log" , " calibration" , " georef" ))
4351
4452 url_col <- switch (type ,
@@ -63,29 +71,51 @@ fly_fetch <- function(photos_sf, type = "thumbnail",
6371 seq_len(nrow(photos_sf ))
6472 }
6573
66- results <- dplyr :: tibble(
67- airp_id = ids ,
68- url = urls ,
69- dest = NA_character_ ,
70- success = FALSE
71- )
74+ rows <- lapply(seq_along(urls ), function (i ) {
75+ list (airp_id = ids [i ], url = urls [i ])
76+ })
7277
73- for (i in seq_len(nrow(results ))) {
74- u <- results $ url [i ]
75- if (is.na(u ) || u == " " ) next
78+ # Self-contained download function that workers can serialize
79+ dl_fn <- function (row ) {
80+ airp_id <- row $ airp_id
81+ u <- row $ url
82+
83+ if (is.na(u ) || u == " " ) {
84+ return (dplyr :: tibble(
85+ airp_id = airp_id , url = u ,
86+ dest = NA_character_ , success = FALSE
87+ ))
88+ }
7689
7790 dest_file <- file.path(dest_dir , basename(u ))
78- results $ dest [i ] <- dest_file
7991
8092 if (! overwrite && file.exists(dest_file )) {
81- results $ success [i ] <- TRUE
82- next
93+ return (dplyr :: tibble(
94+ airp_id = airp_id , url = u ,
95+ dest = dest_file , success = TRUE
96+ ))
8397 }
8498
85- results $ success [ i ] <- tryCatch({
99+ ok <- tryCatch({
86100 utils :: download.file(u , dest_file , mode = " wb" , quiet = TRUE )
87101 file.exists(dest_file ) && file.size(dest_file ) > 0
88102 }, error = function (e ) FALSE )
103+
104+ dplyr :: tibble(
105+ airp_id = airp_id , url = u ,
106+ dest = dest_file , success = ok
107+ )
108+ }
109+
110+ if (workers > 1 ) {
111+ rlang :: check_installed(c(" furrr" , " future" ),
112+ reason = " for parallel downloads (workers > 1)" )
113+ old_plan <- future :: plan(future :: multisession , workers = workers )
114+ on.exit(future :: plan(old_plan ), add = TRUE )
115+ results <- furrr :: future_map_dfr(rows , dl_fn ,
116+ .options = furrr :: furrr_options(packages = " dplyr" ))
117+ } else {
118+ results <- purrr :: map_dfr(rows , dl_fn )
89119 }
90120
91121 n_ok <- sum(results $ success )
0 commit comments