generated from Dicken/dickendock
round31: Infrastruktur-Praefixe (lxc/vm/docker) aus Namen und Suche entfernt, Icon-Datenbank-Abgleich auch ohne erkannte Software, Sichtbarkeit bei eindeutigem Icon-Treffer
This commit is contained in:
@@ -172,6 +172,26 @@ export async function findBestIconMatch(name: string): Promise<string | null> {
|
|||||||
if (match) return `${CDN_BASE}/${match}.png`;
|
if (match) return `${CDN_BASE}/${match}.png`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Letzter, bewusst noch immer präziser Versuch: ein Name wie "adguard"
|
||||||
|
// trifft "adguard-home" nicht exakt (auch nicht nach Bindestrich-Vergleich),
|
||||||
|
// ist aber ein eindeutiger Wortanfang-Treffer, wenn KEIN anderer Icon-Name
|
||||||
|
// mit "<wort>-" beginnt. Nur dann automatisch übernehmen - bei mehreren
|
||||||
|
// möglichen Treffern bleibt es bei "kein Favicon" (dafür gibt es die
|
||||||
|
// interaktive Auswahl mit mehreren Kandidaten).
|
||||||
|
for (const candidate of [wholeName, ...byPriority(words)]) {
|
||||||
|
if (candidate.length < 3) continue;
|
||||||
|
const prefixMatches = names.filter((n) => n === candidate || n.startsWith(`${candidate}-`));
|
||||||
|
if (prefixMatches.length === 1) return `${CDN_BASE}/${prefixMatches[0]}.png`;
|
||||||
|
if (prefixMatches.length > 1) {
|
||||||
|
// Mehrere Treffer (z. B. "adguard-home" UND "adguard-home-sync" für
|
||||||
|
// "adguard") - den kürzesten (meist der "Haupt"-Name der Software)
|
||||||
|
// automatisch nehmen, aber NUR wenn er eindeutig der kürzeste ist,
|
||||||
|
// sonst bleibt es zweideutig (dafür gibt es die interaktive Auswahl).
|
||||||
|
const sorted = [...prefixMatches].sort((a, b) => a.length - b.length);
|
||||||
|
if (sorted[0].length < sorted[1].length) return `${CDN_BASE}/${sorted[0]}.png`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,12 +49,21 @@ function isIpAddress(value: string): boolean {
|
|||||||
* Liefert null, wenn der Hostname selbst keine brauchbare Information trägt
|
* Liefert null, wenn der Hostname selbst keine brauchbare Information trägt
|
||||||
* (leer oder reine IP) - dann bleibt nur der IP:Port-Fallback übrig.
|
* (leer oder reine IP) - dann bleibt nur der IP:Port-Fallback übrig.
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* Generische Infrastruktur-Präfixe/-Suffixe, die in Proxmox/Docker-Umfeld
|
||||||
|
* üblich, aber inhaltlich bedeutungslos sind ("lxc-adguard" soll als
|
||||||
|
* "Adguard" vorgeschlagen werden, nicht als "Lxc Adguard") - dieselbe Logik
|
||||||
|
* wie die STOPWORDS in scanner/iconDb.ts, hier auf den Hostnamen angewendet.
|
||||||
|
*/
|
||||||
|
const GENERIC_INFRA_WORDS = new Set(["lxc", "vm", "ct", "docker", "container"]);
|
||||||
|
|
||||||
function humanizeHostname(hostname: string): string | null {
|
function humanizeHostname(hostname: string): string | null {
|
||||||
if (!hostname || isIpAddress(hostname)) return null;
|
if (!hostname || isIpAddress(hostname)) return null;
|
||||||
const words = hostname
|
const words = hostname
|
||||||
.replace(/\.(home|local|fritz\.box)$/i, "")
|
.replace(/\.(home|local|fritz\.box)$/i, "")
|
||||||
.split(/[-_.\s]+/)
|
.split(/[-_.\s]+/)
|
||||||
.filter(Boolean);
|
.filter(Boolean)
|
||||||
|
.filter((w) => !GENERIC_INFRA_WORDS.has(w.toLowerCase()));
|
||||||
if (words.length === 0) return null;
|
if (words.length === 0) return null;
|
||||||
return words.map((w) => (w.length > 0 ? w[0].toUpperCase() + w.slice(1) : w)).join(" ");
|
return words.map((w) => (w.length > 0 ? w[0].toUpperCase() + w.slice(1) : w)).join(" ");
|
||||||
}
|
}
|
||||||
@@ -227,11 +236,23 @@ export async function scanDeviceServices(
|
|||||||
// ein falsch zugeordnetes.
|
// ein falsch zugeordnetes.
|
||||||
for (const service of found) {
|
for (const service of found) {
|
||||||
if (service.favicon) continue;
|
if (service.favicon) continue;
|
||||||
const nameToMatch = service.category ? service.suggestedDisplayName : null;
|
// Vorher: nur versucht, wenn Software erkannt wurde. Jetzt auch bei
|
||||||
if (!nameToMatch) continue;
|
// einem aus dem Gerätenamen abgeleiteten Namen ("lxc-adguard" ->
|
||||||
|
// "Adguard", siehe humanizeHostname) - blieb Softwareerkennung aus,
|
||||||
|
// konnte trotzdem korrekt "adguard-home" gefunden werden. Nur der reine
|
||||||
|
// IP:Port-Nietenwert (keine Information vorhanden) wird übersprungen.
|
||||||
|
const isBareAddressFallback = /^[\d.:]+$/.test(service.suggestedDisplayName);
|
||||||
|
if (isBareAddressFallback) continue;
|
||||||
try {
|
try {
|
||||||
const match = await findBestIconMatch(nameToMatch);
|
const match = await findBestIconMatch(service.suggestedDisplayName);
|
||||||
if (match) service.favicon = match;
|
if (match) {
|
||||||
|
service.favicon = match;
|
||||||
|
// Ein eindeutiger Icon-Datenbank-Treffer ist selbst ein starkes
|
||||||
|
// Erkennungssignal - auch wenn Titel/Software-Erkennung nichts
|
||||||
|
// Brauchbares geliefert haben (z. B. bei einer reinen
|
||||||
|
// Client-seitig-gerenderten Login-Seite ohne Server-Titel).
|
||||||
|
service.visible = true;
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// Icon-Datenbank nicht erreichbar (kein Internetzugang o. ä.) - der
|
// Icon-Datenbank nicht erreichbar (kein Internetzugang o. ä.) - der
|
||||||
// Scan soll deswegen nicht fehlschlagen, einfach ohne Favicon weiter.
|
// Scan soll deswegen nicht fehlschlagen, einfach ohne Favicon weiter.
|
||||||
|
|||||||
@@ -60,7 +60,11 @@ export const SOFTWARE_SIGNATURES: SoftwareSignature[] = [
|
|||||||
{ name: "Jellyfin", category: "Medien", matches: (i) => bodyContains(i, /jellyfin/i) },
|
{ name: "Jellyfin", category: "Medien", matches: (i) => bodyContains(i, /jellyfin/i) },
|
||||||
{ name: "Nextcloud", category: "Cloud", matches: (i) => bodyContains(i, /nextcloud/i) },
|
{ name: "Nextcloud", category: "Cloud", matches: (i) => bodyContains(i, /nextcloud/i) },
|
||||||
{ name: "Pi-hole", category: "DNS", matches: (i) => bodyContains(i, /pi-?hole/i) },
|
{ name: "Pi-hole", category: "DNS", matches: (i) => bodyContains(i, /pi-?hole/i) },
|
||||||
{ name: "AdGuard Home", category: "DNS", matches: (i) => bodyContains(i, /adguard/i) },
|
{
|
||||||
|
name: "AdGuard Home",
|
||||||
|
category: "DNS",
|
||||||
|
matches: (i) => bodyContains(i, /adguard/i) || titleMatches(i, /adguard/i),
|
||||||
|
},
|
||||||
{ name: "UniFi Network", category: "Netzwerk", matches: (i) => bodyContains(i, /unifi/i) },
|
{ name: "UniFi Network", category: "Netzwerk", matches: (i) => bodyContains(i, /unifi/i) },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user