iOS thumbnails: progress logging + newest-first loading order

Sort photos by dateTaken descending before pre-fetching so most
recent photos get thumbnails first — the ones most likely to import.
Log progress after each batch: 'iOS thumbnails: 30/600 loaded (batch 1/20)'.
Log skip count for already-cached photos on subsequent launches.
This commit is contained in:
Kyle Bolen
2026-07-28 08:48:11 +00:00
parent 6e3f6aa20e
commit eef4f61050

View File

@@ -183,8 +183,10 @@ class AppState(private val configStore: ConfigStore) {
val tmpDir = java.nio.file.Paths.get(System.getProperty("java.io.tmpdir"), "photophetch-thumbs") val tmpDir = java.nio.file.Paths.get(System.getProperty("java.io.tmpdir"), "photophetch-thumbs")
if (!tmpDir.toFile().exists()) tmpDir.toFile().mkdirs() if (!tmpDir.toFile().exists()) tmpDir.toFile().mkdirs()
// Only fetch photos not already cached // Only fetch photos not already cached, sorted newest first
val needed = photos.filter { photo -> val needed = photos
.sortedByDescending { it.dateTaken }
.filter { photo ->
val ext = photo.filename.substringAfterLast(".", "").lowercase() val ext = photo.filename.substringAfterLast(".", "").lowercase()
if (ext in setOf("mp4", "mov", "3gp", "avi", "mkv", "m4v", "webm")) return@filter false if (ext in setOf("mp4", "mov", "3gp", "avi", "mkv", "m4v", "webm")) return@filter false
val hash = (cacheKey + photo.devicePath).hashCode().toString(16) val hash = (cacheKey + photo.devicePath).hashCode().toString(16)
@@ -192,11 +194,17 @@ class AppState(private val configStore: ConfigStore) {
!cachePath.toFile().exists() || cachePath.toFile().length() == 0L !cachePath.toFile().exists() || cachePath.toFile().length() == 0L
} }
if (needed.isEmpty()) return if (needed.isEmpty()) {
log.info("Pre-fetching ${needed.size} iOS thumbnails...") log.info("iOS thumbnails: all ${photos.size} already cached")
return
}
log.info("iOS thumbnails: pre-fetching ${needed.size} / ${photos.size} (${photos.size - needed.size} already cached)")
var loaded = 0
val batchSize = 30
// Build pairs JSON and run batch-thumbs command // Build pairs JSON and run batch-thumbs command
needed.chunked(30).forEach { batch -> needed.chunked(batchSize).forEachIndexed { batchIdx, batch ->
val pairs = batch.joinToString(",") { photo -> val pairs = batch.joinToString(",") { photo ->
val ext = photo.filename.substringAfterLast(".", "").lowercase() val ext = photo.filename.substringAfterLast(".", "").lowercase()
val hash = (cacheKey + photo.devicePath).hashCode().toString(16) val hash = (cacheKey + photo.devicePath).hashCode().toString(16)
@@ -210,11 +218,12 @@ class AppState(private val configStore: ConfigStore) {
try { try {
val process = ProcessBuilder(connector.pythonBin, connector.helperScript, "batch-thumbs", pairsJson) val process = ProcessBuilder(connector.pythonBin, connector.helperScript, "batch-thumbs", pairsJson)
.redirectErrorStream(false).start() .redirectErrorStream(false).start()
process.inputStream.readBytes() // stdout process.inputStream.readBytes()
process.errorStream.readBytes() // stderr process.errorStream.readBytes()
process.waitFor() process.waitFor()
// Run sips on each successfully pulled file // Run sips on each successfully pulled file
var batchLoaded = 0
batch.forEach { photo -> batch.forEach { photo ->
val ext = photo.filename.substringAfterLast(".", "").lowercase() val ext = photo.filename.substringAfterLast(".", "").lowercase()
val hash = (cacheKey + photo.devicePath).hashCode().toString(16) val hash = (cacheKey + photo.devicePath).hashCode().toString(16)
@@ -227,13 +236,16 @@ class AppState(private val configStore: ConfigStore) {
sips.inputStream.readBytes() sips.inputStream.readBytes()
sips.waitFor() sips.waitFor()
tmpFile.toFile().delete() tmpFile.toFile().delete()
if (cachePath.toFile().exists()) batchLoaded++
} }
} }
loaded += batchLoaded
log.info("iOS thumbnails: $loaded / ${needed.size} loaded (batch ${batchIdx + 1}/${(needed.size + batchSize - 1) / batchSize})")
} catch (e: Exception) { } catch (e: Exception) {
log.warn("iOS thumbnail batch failed: ${e.message}") log.warn("iOS thumbnail batch ${batchIdx + 1} failed: ${e.message}")
} }
} }
log.info("iOS thumbnail pre-fetch complete") log.info("iOS thumbnails: done — $loaded / ${needed.size} loaded successfully")
} }
fun selectFolder(folderName: String?) { fun selectFolder(folderName: String?) {