diff --git a/diagnostic/index.html b/diagnostic/index.html
index 8097eb4..c63a475 100644
--- a/diagnostic/index.html
+++ b/diagnostic/index.html
@@ -4753,11 +4753,20 @@
document.getElementById('apk-status').textContent = '';
const log = document.getElementById('apk-log');
log.style.display = 'none'; log.textContent = '';
- // Namensfeld vorbelegen — aber nicht mit Seriennummern/IP-Platzhaltern,
- // die die Netz-Erkennung bei Fire TV oft liefert (z.B. 0d94400fa5b63301).
+ // Namensfeld vorbelegen. Reihenfolge:
+ // 1. Name, den der Agent auf DIESEM Gerät schon trägt (per IP zugeordnet)
+ // 2. zuletzt hier eingegebener Name (im Browser gemerkt)
+ // 3. der Name aus der Netz-Erkennung — aber nur, wenn er menschenlesbar ist
+ // (Fire TV meldet oft Seriennummern wie F8FCE10B4E6C@AS-AFTKA[AirPlay])
+ const known = (hosts || []).find(h => h.ip && h.ip === ip);
+ const remembered = (function () {
+ try { return localStorage.getItem('apkName:' + satId + ':' + ip) || ''; }
+ catch (e) { return ''; }
+ })();
const looksTechnical = !name || /^[0-9a-f]{8,}$/i.test(name) ||
- /^\d{1,3}(\.\d{1,3}){3}$/.test(name);
- document.getElementById('apk-name').value = looksTechnical ? '' : name;
+ /^\d{1,3}(\.\d{1,3}){3}$/.test(name) || /[@\[\]:]/.test(name);
+ document.getElementById('apk-name').value =
+ (known && known.name) || remembered || (looksTechnical ? '' : name);
document.getElementById('apk-modal').classList.add('open');
}
function closeApkDeploy() {
@@ -4785,6 +4794,7 @@
// Am PC getippter Name gewinnt; sonst der aus der Netz-Erkennung (der
// ist bei Fire TV oft nur die Seriennummer).
params.name = document.getElementById('apk-name').value.trim() || apkTarget.name;
+ rememberApkName(params.name);
}
send({ action: 'sat_command', satellite: apkTarget.satId, cmd: 'adb.install',
requestId: apkRequestId, params });
@@ -4803,7 +4813,16 @@
send({ action: 'sat_command', satellite: apkTarget.satId, cmd: 'adb.provision',
requestId: apkRequestId,
params: { ip: apkTarget.ip, provision: true,
- name: document.getElementById('apk-name').value.trim() || apkTarget.name } });
+ name: rememberApkName(document.getElementById('apk-name').value.trim()
+ || apkTarget.name) } });
+ }
+
+ /** Merkt sich den vergebenen Namen pro Gerät (Vorschlag beim naechsten Mal). */
+ function rememberApkName(n) {
+ try {
+ if (apkTarget && n) localStorage.setItem('apkName:' + apkTarget.satId + ':' + apkTarget.ip, n);
+ } catch (e) { /* privater Modus o.ae. */ }
+ return n;
}
/** Prüft, ob der Agent auf dem Gerät installiert ist und läuft. */
diff --git a/diagnostic/server.js b/diagnostic/server.js
index 6caa258..3e03e64 100644
--- a/diagnostic/server.js
+++ b/diagnostic/server.js
@@ -557,7 +557,7 @@ function hostList() {
const now = Date.now();
return Array.from(hosts.values()).map(h => ({
hostId: h.hostId, name: h.name, os: h.os, caps: h.caps, control: h.control,
- online: (now - (h.last_seen || 0)) < 300000,
+ ip: h.ip || "", online: (now - (h.last_seen || 0)) < 300000,
}));
}
@@ -1087,7 +1087,8 @@ function connectRVS(forcePlain) {
const wasKnown = hosts.has(p.hostId);
hosts.set(p.hostId, {
hostId: p.hostId, name: p.name || p.hostId, os: p.os || "",
- caps: p.caps || [], control: !!p.control, last_seen: Date.now(),
+ caps: p.caps || [], control: !!p.control, ip: p.ip || "",
+ last_seen: Date.now(),
});
if (!wasKnown) broadcastHosts();
else hosts.get(p.hostId).last_seen = Date.now();
diff --git a/host-agent/android/app/src/main/java/de/hackersoft/ariaagent/RvsClient.kt b/host-agent/android/app/src/main/java/de/hackersoft/ariaagent/RvsClient.kt
index e315067..5e5f690 100644
--- a/host-agent/android/app/src/main/java/de/hackersoft/ariaagent/RvsClient.kt
+++ b/host-agent/android/app/src/main/java/de/hackersoft/ariaagent/RvsClient.kt
@@ -126,11 +126,24 @@ class RvsClient(
p.put("name", config.displayName())
val kind = if (isTv) "Fire TV / Android TV" else "Android"
p.put("os", "$kind ${Build.VERSION.RELEASE} (${Build.MODEL})")
+ // Eigene LAN-IP mitmelden: so kann die Diagnostic diesen Agenten dem im
+ // Netz entdeckten Geraet zuordnen (z.B. um beim Ausrollen den bereits
+ // vergebenen Namen vorzuschlagen statt der technischen Kennung).
+ localIp()?.let { p.put("ip", it) }
p.put("caps", JSONArray(caps))
p.put("control", config.controlEnabled)
send(webSocket, "host_hello", p)
}
+ /** Erste echte IPv4 dieses Geraets im LAN (ohne Loopback). */
+ private fun localIp(): String? = try {
+ java.net.NetworkInterface.getNetworkInterfaces().toList()
+ .filter { it.isUp && !it.isLoopback }
+ .flatMap { it.inetAddresses.toList() }
+ .firstOrNull { !it.isLoopbackAddress && it is java.net.Inet4Address }
+ ?.hostAddress
+ } catch (_: Throwable) { null }
+
private fun startPing(webSocket: WebSocket) {
pingThread?.interrupt()
pingThread = Thread {