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 {