Fix Android photo discovery: dynamically scan all DCIM subdirs
Instead of hardcoding /sdcard/DCIM/Camera, list all subdirectories under /sdcard/DCIM and /storage/emulated/0/DCIM dynamically. This handles Samsung, Pixel, OnePlus and other vendors that use different DCIM subfolder names. Falls back to hardcoded list if discovery finds nothing.
This commit is contained in:
@@ -24,8 +24,9 @@ class AndroidConnector(
|
||||
|
||||
private val log = LoggerFactory.getLogger(AndroidConnector::class.java)
|
||||
|
||||
// Directories on Android that contain camera-roll originals
|
||||
private val cameraDirs = listOf(
|
||||
// Directories on Android that contain camera-roll originals.
|
||||
// Used as fallback if dynamic DCIM discovery finds nothing.
|
||||
private val fallbackCameraDirs = listOf(
|
||||
"/sdcard/DCIM/Camera",
|
||||
"/sdcard/DCIM/100ANDRO",
|
||||
"/sdcard/Pictures/Camera",
|
||||
@@ -65,13 +66,30 @@ class AndroidConnector(
|
||||
val serial = requireSerial(device)
|
||||
val photos = mutableListOf<PhonePhoto>()
|
||||
|
||||
for (dir in cameraDirs) {
|
||||
// Check if directory exists first
|
||||
// Dynamically discover all subdirectories under DCIM on common storage paths
|
||||
val dcimRoots = listOf("/sdcard/DCIM", "/storage/emulated/0/DCIM")
|
||||
val cameraDirs = mutableListOf<String>()
|
||||
|
||||
for (root in dcimRoots) {
|
||||
val lsOutput = runAdb(serial, "shell", "ls", root, "2>/dev/null")
|
||||
if (lsOutput.contains("No such file") || lsOutput.isBlank()) continue
|
||||
lsOutput.lines()
|
||||
.map { it.trim() }
|
||||
.filter { it.isNotBlank() && !it.contains("No such file") }
|
||||
.forEach { subdir -> cameraDirs.add("$root/$subdir") }
|
||||
}
|
||||
|
||||
// Also check Pictures/Camera (some Samsung models store there)
|
||||
cameraDirs.add("/sdcard/Pictures/Camera")
|
||||
cameraDirs.add("/storage/emulated/0/Pictures/Camera")
|
||||
|
||||
// Fall back to hardcoded list if dynamic discovery found nothing
|
||||
val dirsToScan = cameraDirs.ifEmpty { fallbackCameraDirs }
|
||||
|
||||
for (dir in dirsToScan) {
|
||||
val check = runAdb(serial, "shell", "ls", dir, "2>/dev/null")
|
||||
if (check.contains("No such file") || check.isBlank()) continue
|
||||
|
||||
// List files with metadata: size, date, time, name
|
||||
// `stat` format: size=%s mtime=%Y path=%n
|
||||
val statOutput = runAdb(
|
||||
serial, "shell",
|
||||
"find", dir, "-maxdepth", "1", "-type", "f",
|
||||
@@ -98,8 +116,6 @@ class AndroidConnector(
|
||||
filename = filename,
|
||||
sizeBytes = sizeBytes,
|
||||
dateTaken = Instant.ofEpochSecond(epochSecs),
|
||||
// Android stat doesn't give EXIF; we infer Make/Model from
|
||||
// the device itself rather than per-file EXIF
|
||||
exifMake = device.displayName,
|
||||
exifModel = device.displayName,
|
||||
mediaType = if (ext in setOf("mp4", "mov", "3gp", "avi"))
|
||||
|
||||
Reference in New Issue
Block a user