import Foundation /// Macht aus dem, was jemand eintippt, eine Adresse, die antwortet. /// /// Jellyfin hat kein Verzeichnis wie plex.tv — die Adresse kommt vom Nutzer. /// Und die tippt niemand vollständig: „192.168.1.50" ohne Schema, ohne Port, /// oder „medien.example.com" ohne „https://". Dieser Typ rät nicht **eine** /// Ergänzung, sondern nennt die plausiblen in der Reihenfolge, in der sie es /// wahrscheinlich sind; der Aufrufer probiert sie durch und nimmt die erste, /// die sich als Jellyfin-Server ausweist. /// /// Die Reihenfolge ist der ganze Inhalt dieser Datei, und sie ist nicht /// beliebig: eine IP-Adresse im eigenen Netz spricht fast nie HTTPS, ein /// Domänenname fast immer. public enum JellyfinAddress { /// Der Standardport eines Jellyfin-Servers. public static let defaultPort = 8096 public static func candidates(for input: String) -> [URL] { var text = input.trimmingCharacters(in: .whitespacesAndNewlines) while text.hasSuffix("/") { text.removeLast() } guard !text.isEmpty else { return [] } // Wer ein Schema hinschreibt, meint es auch so. Daran wird nichts // ergänzt — sonst landet eine Anfrage unverschlüsselt, obwohl jemand // ausdrücklich „https" getippt hat. if text.contains("://") { return URL(string: text).map { [$0] } ?? [] } // IPv6 in eckigen Klammern: hier wird nicht geraten, weil die // Doppelpunkte sonst als Port gelesen würden. if text.hasPrefix("[") { return ["http://\(text)", "https://\(text)"].compactMap(URL.init(string:)) } let authority = String(text.split(separator: "/", maxSplits: 1).first ?? "") let host = String(authority.split(separator: ":").first ?? "") let hasExplicitPort = authority.contains(":") && Int(authority.split(separator: ":").last ?? "") != nil if hasExplicitPort { // Port genannt, Schema nicht: erst unverschlüsselt, weil ein // eigener Port fast immer ein Server ohne Zertifikat ist. return ["http://\(text)", "https://\(text)"].compactMap(URL.init(string:)) } // Eine reine Zahlenadresse, ein Bonjour-Name oder ein Wort ohne Punkt // — alles Dinge, die es nur im eigenen Netz gibt. let isLocalLooking = host.allSatisfy { $0.isNumber || $0 == "." } || host.hasSuffix(".local") || !host.contains(".") let forms = isLocalLooking ? ["http://\(withDefaultPort(text))", "http://\(text)", "https://\(text)"] : ["https://\(text)", "http://\(text)", "http://\(withDefaultPort(text))"] return forms.compactMap(URL.init(string:)) } /// Hängt den Standardport an — vor einen etwaigen Pfad, nicht dahinter. private static func withDefaultPort(_ text: String) -> String { guard let slash = text.firstIndex(of: "/") else { return "\(text):\(defaultPort)" } return "\(text[text.startIndex..