feat(import-progress): track and expose Immich import progress
This change introduces a cross-language import progress API for Immich imports and exposes a new query command to report live progress. A new ImportProgress model captures active state, totals, and bytes downloaded, allowing consuming code to display import status to users. - Adds ImportProgress data type and progress tracking during import - Exposes get_immich_import_progress command in Android and Rust - Updates permissions and schemas to include allow-get-immich-import-progress
This commit is contained in:
@@ -17,6 +17,7 @@ import java.nio.charset.StandardCharsets
|
||||
import java.security.KeyStore
|
||||
import java.util.concurrent.Callable
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.KeyGenerator
|
||||
import javax.crypto.SecretKey
|
||||
@@ -33,8 +34,16 @@ object ImmichClient {
|
||||
private const val KEY_ALIAS = "wallpaperflow_immich_api_key"
|
||||
private val assetIdPattern = Regex("^[0-9a-fA-F-]{36}$")
|
||||
private val thumbnailPool = Executors.newFixedThreadPool(4)
|
||||
private val importProgress = AtomicReference(ImportProgress())
|
||||
|
||||
private data class Credentials(val serverUrl: String, val apiKey: String)
|
||||
private data class ImportProgress(
|
||||
val active: Boolean = false,
|
||||
val completed: Int = 0,
|
||||
val total: Int = 0,
|
||||
val bytesDownloaded: Long = 0,
|
||||
val bytesTotal: Long = 0,
|
||||
)
|
||||
|
||||
private fun prefs(context: Context) = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
|
||||
@@ -188,7 +197,21 @@ object ImmichClient {
|
||||
val connection = openConnection(serverUrl, apiKey, path)
|
||||
try {
|
||||
if (connection.responseCode !in 200..299) throw IOException(errorMessage(connection))
|
||||
connection.inputStream.use { input -> target.outputStream().use { output -> input.copyTo(output) } }
|
||||
val total = connection.contentLengthLong.coerceAtLeast(0)
|
||||
var downloaded = 0L
|
||||
importProgress.updateAndGet { it.copy(bytesDownloaded = 0, bytesTotal = total) }
|
||||
connection.inputStream.use { input ->
|
||||
target.outputStream().use { output ->
|
||||
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
|
||||
while (true) {
|
||||
val count = input.read(buffer)
|
||||
if (count < 0) break
|
||||
output.write(buffer, 0, count)
|
||||
downloaded += count
|
||||
importProgress.updateAndGet { it.copy(bytesDownloaded = downloaded, bytesTotal = total) }
|
||||
}
|
||||
}
|
||||
}
|
||||
return connection.contentType.orEmpty().substringBefore(';')
|
||||
} catch (error: Exception) {
|
||||
target.delete()
|
||||
@@ -285,7 +308,26 @@ object ImmichClient {
|
||||
require(ids.isNotEmpty()) { "Wähle mindestens ein Immich-Bild aus." }
|
||||
require(ids.size <= 100) { "Bitte importiere höchstens 100 Bilder auf einmal." }
|
||||
val credentials = credentials(context)
|
||||
ids.distinct().forEach { importOne(context, credentials, it) }
|
||||
return WallpaperStore.state(context)
|
||||
val uniqueIds = ids.distinct()
|
||||
importProgress.set(ImportProgress(active = true, total = uniqueIds.size))
|
||||
try {
|
||||
uniqueIds.forEachIndexed { index, id ->
|
||||
importOne(context, credentials, id)
|
||||
importProgress.updateAndGet { it.copy(completed = index + 1, bytesDownloaded = 0, bytesTotal = 0) }
|
||||
}
|
||||
return WallpaperStore.state(context)
|
||||
} finally {
|
||||
importProgress.updateAndGet { it.copy(active = false) }
|
||||
}
|
||||
}
|
||||
|
||||
fun importProgress(): JSObject = importProgress.get().let { progress ->
|
||||
JSObject().apply {
|
||||
put("active", progress.active)
|
||||
put("completed", progress.completed)
|
||||
put("total", progress.total)
|
||||
put("bytesDownloaded", progress.bytesDownloaded)
|
||||
put("bytesTotal", progress.bytesTotal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,4 +179,8 @@ class WallpaperPlugin(private val activity: Activity) : Plugin(activity) {
|
||||
invoke.resolve(ImmichClient.importAssets(activity, args.ids.toList()))
|
||||
} catch (error: Exception) { invoke.reject(error.message ?: "Immich-Bilder konnten nicht importiert werden") }
|
||||
}
|
||||
|
||||
@Command fun getImmichImportProgress(invoke: Invoke) {
|
||||
invoke.resolve(ImmichClient.importProgress())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user