MusicBee UPnP Plugin Hilfe

Neuerungen

2.0.9 - 2026-08-23

Der Update-Hinweis öffnet seine Seiten in Ihrer Sprache

Was: Die Links Was ist neu und Herunterladen im Update-Hinweis öffnen jetzt die Plugin-Seiten in der Sprache von MusicBee, anstatt auf Englisch.

Warum: Diese beiden Links schränkten die Sprache auf eine von vier ein – Englisch, Französisch, Spanisch oder Deutsch – bevor sie an die Website gesendet wurden, sodass alle anderen die englische Seite erhielten, selbst wenn eine Übersetzung davon existierte. Sie übergeben jetzt die Sprache von MusicBee unverändert und lassen die Website entscheiden, was sie bereitstellt, was der daneben befindliche Hilfe-Button schon immer getan hat.

2.0.8 - 2026-08-22

Das Plugin stellt sich nun den Apps und Geräten, die es in Ihrem Netzwerk entdecken, korrekt vor, und die Einstellungen der Geräteprofile sind wieder ausgerichtet.

Ihre Geräte zeigen den richtigen Hersteller, das richtige Modell und die richtige Version an

Was: Wenn eine Steuerungs-App, ein Telefon oder ein Fernseher MusicBee in Ihrem Netzwerk findet, präsentiert es dieses Plugin nun als von yaiol erstellt, verweist auf die eigene Website des Plugins, beschreibt es als alle drei Rollen abdeckend – Server, Player und Renderer – und meldet die tatsächlich installierte Version.

Warum: Jedes UPnP-Gerät gibt an, wer es hergestellt hat und was es ist, und Steuerungs-Apps zeigen dies als Identität des Geräts an. Dieses Plugin kündigte immer noch die Details des ursprünglichen Plugins an, von dem es abgezweigt wurde: den Namen eines anderen Autors, die Website von MusicBee anstelle seiner eigenen und eine Modellnummer, die seit der allerersten Veröffentlichung bei "1.0" eingefroren war. Von Ihrem Telefon aus gab es keine Möglichkeit zu erkennen, mit welchem Plugin Sie sprachen, geschweige denn, welche Version davon. Diese Details stammen nun vom Plugin selbst, sodass die neben dem Gerät angezeigte Version bei jedem Update korrekt bleibt.

Die Einstellungen der Geräteprofile sind wieder ausgerichtet

Was: Auf der Registerkarte „Geräteprofile“ teilen sich die Beschriftungen und ihre Felder eine linke Kante und sind gleichmäßig angeordnet, und der Abtastratenbereich wird als eine einzige Zeile angezeigt.

Warum: Die Felder waren im Laufe der Zeit durch das Hinzufügen von Optionen auf der Registerkarte auseinandergedriftet, und die Beschriftung „bis“ des Abtastratenbereichs war auf dem daneben liegenden Feld gelandet – lesbar, sobald man wusste, was sie sagte, aber beim ersten Anblick verwirrend.

2.0.7 - 2026-08-08

Größere Tracks behalten ihren Titel und ihren Positionsschieberegler

Was: Ein größerer Track, der von einem Telefon gesendet wird – eine lange FLAC-, eine hochauflösende oder DSD-Datei – zeigt jetzt seinen richtigen Titel an und kann wie ein kleinerer Track verschoben werden. Zuvor wurden einige davon stattdessen über das Netzwerk abgespielt, mit einer Webadresse anstelle des Titels und einem Schieberegler, der nichts bewirkte.

Warum: Das Plugin wartet auf seine lokale Kopie, bevor es startet, aber es entschied im Voraus, ob es sich lohnte, auf eine Datei zu warten, basierend auf ihrer Größe. Das war eigentlich eine Schätzung, wie schnell Ihr Netzwerk ist, was es nicht wissen kann: Ein 65 MB großer Track wurde als zu groß eingestuft und war eine Sekunde später mit dem Download fertig – bequem innerhalb der Wartezeit, die es bereits aufgegeben hatte. Es überwacht jetzt einfach den Download. Solange er noch ankommt, wartet das Plugin, egal wie lange es dauert; es gibt nur auf, wenn die Übertragung tatsächlich ins Stocken gerät, was es jetzt schneller bemerkt als die alte feste Verzögerung.

2.0.6 - 2026-08-03

Von einem Telefon gesendete Alben werden jetzt ohne Unterbrechung zwischen den Titeln abgespielt, und Internetradio wird als Radio erkannt, anstatt als ungewöhnlich langes Lied behandelt zu werden.

Alben werden ohne Unterbrechungen abgespielt

Was: Wenn Sie ein ganzes Album von Ihrem Telefon senden, spielt MusicBee jetzt ohne Pause von einem Titel zum nächsten – so bleiben Live-Aufnahmen, DJ-Sets und durchgehende klassische Werke zusammen.

Warum: Der Standard erlaubt einer steuernden App zu sagen „hier kommt als Nächstes“, was eine nahtlose Verbindung ermöglicht. Diese Anweisung wurde überhaupt nicht akzeptiert, sodass die App den kommenden Titel nirgendwo platzieren konnte und ihn so ankündigte, als wäre er der aktuelle – die Ursache des in der vorherigen Version behobenen Albumproblems. Sie wird jetzt ordnungsgemäß akzeptiert: Der nächste Titel wird abgerufen, während der aktuelle noch abgespielt wird, und der eigene Player von MusicBee überquert die Grenze.

Internetradio wird als Radio erkannt

Was: Ein an MusicBee gesendeter Live-Sender wird als Stream abgespielt und niemals heruntergeladen.

Warum: Das Herunterladen einer Sendung ist sinnlos – sie hat kein Ende, und es gibt nichts, worin man springen könnte – aber das Plugin hatte zuvor keine Möglichkeit, sie von einer Musikdatei zu unterscheiden, also begann es mit dem Abrufen und stoppte, sobald der Download eine feste Größe überschritt. Die steuernde App gibt an, welches der beiden sie sendet, und das wird jetzt direkt gelesen. Keine Einstellung, kein Raten.

Lange hochauflösende Titel behalten ihre Kopie

Was: DSD-Dateien und lange 24-Bit-Aufnahmen können jetzt wie jeder andere Titel durchsucht werden.

Warum: Sie wurden durch die oben genannte Größenbeschränkung erfasst – ein 20-minütiger hochauflösender Satz oder ein 10-minütiger DSD-Titel überschritten diese beide – sodass ihre Kopie aufgegeben wurde und der Positionsschieberegler genau für das Material nicht mehr funktionierte, das am ehesten es wert war, durchsucht zu werden. Da Radio ordnungsgemäß identifiziert wird, ist keine Größenbeschränkung erforderlich.

2.0.5 - 2026-08-03

Zwei Korrekturen für die Steuerung von MusicBee über ein Telefon: Die Lautstärke bedeutet jetzt an beiden Enden dasselbe, und das Übertragen eines ganzen Albums funktioniert auch nach dem ersten Titel weiter.

Die Lautstärke auf Ihrem Telefon entspricht der Lautstärke in MusicBee

Was: Wenn Sie die Lautstärke auf Ihrem Telefon auf Maximum stellen, erreicht sie jetzt das Maximum in MusicBee, und die eigene Einstellung von MusicBee wird auf dem Telefon korrekt zurückgelesen.

Warum: Das Plugin teilte der steuernden App nie mit, wie hoch die maximale Lautstärke war, sodass jede App raten musste. Eine davon legte sich auf 69 fest, was bedeutete, dass ihre 100 % nur 69 % in MusicBee erreichten, während MusicBees 100 % auf dem Telefon als 144 % zurückkamen – und die Lautstärketasten des Telefons konnten nie ganz das Maximum erreichen. Der Renderer gibt den Bereich nun klar an, sodass beide Enden über dieselbe Skala sprechen.

Das Übertragen eines Albums behält seine Titel und seinen Positionsschieberegler bei

Was: Jeder Titel eines von einem Telefon gesendeten Albums zeigt jetzt seinen richtigen Titel an und kann durchgespult werden, nicht nur der erste.

Warum: Eine steuernde App kündigt den nächsten Titel einen Bruchteil einer Sekunde nach dem aktuellen an, und diese Ankündigung brach die Kopie ab, die für den gleich abzuspielenden Titel abgerufen wurde – so fielen die meisten Titel stillschweigend auf die Wiedergabe über das Netzwerk zurück, wodurch sowohl der Titel als auch die Möglichkeit, herumzuspringen, verloren gingen. Kopien für mehrere Titel werden jetzt nebeneinander gehalten, sodass eine Ankündigung die verwendete nicht mehr abbrechen kann.

2.0.4 - 2026-08-02

Musik, die von einem Telefon oder einem anderen Server an MusicBee gesendet wird, verhält sich jetzt wie ein echter Titel: Sie können darin navigieren, und der richtige Titel wird sofort angezeigt. Außerdem ein Fix für Hi-Fi-Streamer, die sich als ein kombiniertes Gerät präsentieren.

Navigieren Sie durch einen von anderswo gesendeten Titel

Was: Das Ziehen des Positionsschiebers funktioniert jetzt für einen Titel, der von Ihrem Telefon, einem NAS oder einem anderen Medienserver gesendet wurde. Um dies zu ermöglichen, lädt MusicBee eine Kopie des Titels in einen temporären Ordner herunter, während er abgespielt wird, und spielt diese Kopie ab. Dies dauert in einem Heimnetzwerk etwa eine Sekunde, die Kopie wird gelöscht, sobald Sie einen anderen Titel senden, und alle Überreste werden beim nächsten Start von MusicBee gelöscht.

Warum: MusicBee kann etwas, das es über das Netzwerk abhört, starten und stoppen, aber es kann nicht darin navigieren – so schien der Schieberegler zu springen und glitt dann ohne Erklärung direkt an seine ursprüngliche Position zurück. Das Abspielen einer gewöhnlichen Datei auf Ihrer eigenen Festplatte beseitigt die Einschränkung vollständig, anstatt sie zu umgehen.

Korrekter Titel und Länge von der ersten Note an

Was: Ein Titel, der von einer App gesendet wird, die ihren Dateien keine gewöhnliche Dateierweiterung gibt, zeigt jetzt sofort seinen echten Titel und seine Länge an, anstatt als lange Webadresse zu erscheinen.

Warum: MusicBee identifiziert einen Titel – und findet seine Tags – anhand der Dateierweiterung, und einige Player geben Adressen ohne jegliche Erweiterung aus. Die lokale Kopie trägt immer die richtige, sodass der Titel erkannt wird, egal wie die sendende App ihn nennt.

Ein Sprung, der nicht gemacht werden kann, wird jetzt angezeigt

Was: Wenn der Renderer tatsächlich nicht zum angeforderten Punkt springen kann, wird die steuernde App darüber informiert und meldet dies.

Warum: Zuvor antwortete sie ungeachtet dessen "erledigt", sodass der Schieberegler eine Sekunde später zurückglitt, ohne dass erklärt wurde, warum. Eine ehrliche Ablehnung ist einfacher zu handhaben als eine stille.

Kombinierte Hi-Fi-Streamer werden korrekt gelesen

Was: Wenn MusicBee auf ein Gerät ausgibt, das sich als eine kombinierte Einheit präsentiert – ein Marantz- oder Denon-Streamer, bei dem der Player in einer Herstellerhülle neben einem Medienserver sitzt –, liest das Plugin jetzt die eigenen Details des Players anstelle der des Medienservers.

Warum: Es hatte zuvor die falsche Hälfte des Geräts gefragt, welche Audioformate es verarbeiten konnte, erhielt keine brauchbare Antwort und fuhr fort, ohne jemals zu prüfen – genau die Hardware, bei der die Formatverarbeitung am wichtigsten ist. Die Modellbeschreibung eines Geräts wird jetzt auch bei der Zuordnung zu einem Geräteprofil berücksichtigt; sie wurde zuvor von der falschen Stelle gelesen und verworfen.

2.0.3 - 2026-08-02

Die Play-to-Rolle wächst: MusicBee kann jetzt Musik empfangen, die sich noch nicht in seiner Bibliothek befindet – eine Datei auf Ihrem Telefon, auf einem NAS, auf einem anderen Server – anstatt nur Titel, die es bereits besitzt.

Musik abspielen, die von Ihrem Telefon gesendet wurde, nicht nur aus Ihrer eigenen Bibliothek

Was: Wenn Sie eine Steuerungs-App wie Symfonium oder BubbleUPnP verwenden, um Musik an MusicBee zu senden, muss der Titel nicht mehr aus der eigenen Bibliothek von MusicBee stammen. Eine Datei, die auf dem Telefon selbst, auf einem NAS oder auf einem anderen Medienserver gespeichert ist, wird jetzt abgespielt. Titel und Länge stammen von der App, die sie gesendet hat, sodass der Titel korrekt angezeigt wird, obwohl MusicBee die Datei noch nie gesehen hat.

Warum: Die Play-to-Rolle wurde für den Fall entwickelt, dass Sie die Bibliothek dieses PCs von Ihrem Telefon aus durchsuchen und auf einen Song tippen – der Titel war bereits auf dem PC, sodass MusicBee einfach seine eigene Datei abspielte. Alles, was von woanders kam, wurde stillschweigend verworfen, was die Funktion für den ebenso natürlichen Fall, Musik vom Telefon zu den guten Lautsprechern zu übertragen, nutzlos machte.

Ein Titel, der nicht abgespielt werden kann, wird entsprechend gemeldet

Was: Wenn der Renderer das, was ihm gesendet wurde, tatsächlich nicht abspielen kann, meldet er dies nun an die sendende App zurück.

Warum: Zuvor antwortete er auf alles mit "erhalten", sodass die Steuerungs-App fortfuhr und auf Wiedergabe drückte. Da nichts tatsächlich geladen war, startete MusicBee den Titel neu, der zuvor übrig geblieben war – und wenn diese Datei fehlte, beschwerte es sich, dass seine Quelle nicht gefunden werden konnte. Der Fehler nannte einen nicht verwandten Titel und wies nicht auf das eigentliche Problem hin.

Das Senden eines neuen Titels während der Pause spielt diesen Titel jetzt ab

Was: Wenn MusicBee pausiert ist und Ihre Steuerungs-App etwas Neues sendet, beginnt der neue Titel.

Warum: Die Wiederaufnahme hatte Vorrang vor dem Laden, sodass der pausierte Titel dort fortgesetzt wurde, wo er aufgehört hatte, und der gerade ausgewählte Titel ohne ein Wort verworfen wurde.

2.0.2 - 2026-08-01

Suchen ist das Thema: Es funktioniert jetzt nach Künstler, liefert die richtigen Ergebnisse und ist in einer großen Bibliothek schnell. Außerdem gibt es eine neue Möglichkeit, die Zufallswiedergabe Ihrer Steuerungs-App zu steuern, und eine Korrektur für drei Schaltflächen, die ins Leere führten.

Die Suche nach Künstler funktioniert jetzt tatsächlich

Was: Die Suche nach einem Künstler über Ihre Steuerungs-App liefert jetzt die Musik dieses Künstlers. Die Suche gleicht sowohl den Künstler des Titels als auch den Albumkünstler des Albums ab, sodass eine Kompilation gefunden wird, egal ob Sie den Namen des Interpreten oder den Namen eingeben, unter dem das Album abgelegt ist.

Warum: Eine Künstlersuche wurde zuvor fälschlicherweise als „gib mir alles dieser Art“ interpretiert – der eingegebene Künstler wurde verworfen und die gesamte Bibliothek zurückgegeben, sodass eine Suche, die ein paar hundert Titel hätte finden sollen, Zehntausende zurückgab. Das Abgleichen nur eines der beiden Künstlerfelder hätte stillschweigend die Hälfte der Ergebnisse verloren, daher werden beide überprüft.

Suchergebnisse werden korrekt paginiert

Was: Das Scrollen durch eine lange Liste von Suchergebnissen bewegt sich jetzt durch diese. Jede Seite, zu der Sie scrollen, ist die Seite, die Sie erhalten.

Warum: Der Server beantwortete früher jede Anfrage mit den ersten paar Ergebnissen, während er die vollständige Trefferzahl meldete, sodass eine App, die nach mehr scrollte, immer dieselben Elemente erhielt und nie das Ende erreichte.

Die Suche ist in einer großen Bibliothek viel schneller

Was: Eine Suche führt jetzt eine einzige Abfrage für den gesamten Ergebnissatz aus und liest nur die Tags der Seite, die Sie gerade betrachten.

Warum: Jede Seite führte zuvor die Abfrage erneut gegen die Bibliothek aus und lud dann die Tags jedes Treffers – Tausende davon – um ein Dutzend anzuzeigen. Bei einer großen Sammlung führte dies dazu, dass jedes Scrollen eine Pause verursachte. Die Ergebnisse werden auch verworfen, wenn die Bibliothek aktualisiert wird, sodass eine Bearbeitung niemals veraltete Daten liefert.

Richten Sie Ihre Zufallswiedergabe auf einen Filter aus

Was: Eine neue Einstellung Zufällige Wiedergaben aus auf der Registerkarte „Bibliotheksoptionen“. Lassen Sie sie auf Alle Musik und die Ordner Zufällige Titel / Zufällige Alben Ihrer Steuerungs-App verhalten sich wie zuvor; wählen Sie einen Ihrer MusicBee-Filter und jede zufällige Anfrage zieht stattdessen aus diesem Filter. Versteckte Filter werden ebenfalls angeboten.

Warum: Ein Zufallswiedergabeordner fragt nach einem Ausschnitt von „allem“, und es ist die einzige Anfrage, die keinen Hinweis darauf enthält, was Sie gemeint haben – daher zog sie immer aus der gesamten Bibliothek, gesprochenes Wort und alles. Hier sagen Sie, was „alles“ bedeutet. Das Öffnen eines Zufallswiedergabeordners innerhalb eines Filters auf dem Gerät mischt diesen Filter weiterhin: Eine Wahl, die Sie beim Browsen treffen, gewinnt über die Einstellung.

Hilfe, GitHub und Update-Prüfung erreichen echte Seiten

Was: Die Schaltflächen Hilfe und GitHub im Einstellungsdialog sowie die automatische Prüfung auf eine neue Version öffnen jetzt die Seiten, die sie benennen.

Warum: Alle drei wurden aus einer verkürzten Form des Plugin-Namens erstellt, unter der nie eine Seite existiert hat, sodass jede stillschweigend fehlschlug – die Schaltflächen schienen nichts zu tun und die Update-Prüfung meldete nie etwas, egal wie lange eine neue Version bereits verfügbar war.

2.0.1 - 2026-07-26

Eine Runde von Wiedergabe- und Browsing-Korrekturen, konzentriert auf Podcasts und auf die Controller-Apps (wie BubbleUPnP), die die Wiedergabe und das Shuffle steuern.

Podcasts beginnen ohne Pause zu spielen

Was: Eine heruntergeladene Podcast-Episode gibt jetzt ihre tatsächliche Länge und Dateigröße im Voraus an, direkt aus der Datei auf der Festplatte in die Medienmetadaten übernommen.

Warum: Ohne eine angegebene Dauer scannt ein Controller wie BubbleUPnP jedes Mal, wenn Sie auf Wiedergabe drücken, den gesamten Audiostream erneut, nur um herauszufinden, wie lang die Episode ist – die Wiedergabe begann also erst nach einer merklichen Pause. Da die Länge nun bekannt ist, startet sie sauber.

Podcasts erscheinen, wenn Sie nach Künstler browsen

Was: Der Name einer Podcast-Sendung wird jetzt als ihr Künstler abgelegt – gespiegelt in die Felder „Künstler“ und „Albumkünstler“ (und deren Sortiervarianten), genau wie er bereits das Feld „Album“ füllt.

Warum: Ein Browsing-Pfad, der nach einem Künstlerfeld gruppiert, fand früher den Künstler jedes Podcasts leer und endete in einer leeren Ebene. Die Sendung selbst als Künstler zu behandeln – konsistent mit der Behandlung als Album – bedeutet, dass diese Pfade jetzt die Episoden statt nichts erreichen.

„Zuletzt gespielt“ und Casting funktionieren direkt nach einem Neustart

Was: Das direkte Abspielen eines Podcasts, Hörbuchs, Inbox- oder Radiotracks – ohne vorheriges Browsen, wie es die „Zuletzt gespielt“-Liste und Cast-Ziele von BubbleUPnP tun – schlägt nicht mehr fehl. Das Plugin lädt den Track jetzt bei Bedarf, wenn er per ID angefordert wird.

Warum: Diese Listen fordern einen Track direkt nach dem Neustart von MusicBee an, bevor etwas durchsucht wurde, sodass das Plugin die ID nie gesehen hatte und mit „Ungültige ID“ antwortete. Es lädt jetzt die relevanten Quellen bei dieser ersten direkten Anfrage zwangsweise und findet den Track.

„Zufällige Titel“ und „Zufällige Alben“ liefern Ergebnisse

Was: Die Shuffle-Ordner „Zufällige Titel“ und „Zufällige Alben“ von BubbleUPnP, die einen zufälligen Ausschnitt der gesamten Bibliothek anfordern, sind jetzt gefüllt.

Warum: Dies sind Suchen ohne passenden Titel, und das Plugin beantwortete sie zuvor aus einer leeren internen Liste, sodass sie immer nichts anzeigten. Sie werden jetzt – korrekt paginiert – über denselben On-Demand-Abfragepfad bereitgestellt, den der Rest des Browsings verwendet.

Alben mit einem leeren Tag listen ihre Titel auf

Was: Das Öffnen eines Albums, das nach einem leeren Wert gruppiert wurde – zum Beispiel Inbox-Titel, die kein Jahr tragen – zeigt jetzt seine Titel an.

Warum: Die Übereinstimmung, die die Titel eines Albums sammelt, behandelte „dieses Tag ist leer“ als „keine Übereinstimmung“, sodass jedes Album, das aus einem leeren Feld gebildet wurde, zu nichts führte. Ein leerer Gruppenwert stimmt jetzt korrekt mit den Titeln überein, die ihn teilen.


2.0.0 - 2026-07-22

Dies ist die erste öffentliche Version des Open-Source-Forks yaiol des MusicBee UPnP-Plugins. Sie wird in zwei Teilen präsentiert: alles, was neu in diesem Fork ist, und dann die Korrekturen und Verbesserungen, die am ursprünglichen Plugin vorgenommen wurden. Jeder Punkt behält die Was / Warum-Form des internen Feature-Katalogs des Projekts bei, sodass die Begründung für jede Änderung auf der Seite steht, nicht nur die Änderung selbst.

Neu in diesem Fork

MediaRenderer – Wiedergabe an MusicBee

N01 – MusicBee als Wiedergabe-Renderer

Was: Normalerweise funktioniert dieses Plugin in eine Richtung: Ein Telefon oder ein anderes Gerät durchsucht die MusicBee-Bibliothek und spielt die Musik auf sich selbst ab. Diese Funktion fügt die entgegengesetzte Richtung hinzu – sie lässt MusicBee der Player sein. Von einer Controller-App auf Ihrem Telefon (wie BubbleUPnP) können Sie Ihr Desktop-MusicBee als Wiedergabegerät auswählen und es dann von Hand steuern: Wiedergabe, Pause, Stopp, Vor- oder Zurückspringen, zu einem Punkt im Titel springen und die Lautstärke ändern oder stummschalten.

Warum: Es verwandelt Ihr Telefon in eine Fernbedienung für die Musik, die sich bereits auf Ihrem PC befindet. Setzen Sie sich auf die Couch, durchsuchen Sie Ihre Bibliothek auf dem Telefon, tippen Sie auf einen Titel, und er kommt aus den Lautsprechern, die an Ihrem Desktop angeschlossen sind – mit voller Kontrolle von Ihrem Sitzplatz aus. Das ursprüngliche Plugin hat dies nie als funktionierende Funktion ausgeliefert.

Einschalten: Es ist standardmäßig ausgeschaltet, da das Einschalten es jedem Gerät in Ihrem Heimnetzwerk ermöglicht, die Wiedergabe auf Ihrem PC zu starten. Sie aktivieren es mit einem Kontrollkästchen auf der Registerkarte „Allgemein“ des Einstellungsdialogs. Die drei Rollen des Plugins haben jeweils ein eigenes Kontrollkästchen dort – meine Bibliothek teilen (Server), andere zu mir spielen lassen (Renderer) und auf andere Geräte spielen (Kontrollpunkt) – und der Dialog zeigt nur die Einstellungsregisterkarten an, die die von Ihnen aktivierten Rollen tatsächlich benötigen, sodass Sie nie mit Optionen konfrontiert werden, die für Sie nicht relevant sind.

Ihre Geräte unterscheiden: Sie können dem Renderer einen beliebigen Namen geben (er beginnt als „MusicBee (yaiol)“). Dieser Name erscheint in der Liste der Wiedergabeziele Ihres Telefons, sodass Sie, wenn mehr als ein PC MusicBee ausführt, erkennen können, welcher welcher ist. Eine Namensänderung wird sofort wirksam, ohne Neustart.

Bestmöglicher Klang bei der Wiedergabe an sich selbst: Wenn Sie MusicBees eigene Bibliothek von Ihrem Telefon aus durchsuchen und einen Titel an dasselbe MusicBee zurücksenden, erkennt das Plugin, dass es aufgefordert wird, eine seiner eigenen Dateien abzuspielen, und spielt sie einfach direkt von Ihrer Festplatte ab. Das Ergebnis ist exakt und sofort – bit-perfekt, mit MusicBees eigenem Equalizer und Lautstärkeanpassung – anstatt das Audio sinnlos ins Netzwerk und direkt zurück an sich selbst zu senden.

Privater Betrieb: Die drei Rollen arbeiten unabhängig voneinander, sodass Sie den Renderer einschalten können, während die Bibliotheksfreigabe deaktiviert bleibt. In dieser „nur Renderer“-Einrichtung bleibt Ihre Bibliothek vollständig vor dem Netzwerk verborgen – nur das Wiedergabeziel wird angekündigt – und MusicBee wird niemals anbieten, an sich selbst abzuspielen.


Wiedergabeverhalten

N02 – 5.1 FLAC wird nicht automatisch heruntergemischt

Was: Die Kanalanzahl-Begrenzung in MediaServerDevice.GetEncodedFile war If StereoOnly OrElse Not isPcmData Then channelCount = 2. Die Klausel Not isPcmData mischte jede Nicht-PCM-Transkodierung (FLAC, MP3, AAC, Ogg) stillschweigend auf Stereo herunter, unabhängig von der Kanalanzahl der Quelle, was 5.1-fähige Renderer bei 5.1 FLAC-Quellen nutzlos machte. Jetzt schließt die zweite Klausel FLAC aus: Not isPcmData AndAlso encoder.Codec <> FileCodec.Flac. FLAC 5.1 wird durchgelassen; MP3/AAC/Ogg erzwingen weiterhin Stereo, da MusicBees Kommandozeilen-Encoder für diese Formate 2-Kanal-Eingabe erwarten.

Warum: Der ganze Sinn der Transkodierung einer 5.1 FLAC-Quelle in FLAC-Ausgabe ist es, den Mehrkanal-Mix zu erhalten. Stilles Heruntermischen machte die FLAC-Transkodierungsoption für Surround-Hören nutzlos. Mit N02 funktioniert es richtig.


Architektur

Die strukturelle Änderung, die den Fork auf einer großen Bibliothek praktikabel macht – im ursprünglichen Plugin nicht vorhanden.

N03 – Lazy (On-Demand) Browse-Baum

Was: Das ursprüngliche Plugin baute den gesamten Browse-Baum beim MusicBee-Start auf – jede Spur aufzählen, vollständiges Library_GetFileTags pro Datei, die gesamte Container-Hierarchie zusammenstellen – bevor der HTTP-Port geöffnet wurde. Bei einer echten Bibliothek (50.000+ Spuren, 5400 Podcast-Episoden, Hunderte von Sendern) sind das Minuten des Kaltstarts, und der Baum bleibt für immer im RAM, einschließlich Zweigen, die kein Client jemals öffnet. Dieser Fork baut nichts im Voraus auf: Der Root-Knoten zeigt einen L:-präfixierten Platzhalter pro Endpunkt (L:music, L:podcast, L:filter:…); jede Ebene wird nur berechnet, wenn ein Client in sie hineinbrowsed (LazyBrowseEnsureLazyEndpointInMemory → Caches pro Ebene), und Bibliotheksänderungsbenachrichtigungen löschen die Caches (SetLibraryDirty).

Warum: Der Kaltstart ist im Wesentlichen sofort – der HTTP-Port ist geöffnet, wenn MusicBee die Plugin-Initialisierung beendet hat – und der Speicher bleibt proportional zu dem, was durchsucht wurde, nicht zur Bibliotheksgröße. Kompromiss: Das erste Browsen in einen Endpunkt zahlt seine Ladekosten; der Wiedereintritt wird bis zur nächsten Bibliotheksänderung zwischengespeichert. Dies ist die Grundlage, auf der alles andere basiert. Vollständige Notizen: FIXES.md.


Netzwerk & Robustheit

Härtung des HTTP-Server-Bindungspfads. Das ursprüngliche Plugin stirbt stillschweigend, wenn sein Port nicht verfügbar ist.

N04 – Selbstheilende HTTP-Port-Bindung

Was: Der HTTP-Server des Plugins stirbt nicht mehr, wenn sein konfigurierter Port nicht verfügbar ist. Drei miteinander verbundene Änderungen:

  1. Automatischer Fallback bei Bindungsfehler. HttpServer.Start versucht den konfigurierten Port und scannt bei SocketException bis zu 20 Ports nach oben nach dem ersten freien. Der tatsächlich gebundene Port wird in einem neuen Plugin.boundServerPort aufgezeichnet, und alles, was den Server bewirbt – SSDP LOCATION URLs (NOTIFY + M-SEARCH-Antwort), die Geräte-URL (PrimaryHostUrl), die Router-Portweiterleitung und die SSDP/Control-Point-Selbstfilter – liest jetzt boundServerPort anstelle von Settings.ServerPort. UPnP-Clients entdecken den echten Port über SSDP, sodass ein verschobener Port für Renderer transparent ist.
  2. Benutzerbenachrichtigung. Wenn ein Fallback auftritt (der gespeicherte Port ist nicht der verwendete), informiert eine lokalisierte MessageBox (WarnPortInUse) den Benutzer, welcher Port tatsächlich dient und dass Geräte ihn trotzdem finden werden – da das Plugin headless läuft und eine Nachricht im Dialog nur von jemandem gesehen würde, der bereits ein Problem vermutete.
  3. Neustart-Wiederherstellung. RestartServer (der Neustartpfad zum Speichern der Einstellungen) dereferenzierte Plugin.controller / Plugin.server blind. Wenn die anfängliche Initialise vor deren Erstellung einen Fehler auslöste (genau das, was ein fehlgeschlagener Bindungsversuch verursachte), führte das nächste Speichern der Einstellungen zu einer NullReferenceException – was ein halb totes Plugin hinterließ. Es erstellt und startet sie jetzt neu, wenn Nothing, sodass das Speichern eines funktionierenden Ports das Plugin ohne einen vollständigen MusicBee-Neustart wiederbelebt.

Warum: Der Auslöser war ein echter Benutzerfall. Der alte Standardport 49382 liegt im Windows-dynamischen Bereich (49152-65535), wo Hyper-V/WSL2/Docker/WinNAT große Blöcke reservieren, die sich bei jedem Booten verschieben – so schlug die Bindung mit WSAEACCES („Zugriff verboten“) auf einem Rechner fehl, auf dem sie monatelang funktioniert hatte. Das Ändern des Standards auf einen freien Port kollidierte dann mit Serviio (einem separaten DLNA-Server, der bereits auf dem neuen Port lief) und schlug mit WSAEADDRINUSE fehl. Jeder Fehler wurde in Initialise verschluckt, was das Plugin stillschweigend sterben ließ und dann beim nächsten Speichern der Einstellungen eine NRE auslöste. Nach N04 heilt eine Portkollision sich selbst – der Server läuft auf dem nächsten freien Port weiter, der Benutzer wird informiert, und Clients entdecken ihn neu – anstatt das gesamte Plugin zum Absturz zu bringen.

Implementierung:

  • Standardport verschoben 493829779 (unterhalb des dynamischen Bereichs, sodass Windows ihn nie automatisch reserviert; kein bekannter Media-Server-Standard) in allen drei ServerPort-Deklarationen + dem Fallback bei Einstellungs-Parse-Fehler.
  • Plugin.boundServerPort (neues gemeinsames Feld) enthält den aktiven Listening-Port; activeServerPort bleibt der konfigurierte Snapshot, damit die Logik des „Neustart erforderlich“-Badges bei einem Fallback nicht fälschlicherweise ausgelöst wird.
  • HttpServer.PortScanRange = 20; der Scan stoppt beim ersten erfolgreichen TcpListener.Start() und wirft die letzte Ausnahme nur, wenn alle Versuche fehlschlagen.
  • Neuer EN-Ressourcenschlüssel WarnPortInUse (Übersetzungen folgen dem Locale-Pass zur Veröffentlichungszeit).

N05 – SSDP-Ankündigungen über die Multicast-Gruppe (VPN / Punkt-zu-Punkt)

Was: SSDP-Ankündigungen werden an die UPnP-Multicast-Gruppe (239.255.255.250) gesendet, anstatt an eine IP-Broadcast-Adresse. Der harmlose Fehler „cannot access a disposed object“, der protokolliert wird, wenn eine SSDP-Suchantwort mit einem Server-Neustart kollidiert, wird ebenfalls unterdrückt.

Warum: Bei Punkt-zu-Punkt-/VPN-Netzwerkadaptern gilt IP-Broadcast nicht – der alte Broadcast-Sendefehler führte zu „invalid argument“ und Ankündigungen wurden verpasst, sodass das Plugin für Clients auf diesen Links unsichtbar war. Die Ankündigung an die richtige Multicast-Gruppe behebt die Erkennung auf genau diesen Adaptern.

Bibliotheksnavigation

Diese wurden in diesem Fork ausgeliefert und sind nicht im ursprünglichen Plugin enthalten. Sie entstanden durch das tatsächliche Durchsuchen der eigenen Ausgabe des Plugins von echten UPnP-Clients.

N06 – Filterbasierte Bibliotheksfreigabe

Was: MusicBees Filter-Tabs (.xautopf-Dateien im MusicBee-Ordner des Benutzers) werden zu UPnP-Root-Containern in der Plugin-Bibliothek. Die Titel jedes Filters können dann in einer Hierarchie von AlbumArtistSort → Album → Tracks durchsucht werden.

Warum: Benutzer mit kuratierten MusicBee-Filtern (z. B. „5-Sterne-Titel“, „Zuletzt hinzugefügt“, „Klassik → Barock“) erwarten, diese beim Durchsuchen des Plugins von einem UPnP-Client aus zu finden. Das ursprüngliche Plugin zeigte nur den rohen Bibliotheksbaum an.


N07 – SortAlbumArtist-Feldverdrahtung

Was: Das Plugin liest jetzt MusicBees MetaDataType 165 (Sort Album Artist) und verwendet es zum Gruppieren/Sortieren von Künstlern in Browse-Ansichten.

Warum: Hi-Fi-Browser und Audiophile verwenden Sortier-Künstlernamen („Beethoven, Ludwig van“ anstelle von „Ludwig van Beethoven“), um Bibliotheken zu organisieren. Standarderwartung für ernsthafte Hörer. Fehlt in beiden Upstreams.


N08 – Umgang mit mehrwertigen AlbumArtist-Feldern

Was: Wenn das AlbumArtist-Feld eines Albums mehrere Künstler enthält, die durch "; " getrennt sind (z. B. "yaiol; Ars Ricercata"), erscheint der Titel jetzt unter jedem Künstler in den Browse-Ansichten, nicht unter einem einzigen Frankenstein-Künstler, der die Namen kombiniert.

Warum: Kollaborative Alben und Kompilationen müssen unter jedem Kollaborateur erscheinen. Ohne dies sind die Hälfte der Suchpfade zum Auffinden des Albums unterbrochen.


N09 – Album-Container-Artwork (upnp:albumArtURI)

Was: Album-Container-Knoten in DIDL-Browse-Antworten enthalten jetzt ein upnp:albumArtURI-Element, das auf das Albumcover verweist.

Warum: Ohne dies zeigt jedes Album in der Browse-Ansicht eines UPnP-Clients ein generisches Symbol anstelle des Albumcovers. Visueller Hinweis zur Navigation; von jedem modernen Hi-Fi-Browser erwartet.


N10 – Titelreihenfolge innerhalb von Filteralben

Was: Titel innerhalb eines filter-exponierten Albums werden jetzt nach Disc-Nummer, dann nach Titelnummer sortiert.

Warum: Standard-Albumreihenfolge. Ohne explizite Sortierung kamen die Titel in der Reihenfolge zurück, in der der Filter sie zufällig zurückgab – meist zufällig aussehend.


N11 – Korrektur des Wiedergabelisten-Ordnerbaums

Was: Die Funktion LoadLibraryPlaylists (ursprünglich von Steven Mayall, ~2014) konnte nicht in neu erstellte Wiedergabelisten-Ordner absteigen. Die erste Wiedergabeliste in jedem Ordner sowie alle Unterordner landeten verwaist auf der Stammebene.

Warum: Elf Jahre lang im ursprünglichen Plugin vorhanden. Innerhalb von 30 Sekunden nach dem Öffnen von BubbleUPnP und dem Klicken auf Wiedergabelisten sichtbar. In yaiol durch korrektes Rekursieren in neu erstellte Ordner während des Baumaufbaus behoben.


N12 – Bereinigung von XML-illegalen Steuerzeichen

Was: Jeder Titel mit einem Tag, der ein C0-Steuerzeichen enthielt (z. B. 0x19 von einem schlechten Kodierungsdurchlauf – UTF-8 → Latin-1 → Zurückschneiden von 0x99 zu 0x19), führte dazu, dass die gesamte Browse-Antwort mit Action Failed fehlschlug, sobald der schlechte Titel in einen paginierten Batch gelangte.

Warum: XML 1.0 verbietet die meisten C0-Steuerzeichen, und XmlWriter wirft eine Ausnahme, wenn es aufgefordert wird, eines zu schreiben. Im ursprünglichen Plugin vorhanden. Behoben durch Entfernen ungültiger Zeichen an jedem Library_GetFileTags-Ausgangspunkt über XmlConvert.IsXmlChar.


N13 – Radio-Liste deterministisch über paginiertes Browse

Was: Das Browsen für den Radio-Container fiel in den generischen Dateilisten-Zweig, der bei jedem Aufruf files.Sort(AlbumFileComparer) aufrief. Radio-Einträge haben leere Album-/Disc-/Track-Tags, sodass jeder Vergleich 0 zurückgab – List(Of T).Sort ist instabil und erzeugt bei jedem Aufruf eine andere Reihenfolge. UPnP-Kontrollpunkte paginieren (BubbleUPnP holt 0..15, dann 16..Ende); zwischen den beiden Aufrufen wurde die Liste neu gemischt, sodass einige Sender auf beiden Seiten erschienen (Duplikate) und einige auf keiner (fehlend) – bei jeder Aktualisierung zufällig aussehend.

Warum: Im ursprünglichen Plugin vorhanden (dessen Autor browsed Radio nie über UPnP). Hier behoben mit einem dedizierten ContainerCategory.Radio-Zweig in Browse, keine Sortierung pro Aufruf; radioFiles wird einmal beim Laden nach Titel sortiert (stabil). Paginierte Browse sieht jetzt eine deterministische Reihenfolge; Seite 1 und Seite 2 sind disjunkt.


N14 – UPnP-Suche nach Album-Klasse gibt Album-Container zurück

Was: Die UPnP-Suche nach Album-Klasse-Abfragen (upnp:class = "object.container.album.musicAlbum", z. B. BubbleUPnPs „Zufällige Alben“) gab die vollständige Titelliste anstelle von Album-Containern zurück, sodass der Client null Alben anzeigte. Der ursprüngliche Handler analysierte nur geklammerte Kriterien und gab dann alle Titel aus, unabhängig von der angeforderten Klasse.

Warum: Hier behoben – Album-Klasse-Abfragen enumerieren jetzt eindeutige Alben (gruppiert nach AlbumArtist+Album) und geben jedes als ordnungsgemäßen musicAlbum-Container mit Cover-Art aus, adressierbar über den virtuellen ID-Bereich Salb<idx>, sodass der Client in ein Ergebnis eintauchen und es abspielen kann.


N15 – Funktionierende, bereichsbezogene UPnP-Suche mit Durchklicken

Was: Das Original warb mit keinen Suchfunktionen (GetSearchCapabilities gab leer zurück), sodass Clients sich weigerten, überhaupt eine Suche zu senden; und das alte Backend las aus musicFiles, das in der Ära des Lazy-Baums dauerhaft leer war. Dieser Fork bewirbt die tatsächlich durchsuchbaren Eigenschaften, implementiert Titel nach Titel und Alben nach Titel gegen die Lazy-Bibliothek (HandleLazySearch), begrenzt die Abfrage auf den aktuellen Zweig des Clients, wenn eine echte Container-ID gesendet wird (ersetzt andernfalls L:music, damit Top-Bar-Suchen keinen Podcast-/Radio-/Hörbuch-Lärm hereinziehen), und macht Album-Ergebnisse über synthetische Ssrch_alb_*-IDs anklickbar, die ein Browse-Frühzweig wieder den Titeln des Albums zuordnet. (Der Teil der Album-Klasse-Ergebnisse als Container ist N14.)

Warum: Die Suche in BubbleUPnP wechselte von „Bibliothek unterstützt keine Suche“ zu nützlichen, bereichsbezogenen, abspielbaren Ergebnissen. Vollständiges Design + abgelehnte Ansätze: SEARCH.md.


N16 – UPnP-Cache-Invalidierung (SystemUpdateID)

Was: Das Original gab eine konstante SystemUpdateID=0 zurück – den UPnP ContentDirectory Cache-Invalidierungsvertrag – sodass spezifikationskonforme Clients (BubbleUPnP) die Bibliothek als sich nie ändernd behandelten: veraltete Browse-Ergebnisse, 404-Thumbnails nach einer URL-Schemaänderung und den „MusicBee zweimal neu starten, um Änderungen zu sehen“-Tanz. Dieser Fork initialisiert SystemUpdateID aus Epochensekunden beim Laden (sodass jeder Neustart streng vor dem letzten liegt) und erhöht sie bei jeder Bibliotheksmutation und Einstellungsänderung (SetLibraryDirty / ResetCacheBumpSystemUpdateId).

Warum: Clients übernehmen Bearbeitungen, neue Dateien und Einstellungsänderungen bei ihrem nächsten Browse zuverlässig. Bekannte Einschränkung: Abonnierte Clients erhalten den neuen Wert nicht aktiv über GENA (als zukünftige Arbeit geparkt); sie sehen ihn immer noch bei ihrem nächsten Browse.


N17 – Podcast-Abonnement-Artwork

Was: Podcast-Kacheln zeigten keine Bilder – jede /PodcastThumbnail/-Anfrage führte zu einem 404-Fehler. Zwei gestapelte Fehler: Die Auflösungskette überprüfte nie MusicBees tatsächlichen Artwork-Cache (%LocalAppData%\MusicBee\InternalCache\Subscriptions\<name>.jpg, von wo die Desktop-UI lädt), und die HTTP-Schicht entging+kleinschreibung verstümmelte den Feed-URL-Routenschlüssel bis zu seinem letzten Pfadsegment. Dieser Fork löst Artwork aus MBs InternalCache auf und leitet Lookups über einen URL-sicheren Slug, der die HTTP-Schicht intakt überlebt (PodcastSlug / podcastSubIdBySlug).

Warum: Abonnement-Artwork wird jetzt in Browse-Ansichten gerendert (alle 22 zuvor 404-fehlerhaften Anfragen werden aufgelöst).


N18 – Hierarchisches (abgegrenztes) Tag-Browsing

Was: Jedes Feld kann auf der Registerkarte „Bibliotheksoptionen“ als hierarchisch markiert und mit einem einstelligen Trennzeichen versehen werden (ein Feldauswähler + Trennzeichenfeld mit Hinzufügen/Entfernen, das in den Plugin-Einstellungen gespeichert wird). Wenn Sie Gruppierung auf / und einen Wert wie Jazz/Cool Jazz setzen, wird dies als Jazz › Cool Jazz durchsucht, anstatt als ein einziger flacher Eintrag. Titel, die genau an einem Zweig getaggt sind (nur Jazz), erhalten einen eigenen [Jazz]-Knoten, sodass nichts verborgen bleibt, ein Zweig mit einem einzigen Kind kollabiert von selbst, und ; wird als Trennzeichen abgelehnt, da es MusicBees eigenes Mehrwert-Trennzeichen ist.

Warum: Tiefe Tag-Taxonomien, die ein Benutzer bereits in einem einzigen Feld kodiert hat (Genre-Bäume, Stimmungs-Hierarchien, „Klassik/Barock/Konzert“), werden endlich als der Baum durchsucht, den das Tag beschreibt, anstatt als eine flache Wand von schrägstrichgetrennten Zeichenketten, die der Benutzer von Anfang bis Ende lesen muss.


N19 – Einzelner Root-Pfad, beschriftet nach seinem Gruppierungsfeld

Was: Ein einzelner Browse-Pfad im Root wird nach seinem Gruppierungsfeld (z. B. „Genre“) und nicht nach seinem vollständigen Kurzpfad beschriftet, passend dazu, wie zusammengeführte Erstfeldgruppen benannt werden.

Warum: Der Browse-Baum liest sich konsistent – eine Benennungsregel, ob ein Root-Eintrag allein steht oder mit Geschwistern zusammengeführt wurde (N20) – anstatt dass ein einzelner Root-Eintrag einen ausführlichen internen Pfad anzeigt, während seine zusammengeführten Nachbarn einen sauberen Feldnamen anzeigen.


N20 – Browse-Pfade zusammenführen, die ein erstes Feld teilen

Was: Zwei Browse-Pfade, die dasselbe erste Feld teilen – „Genre / Sort Album Artist“ und „Genre / Podcast People“ – werden zu einem einzigen Genre-Root-Ordner zusammengeführt, der zuerst die Genre-Werte auflistet und sich dann in die beiden Ansichten aufteilt, anstatt zwei fast identische „Genre / …“-Einträge nebeneinander im Root.

Warum: Ein Benutzer mit mehreren verwandten Ansichten, die unter einem gemeinsamen Feld verschachtelt sind, sah den Root mit fast identischen Top-Level-Einträgen überladen. Das Zusammenführen hält den Root lesbar und gruppiert die verwandten Ansichten dort, wo sie hingehören – unter ihrem gemeinsamen Feld.


N21 – Kategorisierte Browse-Pfade (Standard / Radio / Podcast)

Was: Jeder Browse-Pfad ist nach Kategorie typisiert – Standard, Radio oder Podcast. Die Vorlagenliste ist in diese drei Abschnitte gruppiert, der Feldauswähler jeder Vorlage bietet nur die Felder an, die die Daten dieser Kategorie tatsächlich liefern können, und eine Vorlage kann nur auf passende Knoten im Ansichtsbaum angewendet werden (inkompatible Knoten werden ausgegraut und können nicht angekreuzt werden). Die reservierten Radio- und Podcast-Vorlagen können nicht gelöscht werden, sodass ihr Kategorieabschnitt nie verschwindet.

Warum: Ohne die Typisierung könnte ein Benutzer ein Layout erstellen, das stillschweigend leer bleibt – ein Radiosender hat kein „Album“, eine Podcast-Episode hat keinen „Albumkünstler“ – und dies erst durch das Browsen zu einem leeren Ordner von einem UPnP-Client aus entdecken. Die Einschränkung des Feldmenüs und der Anwendungsziele auf die realen Daten der Kategorie macht leere Layouts unmöglich zu erstellen.


N22 – Podcasts nach Veröffentlichungsjahr gruppieren

Was: Das Veröffentlichungsdatum jeder Podcast-Episode wird eingelesen, sodass ein Podcast-Browse-Pfad mit einer Jahresebene Episoden nach Jahr gruppiert, anstatt sie unter einem einzigen „Unbekannt“ zusammenzufassen.

Warum: Große Podcast-Abonnements werden nach Jahr navigierbar wie der Rest der Bibliothek, anstatt dass jede Episode in einem undatierten Haufen landet, weil das Plugin das Veröffentlichungsdatum pro Episode nie beachtet hat.


N23 – Gruppierungsebenen mit Einzelergebnissen zusammenführen

Was: Eine Gruppierungsebene, die zu einem einzigen Wert führt – eine Record Type-Ebene, die nur „LP“ für einen Künstler anzeigt, der nur LPs gemacht hat, oder eine Buchstabenebene mit einem einzigen Buchstaben – wird automatisch übersprungen, wodurch der Benutzer direkt zu ihren Inhalten gelangt.

Warum: Das Durchsuchen eines Ordners, der genau einen Ordner enthält, ist reine Reibung. Das Zusammenführen der Einzelauswahl-Ebene entfernt den unnötigen Klick, ohne zu ändern, was der Benutzer erreichen kann.


N24 – Jahresgruppierung/-suche anhand des MusicBee-Datumsfeldes

Was: Die Jahresbedingung fragt MusicBees vollständiges Datumsfeld „Jahr“ nicht mehr mit einem bloßen vierstelligen Wert ab, und die fest codierte Jahresfeld-Aliasierung ist verschwunden, sodass jedes Gruppierungsfeld jetzt generisch aus der Pfaddefinition aufgelöst wird.

Warum: Für Bibliotheken, deren Jahres-Tag ein vollständiges Datum enthält, lieferte die Gruppierung oder Suche nach Jahr zuvor nichts – die vierstellige Abfrage passte nie zum vollständigen Datumsfeld. Das Abfragen des richtigen Feldes lässt die Jahresgruppierung und -suche die Titel wieder finden.


N25 – Separate „Jahr“ und „Jahr (jjjj)“ Gruppierungsfelder

Was: Album-Gruppierungs- und Browse-Pfade zeigen jetzt beide eigenen Jahresfelder von MusicBee an – Jahr (das vollständige Datumstag) und Jahr (jjjj) (nur das vierstellige Jahr) – sodass der Benutzer bei der Definition einer Album-Gruppierung oder eines Browse-Pfads eines davon auswählen kann.

Warum: Die beiden Felder bedeuten in MusicBee unterschiedliche Dinge, und das Zusammenfassen verlor diese Unterscheidung. Das Anzeigen beider ermöglicht es einem Benutzer, alle Veröffentlichungen eines Jahres zusammenzufassen (jjjj) oder die genaue Datumsreihenfolge beizubehalten (vollständiges Jahres-Tag), wie beabsichtigt.


N32 – Angeheftete Filter und Wiedergabelisten nach Art im Root gruppiert

Was: Ein angehefteter Filter erscheint jetzt direkt unter dem Ordner Filter im Browse-Root, und eine angeheftete Wiedergabeliste direkt unter dem Ordner Wiedergabelisten, anstatt dass alle angehefteten Elemente in einem einzigen Klumpen am Ende des Roots gesammelt werden. Jede angeheftete Verknüpfung sitzt bei ihrer eigenen Art.

Warum: Wenn ein Benutzer mehr Verknüpfungen anheftet, wird ein einzelner nachlaufender Klumpen aus gemischten Filtern und Wiedergabelisten schwerer zu scannen und trennt jede Verknüpfung von dem Ordner, zu dem sie gehört. Das Gruppieren angehefteter Elemente unter ihrer eigenen Kategorie hält den Root lesbar und jede Verknüpfung neben den Dingen, zu denen sie gehört.

Einstellungsdialog & Paketierung

N26 – Gliederter Einstellungsdialog

Was: Die Seite „Einstellungen“ erhielt ein Navigationslayout auf der linken Seite mit Abschnitten: Allgemein / Wiedergabe / Bibliothek / Geräteprofile / Diagnose.

Warum: Das Original war eine einzige lange, flache Liste jeder Einstellung – gut für den Entwickler, der es gebaut hat, verwirrend für alle anderen. Die Gliederung gruppiert verwandte Optionen und lässt den Dialog eher wie moderne App-Einstellungen wirken.


Assembly + Plugin-Umbenennung (keine F-ID – Verpackungshinweis)

Was: Die kompilierte DLL heißt mb_UPnP_yaiol.dll und das Plugin meldet sich als „MusicBee UPnP (yaiol)“. Unterscheidet sich von der ursprünglichen mb_Upnp.dll.

Warum: Benutzer können yaiol neben dem ursprünglichen Plugin installieren und das Verhalten nebeneinander vergleichen.


Badge-System – Anzeige des Laufzeitstatus (Mechanismus hinter F40)

Was: Ein generisches UI-Muster zur Anzeige wichtiger Laufzeitbedingungen als sichtbare farbige Badges im Einstellungsdialog. Aktuelle Instanzen:

  • ⚠ Max Conn (N04) – wird ausgelöst, wenn die maximale Verbindungsbegrenzung seit dem Start von MusicBee mindestens einmal erreicht wurde. Sticky Session Flag Plugin.MaxConnectionsHit. Wird in WaitOnSendBarrier gesetzt, wenn kein Slot frei ist.
  • ⚠ Neustart erforderlich – wird ausgelöst, wenn eine gespeicherte Einstellung einen MusicBee-Neustart erfordert, um wirksam zu werden. Sticky Session Flag Plugin.RestartRequired. Wird im Speicher-Handler des Dialogs gesetzt, wenn der neue persistierte Wert vom Laufzeit-Snapshot abweicht (Plugin.activeMaxConnections, Plugin.activeServerPort, Plugin.activeIpAddress). Neustart-erforderliche Einstellungen sind auf diejenigen beschränkt, die wirklich nicht hot-reloaded werden können – HTTP-Server-Bindungsparameter und das SemaphoreSlim, das einmal bei der Initialisierung erstellt wird.

Warum: Die Protokolldatei des Plugins ist für technische Benutzer zur Fehlersuche in Ordnung, aber ein nicht-technischer Benutzer, der auf „Gerät klingt falsch“ oder „Wiedergabe ist langsam“ starrt, wird niemals Diagnose → Protokoll anzeigen öffnen. Badges erfassen die Fälle, in denen der Benutzer wissen muss, dass etwas passiert ist, und zeigen es beim nächsten Öffnen des Plugins an – auffindbar, ohne etwas lesen zu müssen.

Wiederverwendbar für die Zukunft:

  • Profil-Fehlübereinstimmung erkannt (Geräte-User-Agent stimmte nie mit einem Profil überein, fiel auf Generisch zurück).
  • NextURI-Backoff ausgelöst (F13 – lückenlose Wiedergabe für die Sitzung auf einem fehlerhaften Gerät deaktiviert).
  • Bibliotheks-Scan fehlgeschlagen / teilweise.
  • Renderer-Verbindung während der Sitzung verloren.
  • Jede andere Bedingung, bei der „einmal passiert, Benutzer sollte wissen“ besser ist als „still unter 1000 anderen Zeilen protokolliert“.

Implementierungskonventionen:

  • Badge-Beschriftungen befinden sich auf Dialogebene (nicht innerhalb eines Panels), sodass sie unabhängig davon sichtbar sind, in welchem Abschnitt sich der Benutzer befindet.
  • Positioniert entlang der unteren Zeile in der Nähe von Speichern/Abbrechen (aktuell: y=410 horizontal gestapelt).
  • Jedes Badge hat ein entsprechendes Sticky Session Flag in Plugin, das auf True wechselt, wenn die Bedingung auftritt, und nur bei einem MusicBee-Neustart zurückgesetzt wird.
  • Ressourcen: <Condition>Badge (Beschriftungstext, mit ⚠ präfixieren) + <Condition>BadgeTip (Tooltip, der Ursache + Abhilfe erklärt).
  • Für „gespeicherte Einstellung erfordert Neustart“-Badges, nehmen Sie einen Laufzeit-Snapshot bei Plugin.Initialise() und vergleichen Sie ihn mit Settings.* nach Settings.SaveSettings() im Dialog-Speicher-Handler.

N27 – Abbrechen verwirft Pfad-/Vorlagenbearbeitungen

Was: Änderungen, die an Pfaden und Vorlagen im Einstellungsdialog vorgenommen wurden, werden jetzt verworfen, wenn der Benutzer auf „Abbrechen“ klickt, anstatt stillschweigend angewendet zu bleiben, und jede während der Sitzung entfernte reservierte Vorlage wird neu erstellt. (Vorlagen werden ansonsten live gespeichert, während sie bearbeitet werden – es gibt keinen separaten „Speichern“-Button auf der Registerkarte „Pfade“.)

Warum: Abbrechen sollte Abbrechen bedeuten. Zuvor fand ein Benutzer, der mit Pfad-/Vorlagenänderungen experimentierte und zurücktrat, die Änderungen bereits übernommen, ohne eine Möglichkeit, sie rückgängig zu machen, außer jede manuell neu zu erstellen.


N28 – Literale Ampersands im Feldauswahlmenü

Was: Ein Feld, dessen Name „&“ enthält – z. B. „Stimmung & Kontext“ – rendert das Ampersand im Feldauswahlmenü wörtlich, anstatt es als Alt-Mnemonic-Präfix zu schlucken.

Warum: Feldnamen mit einem Ampersand wurden falsch angezeigt (das Zeichen verschwand und der nächste Buchstabe wurde zu einem Beschleuniger), was den Menüeintrag schwer erkennbar machte.


N29 – Stabiler, unübersetzter Titel des Einstellungsfensters

Was: Der Titel des Einstellungsfensters ist auf den Markennamen „MusicBee UPnP Plugin“ festgelegt und variiert nicht mehr mit der Oberflächensprache; die sprachspezifische DialogTitle-Zeichenfolge wurde aus jedem Locale-Bundle entfernt.

Warum: Ein Fenstertitel, der sich je nach Sprache änderte, war eine übersetzbare Oberfläche ohne Nutzen – der Titel ist ein Markenzeichen. Das Festlegen hält ihn überall stabil und konsistent.

Lokalisierung

Das ursprüngliche Plugin ist nur auf Englisch verfügbar. Dieser Fork ist vollständig lokalisierbar – jede benutzeroberflächennahe Zeichenfolge durchläuft ein Ressourcen-Bundle, und das Plugin erkennt automatisch die UI-Sprache von MusicBee.

N30 – Mehrsprachige Benutzeroberfläche (Übersetzungen ausstehend)

Was: Die Lokalisierungsmechanismen sind vollständig und werden ausgeliefert. Localisation.vb liest die in MusicBee ausgewählte Sprache aus MusicBee3Settings.ini (<SystemLanguage> Endonym) und wendet die passende .NET-Kultur auf den Thread an, sodass My.Resources.Resources.* die lokalisierte Zeichenfolge zurückgibt. Jedes benutzeroberflächennahe Label/Button/Nachricht ist mit einem Ressourcenschlüssel verbunden (Designer-Steuerelemente über ApplyDesignerExtras + sync-en-locale.js; Laufzeit-Strings wie WarnPortInUse manuell hinzugefügt). Was noch nicht erledigt ist, ist die eigentliche Übersetzung: Es existiert nur das englische Quell-Bundle (Resources.resx) – die Satelliten-Bundles für die anderen Sprachen werden in einem Batch-Durchlauf erstellt, wenn das Plugin funktionsfähig ist (stückweises Übersetzen, während Strings noch geändert werden, verschwendet Aufwand).

Zielsprachen (die von MusicBee selbst angebotenen, 1:1 durch endonymToCulture abgeglichen, sodass das Plugin MusicBees Sprache automatisch folgt):

Arabisch (ar) Tschechisch (cs) Deutsch (de) Griechisch (el)
Spanisch (es) Französisch (fr) Ungarisch (hu) Italienisch (it)
Koreanisch (ko) Niederländisch (nl) Norwegisch (nb) Polnisch (pl)
Portugiesisch BR (pt-BR) Portugiesisch PT (pt-PT) Schwedisch (sv) Türkisch (tr)
Ukrainisch (uk) Russisch (ru) Japanisch (ja) Vereinfachtes Chinesisch (zh-CN)
Traditionelles Chinesisch (zh-TW) Englisch (en, Quelle)

Variantenrichtlinie (gemäß der Arbeitsbereichs-Locale-Regel): PT und ZH sind in separate Bundles aufgeteilt, da Vokabular/Schrift tatsächlich divergieren (pt-BR/pt-PT, zh-CN/zh-TW). EN ist ein einzelnes Bundle – MusicBees „English(US)“ (en-US) fällt über die .NET-Kulturkette auf en zurück, sodass kein separates US-Bundle erstellt wird. ES und FR sind ebenfalls Single-Locale.

Warum: Die Einstellungen eines UPnP-Plugins („kein rohes PCM verwenden“, „Little-Endian PCM erzwingen“, Port-Fallback-Warnungen) sind in der Muttersprache kryptisch genug. Das Befolgen der eigenen UI-Sprache von MusicBee – anstatt Englisch zu erzwingen – ist der Unterschied zwischen einem Tool, das ein nicht-englischer Benutzer konfigurieren kann, und einem, das er nicht kann. Keiner der Upstreams hat dies versucht.


N31 – Hilfe-Link öffnet sich in der vollständigen Oberflächensprache

Was: Das Öffnen des Hilfe-Links vom Plugin aus berücksichtigt die vollständige Oberflächensprache des Benutzers (z. B. pt-BR, zh-CN), anstatt auf die Basissprache zurückzufallen, und sendet einen klareren Update-Check-Identifikator.

Warum: Ein Benutzer, der MusicBee in einer regionalen Variante (Brasilianisches Portugiesisch, Vereinfachtes Chinesisch) ausführte, wurde auf die Hilfeseite in der Basissprache weitergeleitet. Das Übertragen der vollständigen Kultur führt ihn auf die Hilfeseite in genau der Sprache, die er verwendet.

Korrekturen und Verbesserungen am ursprünglichen Plugin

Kernprotokoll & Wiedergabe

F01 – Aktualisierte Standard-DLNA-Geräteprofile

Was: Liefert neue Standardprofile für PlayStation 4, Xbox 360/One und modernes BubbleUPnP, mit Fähigkeitsflags (Sample-Raten, Bittiefen, Codecs), die widerspiegeln, was diese Geräte heute tatsächlich unterstützen.

Warum: Die Standardeinstellungen des ursprünglichen Plugins waren um 2014 eingefroren. PS4/Xbox/BubbleUPnP haben seitdem Hi-Res-Audio-Unterstützung erhalten. Out-of-the-box spielt eine Neuinstallation auf diesen Geräten erstklassig, ohne dass der Benutzer die Geräteprofileinstellungen ändern muss.


F02 – Steuergeräte, die MediaRenderer:3 bewerben

Was: Das Plugin prüft die UPnP-Dienstbeschreibung eines Renderers, um zu entscheiden, ob MusicBee ihn steuern kann. Das Original passte nur zu urn:schemas-upnp-org:device:MediaRenderer:1. Moderne Geräte bewerben :2 oder :3. F02 erweitert die Übereinstimmung.

Warum: Ohne dies erscheinen neuere Sonos-/WiiM-/Eversolo-Geräte einfach nicht als Ziele in MusicBees „Wiedergabe an“-Geräteliste – obwohl sie dasselbe Protokoll sprechen. Eine einzige String-Präfix-Übereinstimmung behebt dies und schaltet die gesamte moderne Gerätegeneration frei.


F03 – „Native Stream erzwingen“ pro-Profil-Option (Standard EIN)

Was: Wenn aktiviert, sendet das Plugin die ursprünglichen Dateibytes an das Gerät, ohne Transkodierung, DSP oder ReplayGain-Verarbeitung. Nur die vom Benutzer ausgewählte Rohdatei, Byte für Byte (abzüglich HTTP-Framing).

Warum: Laut Forenberichten ist dies der größte Gewinn bei der Wiedergabequalität. Hi-Fi-Benutzer, die teure Renderer kaufen, wünschen explizit eine bit-perfekte Ausgabe; jede DSP-Berührung macht den Sinn zunichte. Standardmäßig EIN, da die meisten modernen Geräte jeden Codec verarbeiten, den der Benutzer ihnen zugeworfen hat, und ReplayGain/EQ optional sein sollten. Es ist pro-Profil, sodass Sie die Transkodierung für eine alte Xbox beibehalten können, während Sie nativ an einen Hi-Fi-DAC senden.


F04 – „Transkodierung erzwingen“ pro-Profil

Was: Pro-Profil-Überschreibung, die jeden Stream an dieses Gerät durch den Transcoder zwingt, unabhängig von der nativen Codec-Unterstützung. Das Gegenteil von F03 (ForceNativeStream). Gegenseitig ausschließend mit F03 – die Benutzeroberfläche deaktiviert das andere automatisch, wenn eines aktiviert wird.

Warum: Ein einziger globaler Schalter wäre widersprüchlich mit dem pro-Profil ForceNativeStream (F03). Realer Fall: Gerät A ist ein Hi-Fi-DAC, der bit-perfekte native Streams wünscht; Gerät B ist ein alter AV-Receiver, der bei FLAC Probleme hat. Mit einem globalen Schalter müsste der Benutzer wählen – auf Kosten des anderen Geräts. Mit pro-Profil erhält jedes Gerät die richtige Antwort.

Implementierung:

  • StreamingProfile.ForceTranscoding As Boolean = False.
  • Persistenzschema auf v9 erhöht. Pre-v9-Dateien laden den alten globalen Wert einmal und kopieren ihn in alle Profile, wodurch das alte Verhalten durch das Upgrade erhalten bleibt.
  • UI: Aus dem Diagnosepanel entfernt, zum Abschnitt Geräteprofile neben ForceNativeStream hinzugefügt. Zwei-Wege-Ausschluss-Handler (CheckedChanged bei jedem deaktiviert den anderen vor dem Umschalten, um eine Endlosschleife zu vermeiden).
  • Entscheidungsstelle: Settings.ForceTranscodingstreamingProfile.ForceTranscoding in WriteAudioFileDIDL.

F05 – „Little-Endian PCM erzwingen“ pro-Profil

Was: PCM-Streams (L16/L24 Mime-Typen) sind laut Spezifikation Big-Endian. Einige Geräte erwarten fälschlicherweise Little-Endian und spielen weißes Rauschen ab, wenn sie korrekte Big-Endian-Daten erhalten. F05 schaltet die Byte-Reihenfolge pro-Profil um.

Warum: Ohne dies geben bestimmte Geräte eine Wand aus statischem Rauschen aus. Das Symptom ist dramatisch und die Ursache ohne Kenntnis der PCM-Kodierung unsichtbar – der Schalter bietet Benutzern eine Rate-und-Prüf-Lösung.


F06 – „Kein Raw PCM verwenden“ pro-Profil

Was: Wenn das Gerät angibt, rohes PCM zu unterstützen, verwendet das Plugin dies. Einige Geräte lügen – sie akzeptieren den SOAP-Handshake, verfälschen aber tatsächliche rohe PCM-Daten, während sie PCM, das in einem WAVE-Container verpackt ist, korrekt verarbeiten. F06 erzwingt PCM-over-Wave, unabhängig davon, was das Gerät bewirbt.

Warum: Speziell bestimmte Marantz-Modelle – sie bewerben rohes PCM, aber nur WAVE funktioniert. Ohne dies kommen rohe PCM-Streams verzerrt heraus, ohne Fehlermeldung.


F07 – „Content-Length“ pro-Profil

Was: Welchen Wert im HTTP Content-Length-Header senden. Vier Optionen:

  • Standard – tatsächliche Byte-Anzahl, wenn bekannt, weglassen, wenn unbekannt.
  • Keine – den Header niemals senden (nur Chunked Encoding).
  • Nur PCM – nur für rohes PCM senden; für alles andere weglassen.
  • FestUInt32.MaxValue - 8192 senden (ein Sentinel für „riesige unbekannte Länge“).

Warum: UPnP/DLNA-Geräte reagieren sehr unterschiedlich auf Content-Length. Einige benötigen eine genaue Zahl, einige hassen es bei Streams, einige benötigen einen Sentinel-Wert „wirklich groß“, um das Buffering aufrechtzuerhalten. Dies wurde später von nur PCM auf alle Ausgabeformate erweitert, da die gleichen Probleme bei transkodierten MP3/AAC-Streams auftraten.


F08 – „NextURI nicht löschen“ pro-Profil

Was: Normalerweise löscht das Plugin die in der Warteschlange befindliche NextURI des Geräts, wenn die Warteschlange leer ist (sendet SetNextAVTransportURI mit einer leeren URL). Einige Geräte (insbesondere Denon) interpretieren eine leere NextURI als „alles stoppen“ und beenden die Wiedergabe sofort. F08 verhindert, dass das Plugin sie jemals löscht.

Warum: Ohne dies erleben Denon-Besitzer, dass das Gerät mitten im Titel abbricht, wenn die Warteschlange leer ist. Wenn F08 aktiviert ist, behält das Gerät die veraltete NextURI im Speicher (harmlos – sie wird beim nächsten Mal, wenn etwas in die Warteschlange gestellt wird, einfach überschrieben).


F09 – FLAC als Transcode-Ausgabeformat

Was: Das Dropdown-Menü für das Transcode-Format in den Geräteprofilen bietet jetzt FLAC neben PCM 16/24, MP3, AAC, Ogg an. Die Auswahl leitet den BASS-Encoder über MusicBees Standard-FLAC-Konvertierungs-Befehlszeile (derselbe Mechanismus, den MP3/AAC/Ogg bereits verwenden).

Warum: Für Geräte, die FLAC gut verarbeiten, aber den Quell-Codec nicht dekodieren können (z. B. ein Eversolo, der MusicBees WMA-Bibliothek in FLAC konvertiert empfängt), bewahrt dies verlustfreie Qualität, wo MP3/AAC Audiodaten wegwerfen würden. Entsperrt N02 (5.1 Downmix-Steuerung), die ohne eine verlustfreie Transcode-Option nicht adressiert werden konnte.

Implementierung: Eine Zeile Ergänzung zum Select Case Codec-Block von Encoder.StartEncode – FLAC reiht sich bei MP3/AAC/Ogg in den Kommandozeilen-gesteuerten Zweig ein. Das UI-Dropdown erhält „FLAC“ als 6. Option. Die Lade-/Speicherzuordnung in SettingsDialog erweitert sich, um FileCodec.FlacSelectedIndex = 5 zu erkennen. Mime, DLNA-Typ und Encode-Funktion waren bereits in ItemManager.GetMimes / GetDlnaType / GetEncodeFeature aus früheren Arbeiten (F21, F26) verdrahtet.


Lückenlos (SetNextAVTransportURI)

F10 – SetNextAVTransportURI / NextURI Kern

Was: Echte lückenlose Wiedergabe. Wenn das Gerät in seiner UPnP-Dienstbeschreibung die Unterstützung für SetNextAVTransportURI bewirbt, reiht das Plugin den nächsten Titel auf dem Gerät vor dem Ende des aktuellen Titels vor. Das Gerät wechselt intern ohne hörbare Lücke zwischen den Titeln – was Sie auf einem CD-Player hören. Dies ist nicht der „kontinuierliche Stream“-Hack (der alles zu einem langen Stream verkettet und Metadaten pro Titel verliert).

Warum: Das Flaggschiff-Tier-2-Feature. Alben, die als kontinuierliche Live-Performance aufgenommen wurden (Live-Aufnahmen, klassische Sätze, DJ-Sets), klingen falsch, wenn es eine halbe Sekunde Stille zwischen den Titeln gibt. Dies richtig zu lösen, ist ein Flaggschiff-Feature, jetzt in diesem Fork.

Hinweise: Das in der Warteschlange befindliche Audio wird über den HTTP-Server des Plugins mit streamHandle=0 (Bibliotheks-Abrufmodus) bereitgestellt, was bedeutet, dass MusicBees Audio-Engine für den in der Warteschlange befindlichen Titel nicht im Loop ist. Kompromiss: ReplayGain/DSP/EQ-Effekte werden nicht auf den nächsten Titel angewendet. Akzeptabel, wenn „native Stream erzwingen“ aktiviert ist (der Standard).


F11 – „NextURI-Unterstützung deaktivieren“ pro-Profil

Was: Selbst wenn ein Gerät SetNextAVTransportURI bewirbt, zwingt dieses Kontrollkästchen das Plugin, diese Werbung zu ignorieren und auf die Wiedergabe von einem Titel nach dem anderen zurückzufallen.

Warum: Einige Geräte bewerben NextURI, haben aber eine fehlerhafte Implementierung (Abstürze, halbe Übergänge, Hänger). Anstatt jedes defekte Gerät zu reverse-engineeren, erhält der Benutzer einen Schalter zum „einfach hier ausschalten“.


F12 – NextURI-Lebenszyklus in der Wiedergabeliste

Was: Wenn MusicBee NowPlayingListChanged auslöst, bewertet das Plugin neu, was für einen lückenlosen Übergang in die Warteschlange gestellt werden sollte. Es fragt MusicBee nach dem neuen „nächsten“ Titel über NowPlayingList_GetNextIndex(1) + NowPlayingList_GetListFileUrl, vergleicht dies mit dem, was derzeit auf dem Gerät in der Warteschlange ist (verfolgt über das neue Feld nextPlaySourceUrl), und reiht es neu ein, wenn es sich geändert hat (oder löscht die Warteschlange, wenn MusicBee sagt, dass es keinen nächsten Titel gibt).

Warum: Ohne F12 spielte das Gerät eine veraltete NextURI weiter, wenn der Benutzer den in der Warteschlange befindlichen Titel entfernte/neu anordnete. Dies dauerte historisch mehrere Iterationen, da jede Listenmutation eine andere Behandlung erfordert – wir haben es vereinfacht, indem wir NowPlayingList_GetNextIndex vertrauten (das bereits Shuffle und Repeat-All-Wrap-Around berücksichtigt), sodass alle Varianten durch denselben Vergleich geleitet werden.

Implementierung:

  • Neues Feld nextPlaySourceUrl speichert die MusicBee-Bibliotheks-URL des in der Warteschlange befindlichen Elements (die Streaming-URL mit Handle-Suffix ist nicht mit einem Bibliothekspfad vergleichbar).
  • Neue Public Sub RefreshQueuedNextUri() auf MediaRendererDevice. Drei Ergebnisse: keine NextURI in der Warteschlange → keine Aktion; Warteschlange stimmt mit neuem „nächsten“ überein → keine Aktion; Warteschlange weicht ab → QueueNext mit der neuen URL aufrufen (oder QueueNext("") zum Löschen – was F08 DoNotClearNextUri berücksichtigt).
  • Verdrahtet in Plugin.ReceiveNotification unter NotificationType.NowPlayingListChanged.

F13 – NextURI-Fehler-Backoff

Was: Nach 4 aufeinanderfolgenden SetNextAVTransportURI-Fehlern auf demselben Gerät deaktiviert das Plugin die lückenlose Wiedergabe für dieses Gerät, bis MusicBee neu gestartet wird.

Warum: Wenn ein Gerät für NextURI wirklich defekt ist (intermittierende SOAP-Fehler, Netzwerkstörungen), würde das Plugin sonst bei jedem Titel weiter versuchen. F13 stoppt den Lärm und fällt stillschweigend auf die Wiedergabe von einem Titel nach dem anderen zurück.


F14 – Wiederholungsmodus + NextURI-Integration

Was: F14 teilt sich in zwei Fälle auf, die am F15-Übergangsdetektor in OnAvTransportStatusCheck behandelt werden:

  • Alle wiederholen: MusicBee übergibt die korrekte „Wrap“-URL (Titel 1 am Ende der Liste) an Plugin.QueueNext selbst. Es ist keine spezielle Plugin-Logik erforderlich – das Gerät wechselt dazu und der F15-Detektor ruft Player_PlayNextTrack wie gewohnt auf, wodurch MusicBees NPL-Index wieder auf 0 zurückgesetzt wird.
  • Einen wiederholen: MusicBee übergibt dieselbe Titel-URL an Plugin.QueueNext. Das Gerät wechselt dazu (neues Stream-Handle, gleiche Quelle). Der F15-Detektor fragt jetzt Player_GetRepeat() ab – wenn es RepeatMode.One ist, überspringt er den Player_PlayNextTrack-Aufruf, damit MusicBee den NPL-Index nicht vom sich wiederholenden Titel wegbewegt.

Warum: Ohne den Repeat-One-Skip würde der Aufruf von Player_PlayNextTrack beim lückenlosen Übergang MusicBee zum nächsten Titel in der Liste vorrücken (Repeat-One beeinflusst nur das automatische Vorrücken am Ende des Titels in der Player-UI – Nächster Titel bewegt sich immer vorwärts), was dem widerspricht, was Repeat-One bedeutet.

Wiedergabezähler-Vorbehalt: Im Repeat-One-Modus hängt die Erhöhung des Wiedergabezählers davon ab, dass MusicBee 3.7.9563+ die Schleifenwiedergabe bemerkt. Ältere MusicBee-Versionen spielen die lückenlose Wiederholung korrekt ab, verpassen aber die Erhöhung des Wiedergabezählers. Dokumentiert; nicht blockierend.


F15 – Zustandsmaschine zur Erkennung von Titelübergängen

Was: Wenn das Gerät intern vom aktuellen Titel zu NextURI wechselt, muss das Plugin dies bemerken und MusicBee anweisen, seinen aktuell spielenden Index vorzurücken. Andernfalls denkt MusicBee, es sei immer noch auf dem vorherigen Titel, und Wiedergabezähler / UI / Scrobbling geraten aus dem Takt.

Implementierung: Fragt GetPositionInfo.TrackURI bei jedem Status-Timer-Tick ab. Wenn die gemeldete URI mit der von uns über NextURI in die Warteschlange gestellten übereinstimmt, rufen wir Player_PlayNextTrack auf MusicBee auf und setzen suppressNextSoapCall, damit das resultierende PlayToDevice SetAVTransportURI nicht erneut sendet (was die lückenlose Wiedergabe unterbrechen würde).

Warum: Ohne F15 spielt das Gerät den nächsten Titel ab, aber MusicBees UI sagt, es sei immer noch auf dem vorherigen. Verwirrend, unterbricht Scrobbling, unterbricht die Wiedergabezählerverfolgung. Die Erkennung von Titelübergängen erfordert eine lange, pro-Renderer-Iteration, da jede Renderer-Marke ihre eigenen Eigenheiten hat, wann sie die URI-Änderung meldet (einige melden zuerst TRANSITIONING, einige springen direkt zu PLAYING mit neuer URI, einige haben eine kurze STOPPED-Phase dazwischen).

Hinweise: Unser erster Entwurf funktioniert auf BubbleUPnP-Renderer. Geräte-spezifische Randfälle bleiben in B6.


F16 – Pop-on-Gapless-Transition-Fix

Was: Der Knall tritt auf, wenn das Quellformat (Sample-Rate / Kanäle / Codec) des in der Warteschlange befindlichen Titels vom aktuell spielenden Titel abweicht, wodurch der DAC des Geräts gezwungen wird, sich beim Übergang neu zu synchronisieren. F16 fügt eine NextUri:FormatChange-Diagnose hinzu, die zur Warteschlangenzeit ausgelöst wird, wenn die Formate abweichen, und benennt beide Seiten – damit Benutzer, die Knallen hören, dies korrelieren können.

Die Diagnose weist auch auf die Abhilfe hin: Aktivieren Sie ForceTranscoding im Geräteprofil. Das homogenisiert jeden Titel auf einen einzigen Transcode-Codec/Sample-Rate/Bittiefe, wodurch der Quellformatunterschied vollständig eliminiert wird.

Warum für die eigentliche Transcode-to-Match-Fix verschoben: Die strukturelle Korrektur (den in der Warteschlange befindlichen Titel an das Format des spielenden Titels anzupassen) erfordert Änderungen am HTTP-Server-URL-Schema des Plugins – derzeit liefert /encode/{id}0.{ext} die in der Warteschlange befindliche Datei nativ. Eine zukünftige v2 von F16 würde pro-Format /encode/{id}0_{rate}_{depth}.{ext}-Routen hinzufügen und diese durch den Encoder leiten. Das ist eine größere architektonische Änderung, die sich lohnt, wenn ein echtes Gerät den Knall zeigt, nachdem ForceTranscoding nicht ausreicht.

Implementierung heute:

  • Das Feld lastSourceUrl verfolgt die aktuell spielende Quell-URL.
  • QueueNext liest FilePropertyType.SampleRate/Channels/Kind für den aktuellen und den in der Warteschlange befindlichen Titel und protokolliert NextUri:FormatChange bei Nichtübereinstimmung.

F17 – Fortschrittsbalken-Resynchronisation nach dem Suchen

Was: Die Funktion Seek() rief bereits nach einem erfolgreichen Seek-SOAP GetPlayPositionInformation() auf, was den Fall „überhaupt keine Resynchronisation“ behob. F17 schließt die verbleibende Drift von bis zu 1 Sekunde, die durch die 1-Sekunden-Quantisierung von UPnPs RelTime verursacht wird: Wenn die gemeldete Position des Geräts innerhalb von 1 Sekunde des vom Benutzer angeforderten Ziels liegt, vertraut das Plugin jetzt dem sub-sekundengenauen Wert des Benutzers anstelle der Kürzung des Geräts. Nur wenn das Gerät etwas dramatisch anderes meldet (>1s Abweichung), verwenden wir seinen Wert (die Suche landete woanders als angefordert, z. B. Snap-to-Keyframe bei einigen Codecs).

Warum: Ohne dies würde das Suchen nach 2:30.500, verankert an der „2:30“-Meldung des Geräts, dazu führen, dass der Fortschrittsbalken ~500ms hinter der Realität angezeigt wird. Nach F17 stimmt der Balken mit der Absicht des Benutzers für den üblichen In-Track-Scrub-Fall überein und respektiert immer noch die Meldung des Geräts für den Snap-to-Keyframe-Ausreißer.


F18 – Continuous-Stream / NextURI-Verriegelung

Was: Zwei Verriegelungen sind jetzt vorhanden:

  1. Laufzeit: QueueNext gibt False frühzeitig zurück, wenn Settings.ContinuousOutput aktiviert ist. Continuous-Stream ist ein eigener lückenloser Mechanismus (ein langer, verketteter Stream); das Senden von SetNextAVTransportURI zusätzlich dazu verwirrt das Gerät darüber, ob jeder Titel eine diskrete URI oder Teil des kontinuierlichen Flusses ist.
  2. UI: Wenn der Benutzer das globale Kontrollkästchen für den kontinuierlichen Stream aktiviert, wird forceNativeStream des aktuell angezeigten Profils automatisch deaktiviert. Continuous-Stream transkodiert immer, daher ist Force-Native in Kombination bedeutungslos.

Warum: Verhindert, dass der Benutzer zwei widersprüchliche lückenlose Mechanismen gleichzeitig aktiviert. Ohne F18 würde das Gerät sowohl eine kontinuierliche Stream-URI als auch eine NextURI für jeden nachfolgenden Titel erhalten, mit undefiniertem Verhalten je nach Renderer.


F19 – Leere NextURI-Fehler ignoriert

Was: Wenn SetNextAVTransportURI mit einer leeren URL aufgerufen wird (z. B. letzter Titel in der Liste), geben einige Geräte einen SOAP-Fehler zurück. F19 schluckt diese stillschweigend – protokolliert, aber nicht als Fehler weitergegeben.

Warum: Die Bedingung „kein nächster Titel“ ist normal, kein Fehler. Sie als fatal zu behandeln, verschmutzt das Protokoll und löst (in einigen Abläufen) Wiederholungsstürme aus.


Mime-Typen & DLNA-Metadaten

F20 – MP3-Mime → audio/mpeg

Was: Der standardkonforme MP3-Mime-Typ ist audio/mpeg, nicht audio/mp3. Letzteres ist eine häufige Fehlbezeichnung, die die meisten Geräte tolerieren, aber strengere Renderer lehnen sie ab.

Warum: Behebt stillschweigend die Wiedergabe auf strengeren Geräten, die dem Standard folgen. Die yaiol-Codebasis hatte dies bereits korrekt; keine Änderung erforderlich.


F21 – Mime-Typ-Reihenfolge: Nicht-x--Variante zuerst

Was: Wenn ein Gerät sowohl audio/flac als auch audio/x-flac bewirbt, gibt das Plugin zuerst die Nicht-x--Variante zurück. Dasselbe gilt für jeden Codec mit sowohl Standard- als auch experimentellen Mime-Typen.

Warum: Das x--Präfix kennzeichnet experimentelle/inoffizielle Mime-Typen. Einige Renderer verhalten sich mit der Standardform besser. Eine kleine Neuordnung, aber mit realer Auswirkung.


F22 – Opus-Mime-Typ-Unterstützung

Was: Erkennt Opus als streamfähigen Audio-Codec; sendet audio/opus-Mime beim Bereitstellen von Opus-Titeln.

Warum: Opus ist heute weit verbreitet (moderner Kompromiss-Codec für Sprache/Musik). Ohne F22 würde das Plugin die Übertragung von Opus-Dateien selbst an Geräte, die sie verarbeiten, verweigern.


F23 – Monkey Audio (APE) Quelldatei-Unterstützung

Was: Erkennt .ape-Dateien als gültigen Quell-Codec für Streaming/Transkodierung.

Warum: APE ist ein verlustfreies Format mit einer Nische, aber treuen Benutzerbasis. Das Hinzufügen kostet wenig und schaltet die Bibliothek für diese Benutzer frei.


F24 – AAC / ALAC Mime-Fallback

Was: Wenn ein Gerät AAC oder ALAC unterstützt, diese aber nicht explizit in seiner UPnP-Dienstbeschreibung bewirbt, bietet das Plugin sie trotzdem als Fallback an.

Warum: Mehrere Geräte, die AAC gut verarbeiten, haben vergessen, es in ihrer Fähigkeiten-XML aufzulisten. Ohne F24 würde das Plugin es nicht einmal versuchen und Transkodierung erzwingen. Mit F24 versucht das Plugin es und lässt das Gerät es nativ verarbeiten, wenn es kann.


F25 – DLNA-Typ-Flag für native + kodierte WAV-Streams

Was: Das DLNA-Typ-Flag (ein Profil-Identifikator wie LPCM, WAVE, MP3) muss mit dem übereinstimmen, was das Gerät empfängt. F25 stellt sicher, dass native Streams und kodierte WAV-Streams korrekt gekennzeichnet sind.

Warum: Nicht übereinstimmende DLNA-Typen führen dazu, dass einige Geräte die Wiedergabe ganz verweigern oder den falschen Decoder anwenden.


F26 – DLNA-Header für FLAC-Dateien

Was: FLAC-Streams erhalten den korrekten DLNA-Profil-Identifikator in ihren Headern.

Warum: Ohne ihn erkennen einige Geräte, die FLAC unterstützen, den Stream nicht als solchen.


F27 – Bitratenberechnungskorrektur in Metadaten

Was: Die kontinuierliche Stream-res@bitrate wurde als (sampleRate * channels * bitsPerSample) / 1000 berechnet – kbps, um einen Faktor von ~125 von der UPnP DIDL-Spezifikation abweichend, die das Attribut als Bytes pro Sekunde definiert. Jetzt wird durch 8 anstatt durch 1000 geteilt.

Warum: Falsche Bitratenanzeige auf dem Gerät – kosmetisch auf den meisten Renderern, aber einige weisen Stream-Puffer aus dem Wert zu und stottern bei Streams, die ~125× kleiner aussehen, als sie sind. Der nicht-kontinuierliche Quelldateipfad hatte dies bereits richtig ((bitrate_kbps * 1000) \ 8 = Bytes/Sek.); nur der kontinuierliche Stream-Pfad war falsch.


F28 – Metadaten-Zeitformat-Korrektur (Marantz)

Was: res@duration in DIDL wurde als H:MM:SS formatiert (z. B. 0:03:42). Die UPnP DIDL-Spezifikation definiert das Format als H+:MM:SS[.F+] – streng genommen mit optionalen, aber empfohlenen Sekundenbruchteilen; einige Marantz-Geräte behandeln die bloße Form als ungültig und lassen ihre Daueranzeige leer. Jetzt als H:MM:SS.fff formatiert (z. B. 0:03:42.000).

Warum: Anzeigeproblem, das spezifisch für eine Marke ist; konformes ISO-Format mit Sekundenbruchteilen behebt es, ohne andere Geräte zu beeinflussen. Angewendet an beiden DIDL-Emissionsstellen (Quelldateipfad + kodierter Stream-Pfad in WriteAudioFileDIDL).

Bonus-Fix im selben Durchlauf: pv:addedTime und pv:lastPlayedTime verwendeten hh (12-Stunden-Uhr) in ihren DateTime-Formatzeichenfolgen anstelle von HH (24-Stunden-Uhr). Jeder Titel, der zwischen 13:00 und 23:59 hinzugefügt oder abgespielt wurde, würde mit einer falschen Stunde gerendert (z. B. 17:42 → „05:42“) auf Geräten, die das Feld anzeigen. Verwendet jetzt HH.


F29 – Kodierte MP3-Suchunterstützung (CBR)

Was: Transkodierte MP3-Streams bewerben jetzt DLNA.ORG_OP=11 (sowohl Byte- als auch Zeit-Suche) anstelle von DLNA.ORG_OP=10 (nur Byte). Geräte, die zuvor die Zeit-Suche bei transkodierten MP3s verweigerten, können jetzt ihren Fortschrittsbalken/Such-UI normal steuern.

Warum: MusicBees Transcoder erzeugt MP3 mit konstanter Bitrate im HighQuality-Preset, sodass die Byte-↔-Zeit-Zuordnung linear ist – das Gerät kann eine Zeit-Suchanfrage selbst in eine HTTP Range Byte-Suche umwandeln, ohne Encoder-seitige Unterstützung. Das Bewerben von OP=11 schaltet diese UI auf dem Gerät frei. Ohne F29 wurden Benutzer, die in einem transkodierten MP3 suchten, entweder stillschweigend ignoriert oder zum Titelanfang zurückgesetzt.

Implementierung: GetEncodeFeature in ItemManager.vb wurde umstrukturiert, um das Inline-If in eine lesbare If/ElseIf/Else-Kette aufzuteilen. MP3 erhält explizit OP=11; andere Nicht-PCM-Codecs behalten OP=10. Keine Änderung für AAC/FLAC/etc. – diese würden eine Codec-spezifische Überprüfung der CBR-Eigenschaft erfordern, die MusicBee nicht garantiert.


F30 – .mpeg-Dateierweiterung behandelt

Was: Dateien mit der Erweiterung .mpeg (und der noch selteneren .mpe) werden jetzt in GetCodec als FileCodec.Mp3 erkannt. Vor F30 gaben sie FileCodec.Unknown zurück und wurden stillschweigend aus der Bibliothek abgelehnt / konnten nicht als Transcode-Quellen verwendet werden.

Warum: Alte MPEG-1 Layer 3-Archive verwendeten manchmal .mpeg anstelle von .mp3 (die Spezifikation erlaubt beides). Eine Handvoll Dateien in einer 300.000-Bibliothek reicht aus, um das Gefühl zu haben „MusicBee zeigt sie, aber das Plugin nicht“ – verwirrend für den Benutzer.


Wiedergabeverhalten

F31 – Radiostreams verwenden automatisch den kontinuierlichen Modus

Was: WriteAudioFileDIDL prüft jetzt die Kind-Eigenschaft der Quell-URL über Library_GetFileProperty und behandelt jede Datei, deren Kind auf „Stream“ endet (MusicBee meldet „MP3 Stream“, „Internet Stream“ usw. für Radio), als kontinuierlich, unabhängig vom globalen Settings.ContinuousOutput-Schalter. Der kontinuierliche Stream-DIDL-Zweig (Titel: „Continuous Stream“, id="continuousstream", feste PCM/Wave-Ausgabe) wird verwendet; das Gerät sieht einen einzigen Stream im unendlichen Stil.

Warum: Radiostreams haben keine Titelgrenzen, keine feste Länge, keine Suchfunktion. Sie in DIDL wie diskrete Dateien zu behandeln, führte dazu, dass das Plugin Byte-Bereiche und Dauern bewarb, die nicht existieren. Das automatische Umschalten, wenn MusicBee uns bereits mitgeteilt hat „dies ist ein Stream“, entfernt eine Fehlerquelle, über die der Benutzer nicht nachdenken sollte.

Umfang: Gilt nur, wenn MusicBee die Wiedergabe steuert (musicBeePlayToMode). Der Bibliotheks-Abrufpfad (UPnP-Client-Browsing) bleibt unverändert – Radio-URLs sind dort selten, und das benutzerseitige Verhalten sollte sich ohne explizite Tests nicht ändern.


F32 – Codec-Werbungs-Fallback

Was: Wenn ein Gerät bestimmte Codecs nicht bewirbt (oder das Plugin die Fähigkeiten-XML des Geräts nicht parsen kann), lehnt das Plugin den Stream nicht sofort ab. Stattdessen versucht es, ihn zu servieren, und lässt das Gerät entscheiden.

Warum: Viele Geräte haben unvollständige oder unlesbare Fähigkeiten-XML, verarbeiten den Codec aber tatsächlich einwandfrei. F32 tauscht ein kleines „Best-Guess und Versuch“ gegen eine direkte Ablehnung ein.


F33 – Verbesserung der Fortschrittsbalken-Synchronisation

Was: Die Position zwischen den Abfragen wird bereits von einem einzelnen Anker (currentPlayStartTicks) aus der Wanduhr extrapoliert, sodass der Fortschrittsbalken reibungslos mit einer Sub-Sekunden-Rate aktualisiert wird. Die verbleibende Jitter-Quelle war der ursprüngliche Anker für einen frisch gestarteten Titel: Der vorherige Code ging davon aus, dass position=0 in dem Moment war, in dem der Status-Timer zum ersten Mal bemerkte, dass der Status auf „Wiedergabe“ wechselte, aber zu diesem Zeitpunkt könnte das Gerät bereits 100-500 ms (ein Abfrageintervall) gespielt haben. MusicBees Fortschrittsbalken würde bei 0 beginnen und dann nach vorne springen, wenn die Realität aufholte.

F33-Fix: Beim ersten Übergang in den Wiedergabestatus bei einem neuen Titel (currentPlayStartTimeEstimated=True) GetPlayPositionInformation() aufrufen, um die tatsächliche aktuelle Position des Geräts zu erhalten, und dann daran verankern. UPnP meldet nur eine 1-Sekunden-Auflösung, sodass der Anker immer noch quantisiert ist, aber er ist der Wahrheit viel näher als die Annahme von 0.

Warum: Sanftere + genauere Fortschrittsanzeige, besonders direkt nach dem Titelwechsel. Die 1-Sekunden-UPnP-Berichtsauflösung selbst ist nicht zu umgehen – das ist Spezifikation.


F34 – Fortschrittsbalken-Jitter nach Titelwechsel

Was: Wenn PlayToDevice für einen neuen Titel aufgerufen wird, ließ das Plugin currentPlayPositionMs und currentPlayStartTicks für das ~100ms-Fenster zwischen SOAP-Play und der ersten Status-Timer-Abfrage, die den neuen Wiedergabestatus erkennt, auf ihren vorherigen Titelwerten. MusicBees Fortschrittsbalken zeigte kurz das Ende des vorherigen Titels an, sprang dann auf 0 zurück und stieg dann an. F34 setzt beide beim PlayToDevice-Eintrag auf Null – in dem Moment, in dem wir wissen, dass ein Titelwechsel stattfindet, bevor die SOAP-Arbeit beginnt.

Warum: Visueller Fehler bei schnellen Sprung-Anwendungsfällen (manuelles Weiter oder lückenloser Übergang). Jetzt gibt MusicBees erste PlayPositionMs-Abfrage nach Play sauber 0 zurück, dann verfeinert F33s GetPlayPositionInformation sie auf die tatsächliche Position des Geräts beim ersten Statuswechsel-Tick.

Implementierung: Vier Zeilen am Anfang von PlayToDevice, gepaart mit F33s genauer Verankerung zur Übergangszeit.


F35 – „Transkodierung erzwingen“-Fehler

Was: Das Erzwingen der Transkodierung konnte in bestimmten Kombinationen immer noch die Transkodierung überspringen. Nach der F04-Überarbeitung pro Profil wurden zwei spezifische Lücken geschlossen:

  1. Priorität mit ForceNativeStream. Wenn beide True waren (was bei einer Schema-Migration oder einer partiellen Einstellungsdatei passieren kann), gewinnt ForceTranscoding jetzt eindeutig (If streamingProfile.ForceTranscoding Then forceEncode = True ElseIf streamingProfile.ForceNativeStream Then forceEncode = False). Die UI-gegenseitige Ausschließung verhindert, dass der Benutzer beide aktiviert, aber die Laufzeitprüfung behandelt jeden Zustand, der inkonsistent von der Festplatte geladen wurde.
  2. bypassTranscodeDecision-Logik. Zuvor: streamingProfile.ForceNativeStream AndAlso Not Settings.ForceTranscoding. Jetzt: streamingProfile.ForceNativeStream AndAlso Not streamingProfile.ForceTranscoding – gleiche Prioritätsregel, aber im selben pro-Profil-Bereich.

Warum: „Erzwingen“ sollte Erzwingen bedeuten. Wenn der Benutzer ForceTranscoding für ein Gerät explizit aktiviert hat, darf das Plugin niemals stillschweigend auf natives Streaming zurückfallen, unabhängig davon, wie andere Flags kombiniert werden.


F36 – Renderer-geschlossene Ausnahme

Was: Plugin.ReceiveNotification wurde in einen Top-Level-Try/Catch-Block eingeschlossen, der jede unbehandelte Ausnahme protokolliert, anstatt sie an MusicBees Benachrichtigungspumpe weiterzuleiten.

Warum: Benachrichtigungen von MusicBee (PlayStateChanged, VolumeMuteChanged usw.) werden an ControlPointManager gesendet, der über SOAP mit dem Renderer kommuniziert. Einzelne Aufrufstellen hatten bereits Try/Catch um ihre SOAP-Aufrufe, aber ein ausreichend seltsamer Timing-Fall (z. B. Renderer stirbt zwischen zwei SOAP-Aufrufen im selben Benachrichtigungs-Handler) konnte immer noch entweichen. Der Top-Level-Wrapper ist das letzte Sicherheitsnetz, damit der Benutzer niemals ein generisches „TargetInvocationException“-Popup von MusicBee sieht.

Implementierung: Der vorhandene Body wurde in ReceiveNotificationInternal umbenannt und ein dünner Wrapper ReceiveNotification hinzugefügt, der Try { ReceiveNotificationInternal(...) } Catch { LogError(...) } ausführt. Die bereits vorhandene Try/Catch-Infrastruktur pro Methode innerhalb von ControlPointManager (um jeden PostSoapRequest-Aufruf) bleibt bestehen – F36 ist Gürtel + Hosenträger.


F37 – Lange Titel-Suche löst falschen Übergang aus

Was: Das Suchen innerhalb eines langen Titels kann bei einigen Renderern einen kurzen Stopped→Playing-Zyklus erzeugen. Ohne Unterscheidung behandelt ProcessNewPlayState.Stopped dies als natürliches Titelende und ruft Player_PlayNextTrack auf, wodurch MusicBee vorrückt, obwohl der Benutzer nur scrubben wollte. F37 stempelt lastUserInitiatedSeek in Seek() und fügt eine 5-Sekunden-Sperre im Stopped-Handler hinzu (spiegelt das bestehende lastUserInitiatedStop-Fenster wider).

Warum: Stilles Überspringen zum nächsten Titel während einer Suche ist einer dieser Fehler, dessen Ursache niemand erraten kann – der Benutzer denkt „komisch, ich habe versucht, vorwärts zu scrubben, und jetzt spielt es das nächste Lied“. Die Lösung ist mechanisch: dasselbe Muster wie die bereits vorhandene Benutzer-Stopp-Unterscheidung.


F38 – Verbesserte Suchbehandlung für absturzgefährdete Codecs

Was: BubbleUPnP, das bei der MP3-Suche abstürzte, war das kanonische Symptom. Nach einer Überprüfung macht der aktuelle yaiol-Suchcode bereits das Richtige – der native Pfad behandelt HTTP Range korrekt (206, Content-Range, AcceptRanges), der kodierte Pfad bewirbt X-AvailableSeekRange und parst eingehende timeSeekRange.dlna.org / npt-Header, DLNA.ORG_OP-Flags spiegeln die tatsächlichen Stream-Fähigkeiten wider (mit DisablePcmTimeSeek-Opt-out für problematische Platinum-Geräte). Benutzergetestet auf aktuellem BubbleUPnP 4.6.4: keine Abstürze beobachtet.

Warum: Der BubbleUPnP MP3-Suchabsturz wurde um 2024 gemeldet, und die App hat seitdem etwa 16 Monate lang Korrekturen erhalten. F29 (kodiertes MP3 OP=11) war die neue Variable, die es hätte wieder aufdecken können; tut es bei getesteten Versionen nicht.

Wenn ein Absturz zurückkehrt: Die Korrekturform wäre ein pro-Profil „begrenzte Suche“-Schalter, der DLNA.ORG_OP=10 (nur Byte) für gekennzeichnete Codecs erzwingt – spiegelnd, wie DisablePcmTimeSeek bereits für PCM funktioniert. Dann hinzufügen, nicht präventiv.


UI & Protokollierung

F39 – „Hinzufügen“-Schaltfläche wählt das neue Profil aus

Was: Das Klicken auf „Hinzufügen“ in der Liste der Geräteprofile erstellt ein neues Profil UND wählt es automatisch aus, sodass der Benutzer sofort Felder bearbeiten kann. Unser überarbeiteter Dialog mit Abschnitten tut dies bereits – sowohl der direkte Hinzufügen-Pfad als auch der Pfad von der Vorlage enden mit Me.activeStreamingProfiles.SelectedIndex = Me.activeStreamingProfiles.Items.Count - 1. Eine Überprüfung bestätigte, dass unser Fork dies bereits handhabt – nichts zu ändern.

Warum: Kleiner UX-Schönheitsfehler, der sich hier als bereits behoben herausstellte.


F40 – Größere maximale Verbindungen + Warnprotokoll

Was: Die Begrenzung der gleichzeitigen Streams des Plugins (SemaphoreSlim um Sockets_Stream_File / Sockets_Encoder_Start) war fest auf 4 kodiert. F40 macht sie auf der Seite „Allgemeine Einstellungen“ benutzerkonfigurierbar (Standard 16, Bereich 1-256), fügt eine MaxConnections-Protokollzeile hinzu, wenn eine Anfrage auf einen Slot warten muss, UND zeigt ein rotes ⚠ Max Conn-Badge unten links im Einstellungsdialog an, wenn die Begrenzung seit dem Start von MusicBee mindestens einmal erreicht wurde.

Warum: Wenn ein Gerät parallele Anfragen auslöst (einige Marantz/Linn während Artwork-Scans, BubbleUPnPs Metadaten-Probes neben aktiver Wiedergabe), wurden zusätzliche Anfragen stillschweigend hinter dem Semaphor blockiert – der Benutzer sah „Gerät langsam“ ohne sichtbare Ursache. Die Protokollzeile ist gut für die technische Fehlersuche, aber nicht-technische Benutzer lesen niemals Protokolle. Das sichtbare Badge im Einstellungsdialog macht die Bedingung „Begrenzung erreicht“ für jeden auffindbar, der die Plugin-Einstellungen öffnet.

Implementierung:

  • Die Wartezeit wurde in WaitOnSendBarrier(logTag) in MusicBeeUpnp.vb zentralisiert; beide Aufrufstellen (MediaServerDevice.GetFile, Encoder.StartEncode) verwenden sie.
  • Settings.MaxConnections wird in v8 des Einstellungsschemas gespeichert.
  • Plugin.MaxConnectionsHit ist ein Sticky Session Flag, das in WaitOnSendBarrier gesetzt wird; wird nur bei einem MusicBee-Neustart zurückgesetzt.
  • SettingsDialog.maxConnectionsBadge ist ein rotes, fettes Label bei (16, 410), das nur angezeigt wird, wenn Plugin.MaxConnectionsHit True ist. Hat einen Tooltip, der Ursache und Abhilfe erklärt.
  • Das Semaphor wird einmal beim Typ-Laden initialisiert, daher erfordert eine Änderung der Einstellung einen MusicBee-Neustart (im Feldlabel vermerkt).

F41 – Protokoll „Kodierung aufgrund von ReplayGain/DSP“

Was: Anstelle separater Protokollzeilen „Kodierung für RG“ / „Kodierung für DSP“ enthält die einzelne StreamDecision-Zeile von F42 MB-DSP/EQ, MB-ReplayGain, Profile-DSP/EQ, Profile-ReplayGain als kumulierte Gründe. Gleicher Diagnosewert, weniger Rauschen.

Warum: Benutzer sehen alle Gründe, warum die Transkodierung für einen bestimmten Titel stattfindet, in einer Protokollzeile, nicht verstreut. Siehe F42 für vollständige Details.


F42 – Protokoll „Renderer unterstützt Quell-Codec nicht“

Was: Eine StreamDecision-Protokollzeile pro Wiedergabe-zu-Gerät-Titel wurde hinzugefügt, die entweder „native CODEC“ oder „transcode CODEC→CODEC reason=…“ angibt. Das Feld „reason“ sammelt jede Bedingung, die die Transkodierung ausgelöst hat: MB-DSP/EQ, MB-ReplayGain, Profile-DSP/EQ, Profile-ReplayGain, WebFile, VirtualFile, ForceTranscoding(global), SampleRate<min/SampleRate>max, DownmixToStereo, DeviceLacksCodec(X), BandwidthConstrained.

Warum: Benutzer waren verwirrt über unerwartete CPU-Spitzen bei Dateien, die sie nativ streamen wollten. Eine Protokollzeile pro Titel sagt ihnen genau, welche Bedingung die Transkodierung verursacht hat – und wenn das Feld DeviceLacksCodec(Flac) anzeigt, wissen sie sofort, dass die Protokollinformationen des Geräts unvollständig waren und möchten möglicherweise, dass F32s Fallback greift.

Implementierung: Eine einzelne Akkumulatorzeichenfolge, die inkrementell durch die Entscheidungskette aufgebaut wird; einmal am Ende protokolliert. Gesteuert durch Settings.LogDebugInfo, um Protokollrauschen in der Produktion zu vermeiden.


F43 – SetNextAVTransport-Protokoll zeigt Quell-URL an

Was: QueueNext-Protokolleinträge enthalten jetzt source=<MusicBee library path> neben stream=<HTTP streaming URL>. Dieselbe Änderung wurde auf den Erfolgs- und den Fehlerpfad (QueueNext:Failed) angewendet.

Warum: Beim Debuggen eines Problems mit einem in der Warteschlange befindlichen Titel ist die Streaming-URL (/encode/aabbccdd0.flac) an sich undurchsichtig – für jeden Titel gleich. Die Quell-URL ist der von Menschen durchsuchbare Bibliothekspfad, der Ihnen genau sagt, welche Datei MusicBee versucht hat, in die Warteschlange zu stellen.


F44 – Bessere Mime-Typ-Fehlerprotokollierung

Was: Zwei neue Protokolleinträge während Activate:

  • Activate:MimeUnverified – wird pro fehlerhaftem Eintrag in der GetProtocolInfo-Antwort des Geräts ausgelöst und benennt, welcher Eintrag nicht geparst werden konnte (damit der Benutzer z. B. sehen kann: „der Marantz gab http-get:*::* für einen Codec zurück – die Fähigkeit ist unbestätigt, F32s Fallback wird raten“).
  • Activate:NoSinkInfo – wird einmal ausgelöst, wenn das Gerät überhaupt kein <Sink>-Element zurückgegeben hat. Bedeutet, dass SupportedMimeTypes Nothing bleibt und IsCodecSupported auf „alles funktioniert“ herabgestuft wird – nützlicher Kontext, wenn später „Gerät hat Stream abgelehnt“-Fehler auftreten.

Warum: Vor F44 ließen diese stillschweigenden Fähigkeits-Fallbacks Benutzer raten, warum ihre Titel entweder entgegen den Erwartungen transkodiert oder vom Gerät abgelehnt wurden. Jetzt zeigt ein einziger Grep nach Activate: an, ob die Fähigkeitsinformationen des Geräts verwendbar waren.


F45 – Bessere Metadaten-Fehlerprotokollierung

Was: Das Browse-Ausnahmeprotokoll in ContentDirectoryService.vb wurde bereits in früheren yaiol-Arbeiten (der Alia Vox-Fehlersitzung) mit ObjectID und Stack-Trace angereichert. F45 erweitert es weiter mit BrowseFlag (Metadaten vs. Kinder), Filter (welche Attribute der Client angefordert hat), sortCriteria und partialResultLength (wie viele Bytes DIDL vor dem Fehler erzeugt wurden – zeigt an, wie weit im Batch der fehlerhafte Titel sitzt).

Warum: Wenn mitten in DIDL etwas schiefgeht, sagt Ihnen der Teillängenwert, ob der Fehler beim ersten Titel des Batches (partial=0) oder mittendrin (partial=N) auftrat – kombiniert mit dem startingIndex des Batches können Sie den fehlerhaften Titelindex identifizieren. Filter und BrowseFlag erklären, welche Art von Browse der Client wollte; manchmal schlägt ein reiner Metadaten-Browse fehl, wo ein Kinder-Browse für dieselbe ID erfolgreich ist.


Netzwerk

F46 – Automatischer Modus bewirbt nur auf echten Netzwerkadaptern

Was: Im automatischen Schnittstellenmodus kündigte sich das Plugin (SSDP) früher auf jedem betriebsbereiten IPv4-Adapter an. Auf einem Computer, der auch einen VPN-Tunnel (NordLynx) oder einen virtuellen Switch (Hyper-V / WSL / Docker) ausführt, wurde dieselbe Bibliothek auch auf jedem dieser Adapter angekündigt, sodass der Kontrollpunkt, von dem Sie casten, den Server zwei- oder dreimal entdeckte und die Bibliothek als doppelte Kopien auflistete. Der automatische Modus behält jetzt nur Adapter bei, die ein echtes IPv4-Standard-Gateway (HasIPv4Gateway) haben – was die Tunnel- und virtuellen Switch-Adapter nicht haben – sodass diese aus der Ankündigungsliste entfernt werden. Eine vom Benutzer festgelegte Adresse gewinnt immer (nur auf dieser Schnittstelle ankündigen), und wenn kein Adapter ein Gateway meldet, fällt der Selektor auf jeden Adapter zurück, sodass die Liste der beworbenen Adressen niemals leer ist und das Plugin nicht unsichtbar werden kann.

Warum: Das Duplikat wird nicht durch „in einem VPN sein“ verursacht – es wird durch die gleichzeitige Ankündigung auf dem LAN-Adapter und dem Tunnel-/virtuellen Adapter verursacht, sodass ein Kontrollpunkt denselben Server an zwei Adressen sieht. Ein Consumer-VPN (NordVPN/NordLynx) tunnelt nur internetgebundenen Datenverkehr; der DLNA-Renderer befindet sich im LAN und der lokale Subnetz-Datenverkehr umgeht den Tunnel, sodass der Tunnel-Adapter ohnehin niemals einen Renderer erreicht – das Entfernen entfernt eine Phantomkopie, niemals einen funktionierenden Pfad. Der Gateway-Test ist das billige, zuverlässige Signal, das einen echten LAN-/Wi-Fi-Adapter von einem Tunnel oder virtuellen Switch trennt. Ergänzt N05 (das behob, wie Ankündigungen auf solchen Links gesendet werden – Multicast statt Broadcast); F46 regelt, auf welchen Adaptern überhaupt Ankündigungen gesendet werden.

Bekannte Einschränkung: Ein Mesh-/Remote-Access-VPN (Tailscale, ZeroTier, WireGuard-to-home), dessen Renderer tatsächlich über den Tunnel leben, präsentiert normalerweise einen Adapter ohne Standard-Gateway, sodass der automatische Modus ihn ebenfalls entfernt. Diese Benutzer pinnen stattdessen die VPN-Adresse, die Vorrang vor dem Gateway-Filter hat.

Inhalt