MusicBee UPnP Plugin Nápověda

Co je nového

2.0.2 - 2026-07-20

  • Šablonu již nelze odstranit, pokud ji sleduje jakýkoli uzel – tlačítko pro odstranění zůstane jednoduše deaktivováno, takže uzel nikdy nemůže zůstat osamocený. Každý řádek šablony nyní zobrazuje živý počet (n) jejích následovníků, což na první pohled vysvětluje deaktivované odstranění; odstranění nepoužívané šablony se nyní také zachová, namísto tichého opětovného zobrazení výchozích nastavení při dalším načtení.
  • Nové tlačítko trychtýře vedle stromu Zobrazení ukazuje přesně, které uzly sledují šablonu: filtruje strom pouze na následovníky vybrané šablony, znovu filtruje, když vyberete jiné šablony, a obnoví celý strom, když je vypnuto.
  • Uzly Rádio a Podcasty jsou nyní trvale spárovány se šablonou své kategorie – přetvarujte šablonu na kartě Cesty a uzel se sám přizpůsobí; není nic k použití, takže tlačítko Použít je pro ně deaktivováno. Seznam šablon to odráží dvěma pásmy, Standardní (kde jsou vytvářeny všechny nové šablony) a Rezervované (Rádio + Podcasty).

2.0.1 - 2026-07-20

  • Šablony cest jsou nyní živě propojeny s uzly, které je používají. Použití šablony způsobí, že uzel ji následuje: upravte šablonu později a každý uzel, který ji následuje, se okamžitě přetvaruje – bez nutnosti ji hledat a znovu ji aplikovat uzel po uzlu. Strom zobrazení ukazuje, kterou šablonu každý uzel následuje hned za jeho názvem, přejmenování se tam okamžitě objeví a smazání šablony vám nejprve řekne, kolik uzlů ji následuje (zachovají si své aktuální rozložení a jednoduše přestanou cokoli následovat).
  • Použití šablony na skrytý uzel jej také znovu zviditelní – použití je gesto „ukaž mi to, tvarované takto“, zatímco skrytí zůstává u zaškrtávacího políčka Viditelné. Rezervovaná šablona „Skryté“, kterou toto nahrazuje, je pryč.
  • Strom zobrazení již neztrácí vaše místo: zaškrtnutí, rozbalené složky a pozice posuvníku přežijí použití šablon a další obnovení.

2.0.0 - 2026-06-16

Toto je první veřejné vydání open-source forku yaiol pluginu MusicBee UPnP. Je prezentováno ve dvou částech: vše, co je v tomto forku nové, a poté opravy a vylepšení provedené v původním pluginu. Každá položka zachovává formát Co / Proč z interního katalogu funkcí projektu, takže zdůvodnění každé změny je uvedeno přímo, nejen samotná změna.

Novinky v tomto forku

MediaRenderer - přehrávání do MusicBee

N01 - MusicBee jako renderer pro přehrávání

Co: normálně tento plugin funguje jednosměrně: telefon nebo jiné zařízení prochází knihovnu MusicBee a přehrává hudbu na sobě. Tato funkce přidává opačný směr – umožňuje MusicBee být přehrávačem. Z ovládací aplikace na vašem telefonu (jako je BubbleUPnP) si můžete vybrat svůj desktopový MusicBee jako zařízení pro přehrávání a poté jej ovládat z ruky: přehrávat, pozastavit, zastavit, přeskočit vpřed nebo vzad, skočit na konkrétní místo ve skladbě a změnit hlasitost nebo ztlumit.

Proč: promění váš telefon v dálkové ovládání pro hudbu, která je již na vašem PC. Sedněte si na gauč, procházejte svou knihovnu na telefonu, klepněte na skladbu a ta se ozve z reproduktorů připojených k vašemu desktopu – s plnou kontrolou z místa, kde sedíte. Původní plugin tuto funkci nikdy nedodal jako funkční.

Zapnutí: je ve výchozím nastavení vypnuto, protože jeho zapnutí umožňuje čemukoli ve vaší domácí síti spustit přehrávání na vašem PC. Povolíte jej zaškrtnutím políčka na kartě Obecné v dialogovém okně nastavení. Tři role pluginu mají každá své vlastní zaškrtávací políčko – sdílet mou knihovnu (Server), nechat ostatní přehrávat ke mně (Renderer) a přehrávat na jiná zařízení (Control Point) – a dialogové okno zobrazuje pouze karty nastavení, které role, které jste zapnuli, skutečně potřebují, takže se nikdy nesetkáte s možnostmi, které se vás netýkají.

Rozlišení vašich zařízení: rendereru můžete dát libovolné jméno (začíná jako "MusicBee (yaiol)"). Toto jméno se zobrazí v seznamu cílů pro přehrávání ve vašem telefonu, takže když běží MusicBee na více než jednom PC, můžete rozlišit, které je které. Změna názvu se projeví okamžitě, bez restartu.

Nejlepší možný zvuk při přehrávání do sebe: když procházíte vlastní knihovnu MusicBee z telefonu a pošlete skladbu zpět do stejného MusicBee, plugin rozpozná, že je požádán o přehrání jednoho z vlastních souborů a jednoduše jej přehraje přímo z vašeho disku. Výsledek je přesný a okamžitý – bit-perfect, s aplikovaným vlastním ekvalizérem a vyrovnáváním hlasitosti MusicBee – namísto zbytečného posílání zvuku na síť a přímo zpět k sobě.

Provozování soukromě: tři role fungují nezávisle, takže můžete zapnout renderer a zároveň nechat sdílení knihovny vypnuté. V tomto nastavení "pouze renderer" zůstane vaše knihovna zcela skryta před sítí – oznámen je pouze cíl pro přehrávání – a MusicBee nikdy nenabídne přehrávání do sebe.


Chování přehrávání

N02 - 5.1 FLAC není automaticky downmixován

Co: omezení počtu kanálů v MediaServerDevice.GetEncodedFile bylo If StereoOnly OrElse Not isPcmData Then channelCount = 2. Klauzule Not isPcmData tiše downmixovala každý non-PCM transkód (FLAC, MP3, AAC, Ogg) na stereo bez ohledu na počet kanálů zdroje, čímž znemožňovala 5.1-schopným rendererům fungovat, když byl zdrojem 5.1 FLAC. Nyní druhá klauzule vylučuje FLAC: Not isPcmData AndAlso encoder.Codec <> FileCodec.Flac. FLAC 5.1 prochází; MP3/AAC/Ogg stále vynucují stereo, protože MusicBee příkazové řádkové kodéry pro tyto formáty očekávají 2-kanálový vstup.

Proč: celým smyslem transkódování 5.1 FLAC zdroje na FLAC výstup je zachování vícekanálového mixu. Tichý downmix učinil možnost transkódování FLAC pro prostorový poslech zbytečnou. S N02 dělá správnou věc.


Architektura

Strukturální změna, která činí fork životaschopným pro velkou knihovnu – chybí v původním pluginu.

N03 - Líný (na vyžádání) strom procházení

Co: původní plugin sestavil celý strom procházení při spuštění MusicBee – vyjmenoval každou skladbu, provedl plné Library_GetFileTags pro každý soubor, sestavil celou hierarchii kontejnerů – před otevřením HTTP portu. U skutečné knihovny (50 tisíc+ skladeb, 5400 epizod podcastů, stovky stanic) to znamená minuty studeného startu a strom zůstává v RAM navždy, včetně větví, které žádný klient nikdy neotevře. Tento fork nic předem nestaví: kořen vystavuje jeden zástupný symbol s předponou L: pro každý koncový bod (L:music, L:podcast, L:filter:…); každá úroveň je vypočítána pouze tehdy, když do ní klient prochází (LazyBrowseEnsureLazyEndpointInMemory → mezipaměti na úrovni), a oznámení o změně knihovny vymažou mezipaměti (SetLibraryDirty).

Proč: studený start je v podstatě okamžitý – HTTP port je otevřen v době, kdy MusicBee dokončí inicializaci pluginu – a paměť zůstává úměrná tomu, co bylo procházeno, nikoli velikosti knihovny. Kompromis: první procházení do koncového bodu zaplatí své náklady na načtení; opětovný vstup je uložen do mezipaměti až do další změny knihovny. To je základ, na kterém závisí vše ostatní. Úplné poznámky: FIXES.md.


Sítě a robustnost

Zpřísnění cesty vazby HTTP serveru. Původní plugin tiše umírá, když je jeho port nedostupný.

N04 - Samoopravné vázání HTTP portu

Co: HTTP server pluginu již neumírá, když je jeho nakonfigurovaný port nedostupný. Tři související změny:

  1. Automatický fallback při selhání vazby. HttpServer.Start zkusí nakonfigurovaný port a při SocketException prohledá až 20 portů nahoru pro první volný. Skutečný vázaný port je zaznamenán v novém Plugin.boundServerPort, a vše, co inzeruje server – SSDP LOCATION URL (NOTIFY + M-SEARCH odpověď), URL zařízení (PrimaryHostUrl), přesměrování portu routeru a SSDP/control-point self-filtry – nyní čte boundServerPort namísto Settings.ServerPort. UPnP klienti objeví skutečný port přes SSDP, takže přesunutý port je pro renderery transparentní.
  2. Uživatelské oznámení. Když dojde k fallbacku (uložený port není ten, který se používá), lokalizovaný MessageBox (WarnPortInUse) informuje uživatele, který port skutečně slouží a že zařízení jej stále najdou – protože plugin běží bez hlavy a zpráva v dialogovém okně by byla viditelná pouze pro někoho, kdo již tušil problém.
  3. Obnova po restartu. RestartServer (cesta restartu po uložení nastavení) dříve slepě dereferencoval Plugin.controller / Plugin.server. Pokud počáteční Initialise vyhodil chybu před jejich vytvořením (přesně to, co způsobilo selhání vazby), další uložení nastavení narazilo na NullReferenceException – což zanechalo napůl mrtvý plugin. Nyní je znovu vytvoří a spustí, když jsou Nothing, takže uložení funkčního portu oživí plugin bez úplného restartu MusicBee.

Proč: spouštěčem byl skutečný uživatelský incident. Starý výchozí port 49382 se nachází v dynamickém rozsahu Windows (49152-65535), kde Hyper-V/WSL2/Docker/WinNAT rezervují velké bloky, které se posouvají při každém spuštění – takže vazba selhala s WSAEACCES ("přístup zakázán") na stroji, kde fungovala měsíce. Změna výchozího portu na volný pak kolidovala se Serviio (samostatný DLNA server již na novém portu), což selhalo s WSAEADDRINUSE. Každé selhání bylo pohlceno v Initialise, což zanechalo plugin tiše mrtvý a poté NRE-ing při dalším uložení nastavení. Po N04 se kolize portů samoopraví – server pokračuje v běhu na dalším volném portu, uživatel je informován a klienti jej znovu objeví – namísto toho, aby se celý plugin zhroutil.

Implementace:

  • Výchozí port přesunut 493829779 (pod dynamickým rozsahem, takže Windows jej nikdy automaticky nerezervuje; není známým výchozím nastavením mediálního serveru) ve všech třech deklaracích ServerPort + fallbacku při selhání parsování nastavení.
  • Plugin.boundServerPort (nové sdílené pole) drží živý naslouchací port; activeServerPort zůstává nakonfigurovaným snímkem, takže logika odznaku "Restart Required" se nespustí falešně při fallbacku.
  • HttpServer.PortScanRange = 20; sken se zastaví u prvního úspěšného TcpListener.Start() a vyhodí poslední výjimku pouze v případě, že všechny pokusy selžou.
  • Nový EN klíč zdroje WarnPortInUse (překlady následují lokalizační průchod v době publikace).

N05 - SSDP oznámení přes multicastovou skupinu (VPN / point-to-point)

Co: SSDP oznámení jsou odesílána do UPnP multicastové skupiny (239.255.255.250) namísto IP broadcastové adresy. Neškodná chyba "cannot access a disposed object" zaznamenaná, když odpověď na SSDP vyhledávání závodí s restartem serveru, je také potlačena.

Proč: na point-to-point / VPN síťových adaptérech se IP broadcast nepoužívá – staré broadcastové odesílání selhalo s "invalid argument" a oznámení byla vynechána, takže plugin byl pro klienty na těchto spojeních neviditelný. Oznámení správné multicastové skupině opravuje objevování přesně na těchto adaptérech.

Navigace v knihovně

Tyto funkce byly dodány v tomto forku a nejsou v původním pluginu. Vznikly skutečným procházením výstupu pluginu z reálných UPnP klientů.

N06 - Zpřístupnění knihovny na základě filtrů

Co: záložky filtrů MusicBee (soubory .xautopf ve složce MusicBee uživatele) se stávají kořenovými UPnP kontejnery v knihovně pluginu. Skladby každého filtru jsou pak procházitelné v hierarchii AlbumArtistSort → Album → Tracks.

Proč: uživatelé s upravenými filtry MusicBee (např. "5hvězdičkové skladby", "Nedávno přidané", "Klasika → Baroko") očekávají, že je najdou při procházení pluginu z UPnP klienta. Původní plugin zpřístupňoval pouze syrový strom knihovny.


N07 - Propojení pole SortAlbumArtist

Co: plugin nyní čte MetaDataType 165 (Sort Album Artist) z MusicBee a používá jej k seskupování/řazení umělců v zobrazeních procházení.

Proč: hi-fi prohlížeče a audiofilové používají jména umělců pro řazení ("Beethoven, Ludwig van" namísto "Ludwig van Beethoven") k organizaci knihoven. Standardní očekávání pro vážné posluchače. Chybí v obou upstreamových verzích.


N08 - Zpracování vícehodnotového AlbumArtist

Co: když pole AlbumArtist alba obsahuje více umělců oddělených "; " (např. "yaiol; Ars Ricercata"), skladba se nyní zobrazuje pod každým umělcem v zobrazeních procházení, nikoli pod jedním Frankensteinovým umělcem kombinujícím jména.

Proč: kolaborativní alba a kompilace se musí zobrazovat pod každým spolupracovníkem. Bez toho je polovina cest k nalezení alba nefunkční.


N09 - Obal alba kontejneru (upnp:albumArtURI)

Co: uzly kontejnerů alb v DIDL Browse odpovědích nyní obsahují prvek upnp:albumArtURI odkazující na obal alba.

Proč: bez toho se každé album v zobrazení procházení UPnP klienta zobrazuje s generickou ikonou namísto obalu alba. Vizuální vodítko pro navigaci; očekáváno každým moderním hi-fi prohlížečem.


N10 - Řazení skladeb uvnitř alb filtru

Co: skladby uvnitř alba vystaveného filtrem jsou nyní řazeny podle čísla disku a poté podle čísla skladby.

Proč: standardní pořadí alba. Bez explicitního řazení se skladby vracely v jakémkoli pořadí, v jakém je filtr náhodou vrátil – obvykle vypadaly náhodně.


N11 - Oprava stromu složek playlistů

Co: funkce LoadLibraryPlaylists (původně od Stevena Mayalla, ~2014) selhala při sestupu do nově vytvořených složek playlistů. První playlist v každé složce, plus jakékoli podsložky, skončily osamocené na kořenové úrovni.

Proč: přítomno v původním pluginu jedenáct let. Viditelné do 30 sekund po otevření BubbleUPnP a kliknutí na Playlists. Opraveno v yaiol správnou rekurzí do nově vytvořených složek během konstrukce stromu.


N12 - Sanitizace XML-nelegálních řídicích znaků

Co: jakákoli skladba s tagem obsahujícím řídicí znak C0 (např. 0x19 z chybného kódování – UTF-8 → Latin-1 → zpětné zkrácení 0x99 na 0x19) způsobila selhání celé Browse odpovědi s Action Failed, jakmile se špatná skladba dostala do stránkované dávky.

Proč: XML 1.0 zakazuje většinu řídicích znaků C0 a XmlWriter vyhodí chybu, když je požádán o zápis jakéhokoli. Přítomno v původním pluginu. Opraveno odstraněním neplatných znaků na každém výstupním bodě Library_GetFileTags pomocí XmlConvert.IsXmlChar.


N13 - Determinismus seznamu rádií napříč stránkovaným procházením

Co: procházení kontejneru Radio spadalo do obecné větve seznamu souborů, která při každém volání volala files.Sort(AlbumFileComparer). Položky rádia mají prázdné tagy Album/Disc/Track, takže každé porovnání vrátilo 0 – List(Of T).Sort je nestabilní a při každém vyvolání produkuje jiné pořadí. UPnP ovládací body stránkují (BubbleUPnP načte 0..15 a poté 16..konec); mezi dvěma voláními se seznam přeskupil, takže některé stanice se objevily na obou stránkách (duplikáty) a některé na žádné (chybějící) – při každém obnovení vypadaly náhodně.

Proč: přítomno v původním pluginu (jeho autor nikdy neprochází rádio přes UPnP). Opraveno zde s vyhrazenou větví ContainerCategory.Radio v Browse, bez řazení na volání; radioFiles je seřazeno jednou při načtení podle názvu (stabilní). Stránkované procházení nyní vidí deterministické pořadí; stránka 1 a stránka 2 jsou disjunktní.


N14 - UPnP vyhledávání třídy alba vrací kontejnery alb

Co: UPnP vyhledávání pro dotazy třídy alba (upnp:class = "object.container.album.musicAlbum", např. "Náhodná alba" v BubbleUPnP) vracelo celý seznam skladeb namísto kontejnerů alb, takže klient zobrazil nula alb. Původní obsluha parsovala pouze kritéria v závorkách a poté vypsala všechny skladby bez ohledu na požadovanou třídu.

Proč: opraveno zde – dotazy třídy alba nyní vyjmenovávají odlišná alba (seskupená podle AlbumArtist+Album) a každé z nich emitují jako správný kontejner musicAlbum s obalem, adresovatelný přes virtuální ID prostor Salb<idx>, takže klient může prozkoumat výsledek a přehrát jej.


N15 - Funkční, kontextově citlivé UPnP vyhledávání s proklikem

Co: původní verze neoznamovala žádné vyhledávací schopnosti (GetSearchCapabilities vracelo prázdné), takže klienti odmítali vůbec odeslat vyhledávání; a starý backend četl z musicFiles, trvale prázdných v éře líného stromu. Tento fork inzeruje skutečné prohledávatelné vlastnosti, implementuje vyhledávání skladeb podle názvu a alb podle názvu proti líné knihovně (HandleLazySearch), omezuje dotaz na aktuální větev klienta, když je odesláno skutečné ID kontejneru (jinak nahrazuje L:music, aby vyhledávání v horní liště nezahrnovalo šum z podcastů/rádií/audioknih), a umožňuje klikání na výsledky alb pomocí syntetických ID Ssrch_alb_*, které raná větev Browse mapuje zpět na skladby alba. (Část s výsledky třídy alba jako kontejnery je N14.)

Proč: vyhledávání v BubbleUPnP se změnilo z "Knihovna nepodporuje vyhledávání" na vracení užitečných, kontextově relevantních a přehrávatelných výsledků. Kompletní návrh + zamítnuté přístupy: SEARCH.md.


N16 - Zneplatnění UPnP cache (SystemUpdateID)

Co: původní verze vracela konstantní SystemUpdateID=0 – kontrakt UPnP ContentDirectory pro zneplatnění cache – takže klienti kompatibilní se specifikací (BubbleUPnP) považovali knihovnu za neměnnou: zastaralé výsledky procházení, 404 miniatury po změně URL schématu a "restartujte MusicBee dvakrát, abyste viděli změny". Tento fork inicializuje SystemUpdateID z epoch-sekund při načtení (takže každý restart je striktně předchozímu) a zvyšuje jej při každé mutaci knihovny a změně nastavení (SetLibraryDirty / ResetCacheBumpSystemUpdateId).

Proč: klienti spolehlivě zaznamenávají úpravy, nové soubory a změny nastavení při dalším procházení. Známé omezení: přihlášení klienti nedostávají novou hodnotu aktivně znovu přes GENA (odloženo jako budoucí práce); stále ji vidí při dalším procházení.


N17 - Obaly podcastových odběrů

Co: dlaždice podcastů nezobrazovaly žádné obrázky – každý požadavek na /PodcastThumbnail/ skončil chybou 404. Dvě navrstvené chyby: řetězec rozlišení nikdy nekontroloval skutečnou cache obalů MusicBee (%LocalAppData%\MusicBee\InternalCache\Subscriptions\<name>.jpg, odkud se načítá desktopové UI), a HTTP vrstva unescape+lowercase zkomolila klíč trasy URL kanálu až na jeho poslední segment cesty. Tento fork rozlišuje obaly z MB InternalCache a směruje vyhledávání přes URL-bezpečný slug, který přežije HTTP vrstvu neporušený (PodcastSlug / podcastSubIdBySlug).

Proč: obaly odběrů se nyní vykreslují v zobrazeních procházení (všech 22 dříve chybových požadavků 404 je vyřešeno).


N18 - Hierarchické (oddělené) procházení tagů

Co: jakékoli pole může být označeno jako hierarchické na kartě Možnosti knihovny a může mu být přidělen jednopísmenný oddělovač (výběr pole + pole oddělovače s přidáním/odebráním, uložené v nastavení pluginu). Nastavte Seskupování na / a hodnotu jako Jazz/Cool Jazz se pak prochází jako Jazz › Cool Jazz namísto jednoho plochého záznamu. Skladby označené přesně na větvi (jen Jazz) získají svůj vlastní uzel [Jazz], takže nic není skryto, větev s jediným potomkem se sama zhroutí a ; je odmítnut jako oddělovač, protože je to vlastní oddělovač vícehodnot MusicBee.

Proč: hluboké taxonomie tagů, které uživatel již zakódoval do jednoho pole (stromy žánrů, hierarchie nálad, "Klasika/Baroko/Koncert"), se konečně procházejí jako strom, který tag popisuje, namísto ploché stěny řetězců oddělených lomítky, které uživatel musí číst od začátku do konce.


N19 - Jedna kořenová cesta označená svým seskupovacím polem

Co: jedna cesta procházení v kořeni je označena svým seskupovacím polem (např. "Žánr") namísto své plné krátké cesty, což odpovídá tomu, jak jsou pojmenovány sloučené skupiny prvního pole.

Proč: strom procházení se čte konzistentně – jedno pravidlo pojmenování, ať už kořenová položka stojí sama, nebo byla sloučena se sourozenci (N20) – namísto osamělé kořenové položky zobrazující podrobnou interní cestu, zatímco její sloučení sousedé zobrazují čistý název pole.


N20 - Sloučení cest procházení, které sdílejí první pole

Co: dvě cesty procházení, které sdílejí stejné první pole – "Žánr / Řazení umělce alba" a "Žánr / Lidé z podcastů" – se zhroutí do jedné kořenové složky Žánr, která nejprve vypíše hodnoty žánru a poté se rozdělí do dvou zobrazení, namísto dvou téměř duplicitních položek "Žánr / …" vedle sebe v kořeni.

Proč: uživatel s několika souvisejícími zobrazeními vnořenými pod společným polem viděl kořen zaplněný téměř identickými položkami nejvyšší úrovně. Jejich sloučení udržuje kořen čitelný a seskupuje související zobrazení tam, kam patří – pod jejich sdílené pole.


N21 - Cesty procházení typované kategorií (Standardní / Rádio / Podcast)

Co: každá cesta procházení je typována kategorií – Standardní, Rádio nebo Podcast. Seznam šablon je seskupen do těchto tří sekcí, výběr pole každé šablony nabízí pouze pole, která data dané kategorie skutečně mohou poskytnout, a šablona může být aplikována pouze na odpovídající uzly ve stromu zobrazení (nekompatibilní uzly se zašednou a nelze je zaškrtnout). Rezervované šablony Rádio a Podcasty nelze smazat, takže jejich sekce kategorií nikdy nezmizí.

Proč: bez typování by uživatel mohl vytvořit rozložení, které by se tiše objevilo prázdné – rozhlasová stanice nemá "album", epizoda podcastu nemá "umělce alba" – a zjistil by to až procházením do mrtvé složky z UPnP klienta. Omezení nabídky polí a cílů aplikace na skutečná data kategorie činí prázdná rozložení nevytvořitelnými.


N22 - Seskupování podcastů podle roku vydání

Co: datum vydání každé epizody podcastu je načteno, takže cesta procházení podcastu s úrovní Rok seskupuje epizody podle roku namísto jejich zhroucení pod jediné "Neznámé".

Proč: velké podcastové odběry se stávají navigovatelnými podle roku jako zbytek knihovny, namísto toho, aby každá epizoda skončila v jedné nedatované hromadě, protože plugin nikdy nekontroloval datum vydání jednotlivých epizod.


N23 - Sbalení úrovní seskupování s jedním výsledkem

Co: úroveň seskupování, která se vyřeší na jedinou hodnotu – úroveň Typ záznamu zobrazující pouze "LP" pro umělce, který vydal pouze LP, nebo úroveň písmene s jediným písmenem – je automaticky přeskočena, čímž se uživatel dostane přímo k jejímu obsahu.

Proč: procházení složky, která obsahuje přesně jednu složku, je čistá frustrace. Sbalení úrovně s jednou volbou odstraní zbytečné kliknutí, aniž by se změnilo, co uživatel může dosáhnout.


N24 - Seskupování/vyhledávání podle roku proti datovému poli MusicBee

Co: podmínka roku již nehledá v poli "Rok" MusicBee s plným datem pouze čtyřcifernou hodnotu a pevně zakódované aliasování pole roku je pryč, takže každé pole pro seskupování se nyní řeší genericky z definice cesty.

Proč: pro knihovny, jejichž tag Rok obsahuje kompletní datum, seskupování nebo vyhledávání podle roku dříve nevracelo nic – čtyřciferný dotaz nikdy neodpovídal poli s plným datem. Dotazování správného pole způsobí, že seskupování a vyhledávání podle roku znovu najde skladby.


N25 - Samostatná pole pro seskupování "Rok" a "Rok (rrrr)"

Co: seskupování alb a cesty procházení nyní zpřístupňují obě vlastní pole roku MusicBee – Rok (tag s plným datem) a Rok (rrrr) (pouze čtyřciferný rok) – takže uživatel si může vybrat jedno z nich při definování seskupování alb nebo cesty procházení.

Proč: tato dvě pole znamenají v MusicBee různé věci a jejich sloučení ztratilo tento rozdíl. Zobrazení obou umožňuje uživateli shromáždit všechna vydání jednoho roku dohromady (rrrr) nebo zachovat přesné řazení podle data (tag s plným rokem), podle jejich záměru.


N32 - Připnuté filtry a seznamy skladeb seskupené podle druhu v kořeni

Co: připnutý filtr se nyní zobrazuje přímo pod složkou Filtry v kořeni procházení a připnutý seznam skladeb přímo pod složkou Seznamy skladeb, namísto toho, aby se všechna připnutí shromažďovala v jednom chumlu na konci kořene. Každá připnutá zkratka je umístěna se svým druhem.

Proč: čím více zkratek uživatel připne, tím hůře se jediný koncový chuml smíchaných filtrů a seznamů skladeb prochází a každou zkratku odděluje od složky, ke které patří. Seskupení připnutých položek pod vlastní kategorii udržuje kořen čitelný a každou zkratku vedle věcí, ke kterým patří.

Dialog nastavení a balení

N26 - Sekční dialog nastavení

Co: stránka Předvolby získala rozložení s levým navigačním panelem a sekcemi: Obecné / Přehrávání / Knihovna / Profily zařízení / Diagnostika.

Proč: původní verze byla jediný dlouhý plochý seznam všech nastavení – v pořádku pro vývojáře, který ji vytvořil, ale matoucí pro všechny ostatní. Rozdělení do sekcí seskupuje související možnosti a dialogové okno působí více jako moderní nastavení aplikace.


Přejmenování sestavení + pluginu (bez F-id - poznámka k balení)

Co: zkompilovaná DLL je pojmenována mb_UPnP_yaiol.dll a plugin se hlásí jako "MusicBee UPnP (yaiol)". Odlišné od původního mb_Upnp.dll.

Proč: uživatelé mohou nainstalovat yaiol vedle původního pluginu a porovnávat chování vedle sebe.


Systém odznaků - zobrazení stavu za běhu (mechanismus za F40)

Co: obecný vzor uživatelského rozhraní pro zobrazení důležitých podmínek za běhu jako viditelných barevných odznaků v dialogovém okně Nastavení. Aktuální případy:

  • ⚠ Max Conn (N04) – spustí se, když byl limit maximálního počtu připojení dosažen alespoň jednou od spuštění MusicBee. Příznak trvalé relace Plugin.MaxConnectionsHit. Nastaveno uvnitř WaitOnSendBarrier, když není volný slot.
  • ⚠ Vyžadován restart – spustí se, když uložené nastavení vyžaduje restart MusicBee, aby se projevilo. Příznak trvalé relace Plugin.RestartRequired. Nastaveno v obsluze uložení dialogového okna, když se nová trvalá hodnota liší od snímku za běhu (Plugin.activeMaxConnections, Plugin.activeServerPort, Plugin.activeIpAddress). Nastavení vyžadující restart jsou omezena na ta, která se skutečně nemohou za běhu znovu načíst – parametry vazby HTTP serveru a SemaphoreSlim vytvořený jednou při inicializaci.

Proč: soubor protokolu pluginu je v pořádku pro technické uživatele při ladění, ale netechnický uživatel, který se dívá na "zařízení zní špatně" nebo "přehrávání je pomalé", nikdy neotevře Diagnostika → Zobrazit protokol. Odznaky zachycují případy, kdy uživatel potřebuje vědět, že se něco stalo, a zobrazí to, až příště otevře plugin – zjistitelné bez čtení čehokoli.

Znovu použitelné pro budoucnost:

  • Detekována neshoda profilu (uživatelský agent zařízení se nikdy neshodoval s žádným profilem, došlo k fallbacku na Generic).
  • Spuštěn NextURI backoff (F13 - přehrávání bez mezer zakázáno pro relaci na nestabilním zařízení).
  • Skenování knihovny selhalo / bylo částečné.
  • Připojení rendereru ztraceno uprostřed relace.
  • Jakákoli jiná podmínka, kde "stalo se jednou, uživatel by měl vědět" převáží "tiše zaznamenáno mezi 1000 dalšími řádky".

Konvence implementace:

  • Popisky odznaků se nacházejí na úrovni dialogového okna (ne uvnitř žádného panelu), takže jsou viditelné bez ohledu na to, v jaké sekci se uživatel nachází.
  • Umístěny podél spodního řádku poblíž Uložit/Zrušit (aktuální: y=410 horizontálně naskládané).
  • Každý odznak má odpovídající příznak trvalé relace v Plugin, který se přepne na True, když nastane podmínka, a resetuje se pouze při restartu MusicBee.
  • Zdroje: <Condition>Badge (text popisku, s předponou ⚠) + <Condition>BadgeTip (tooltip vysvětlující příčinu + nápravu).
  • Pro odznaky "uložené nastavení vyžaduje restart" pořiďte snímek za běhu při Plugin.Initialise() a porovnejte s Settings.* po Settings.SaveSettings() v obsluze uložení dialogového okna.

N27 - Zrušit zahodí úpravy cest/šablon

Co: úpravy provedené v cestách a šablonách uvnitř dialogového okna nastavení jsou nyní zahozeny, když uživatel klikne na Zrušit, namísto tichého uplatnění, a jakákoli rezervovaná šablona odstraněná během relace je znovu vytvořena. (Šablony se jinak ukládají živě, jak jsou upravovány – na kartě Cesty není samostatné tlačítko Uložit.)

Proč: Zrušit by mělo znamenat zrušit. Dříve uživatel, který experimentoval se změnami cest/šablon a vrátil se zpět, zjistil, že změny již byly potvrzeny, bez možnosti je vrátit zpět, kromě ručního opakování každé z nich.


N28 - Doslovné ampersandy v menu výběru polí

Co: pole, jehož název obsahuje "&" – např. "Nálada & Kontext" – vykresluje ampersand doslovně v menu výběru polí namísto jeho pohlcení jako předpony Alt-mnemoniky.

Proč: názvy polí s ampersandem se zobrazovaly špatně (znak zmizel a další písmeno se stalo akcelerátorem), což ztěžovalo rozpoznání položky menu.


N29 - Stabilní, nepřeložený název okna nastavení

Co: název okna nastavení je pevně nastaven na značkový řetězec "MusicBee UPnP Plugin" a již se nemění s jazykem rozhraní; řetězec DialogTitle pro jednotlivé jazyky byl odstraněn z každého lokalizačního balíčku.

Proč: název okna, který měnil znění podle jazyka, byl přeložitelnou plochou bez přínosu – název je značka. Jeho upevnění jej udržuje stabilní a konzistentní všude.

Lokalizace

Původní plugin je pouze v angličtině. Tento fork je plně lokalizovatelný – každý řetězec pro uživatele prochází balíčkem zdrojů a plugin automaticky detekuje vlastní jazyk uživatelského rozhraní MusicBee.

N30 - Vícejazyčné uživatelské rozhraní (překlady čekají)

Co: lokalizační mechanismus je kompletní a dodáván. Localisation.vb čte vybraný jazyk MusicBee z MusicBee3Settings.ini (endonym <SystemLanguage>) a aplikuje odpovídající .NET kulturu na vlákno, takže My.Resources.Resources.* vrací lokalizovaný řetězec. Každý uživatelsky viditelný popisek/tlačítko/zpráva je propojen s klíčem zdroje (ovládací prvky návrháře přes ApplyDesignerExtras + sync-en-locale.js; řetězce za běhu jako WarnPortInUse ručně přidány). Co není ještě hotovo, je samotný překlad: existuje pouze anglický zdrojový balíček (Resources.resx) – satelitní balíčky pro ostatní jazyky jsou vytvořeny v jedné dávce, až bude plugin kompletní (překládání po částech, zatímco se řetězce stále mění, je plýtvání úsilím).

Cílové jazyky (sada, kterou nabízí samotný MusicBee, shodná 1:1 s endonymToCulture, takže plugin automaticky sleduje jazyk MusicBee):

Arabština (ar) Čeština (cs) Němčina (de) Řečtina (el)
Španělština (es) Francouzština (fr) Maďarština (hu) Italština (it)
Korejština (ko) Nizozemština (nl) Norština (nb) Polština (pl)
Portugalština BR (pt-BR) Portugalština PT (pt-PT) Švédština (sv) Turečtina (tr)
Ukrajinština (uk) Ruština (ru) Japonština (ja) Zjednodušená čínština (zh-CN)
Tradiční čínština (zh-TW) Angličtina (en, zdroj)

Politika variant (dle pravidla lokality pracovního prostoru): PT a ZH jsou rozděleny do odlišných balíčků, protože slovní zásoba/skript se skutečně liší (pt-BR/pt-PT, zh-CN/zh-TW). EN je jediný balíček – "English(US)" (en-US) MusicBee se vrací k en přes řetězec kultur .NET, takže není vytvořen žádný samostatný balíček pro USA. ES a FR jsou rovněž jednolokální.

Proč: nastavení UPnP pluginu ("nepoužívat raw PCM", "vynutit little-endian PCM", varování o fallbacku portu) jsou dostatečně kryptická i v rodném jazyce. Následování vlastního jazyka uživatelského rozhraní MusicBee – namísto vynucování angličtiny – je rozdíl mezi nástrojem, který si uživatel, který nemluví anglicky, může nakonfigurovat, a nástrojem, který nemůže. Ani jeden upstream se o to nepokusil.


N31 - Odkaz na nápovědu se otevírá v plném jazyce rozhraní

Co: otevření odkazu na nápovědu z pluginu respektuje kompletní jazyk rozhraní uživatele (např. pt-BR, zh-CN) namísto zhroucení na základní jazyk a odesílá jasnější identifikátor kontroly aktualizací.

Proč: uživatel používající MusicBee v regionální variantě (brazilská portugalština, zjednodušená čínština) byl přesměrován na stránku nápovědy v základním jazyce. Přenesení plné kultury je přivede na stránku nápovědy v přesném jazyce, který používají.

Opravy a vylepšení původního pluginu

Základní protokol a přehrávání

F01 - Aktualizované výchozí profily zařízení DLNA

Co: dodává nové výchozí profily pro PlayStation 4, Xbox 360/One a moderní BubbleUPnP, s příznaky schopností (vzorkovací frekvence, bitové hloubky, kodeky), které odrážejí to, co tato zařízení dnes skutečně podporují.

Proč: výchozí nastavení původního pluginu byla zmrazena kolem roku 2014. PS4/Xbox/BubbleUPnP od té doby získaly podporu hi-res zvuku. Po instalaci hraje nová instalace na těchto zařízeních nejlépe ve své třídě, aniž by uživatel musel sahat na nastavení profilu zařízení.


F02 - Ovládání zařízení, která inzerují MediaRenderer:3

Co: plugin zkoumá popis UPnP služby rendereru, aby rozhodl, zda jej MusicBee může ovládat. Původní verze odpovídala pouze urn:schemas-upnp-org:device:MediaRenderer:1. Moderní zařízení inzerují :2 nebo :3. F02 rozšiřuje shodu.

Proč: bez toho se nedávné jednotky Sonos / WiiM / Eversolo jednoduše nezobrazují jako cíle v seznamu zařízení "Přehrát do" MusicBee – i když mluví stejným protokolem. Jednoduchá oprava shody předpony řetězce odemyká celou moderní generaci zařízení.


F03 - Možnost "Vynutit nativní stream" pro každý profil (výchozí ZAPNUTO)

Co: po zaškrtnutí plugin odesílá původní bajty souboru do zařízení bez transkódování, bez DSP, bez zpracování ReplayGain. Jen syrový soubor, který uživatel vybral, bajt po bajtu (s výjimkou HTTP rámování).

Proč: podle svědectví z fór je to největší přínos pro kvalitu přehrávání. Hi-fi uživatelé kupující drahé renderery výslovně chtějí bit-perfect výstup; jakýkoli zásah DSP ruší smysl. Výchozí ZAPNUTO, protože většina moderních zařízení zvládne jakýkoli kodek, který jim uživatel předhodí, a ReplayGain/EQ by měly být volitelné. Je to pro každý profil, takže můžete zachovat transkódování pro starý Xbox a zároveň posílat nativní stream do hi-fi DAC.


F04 - "Vynutit transkódování" pro každý profil

Co: přepsání pro každý profil, které vynutí každý stream do tohoto zařízení přes transkodér, bez ohledu na podporu nativního kodeku. Inverze F03 (ForceNativeStream). Vzájemně se vylučuje s F03 – UI automaticky odškrtne druhý, když je jeden z nich zapnut.

Proč: jediný globální přepínač by byl v rozporu s ForceNativeStream (F03) pro každý profil. Reálný případ: zařízení A je hi-fi DAC, které chce bit-perfect nativní streamy; zařízení B je starý AV receiver, který se dusí na FLAC. S globálním přepínačem si uživatel musí vybrat – na úkor druhého zařízení. S profilem pro každé zařízení získá každé zařízení správnou odpověď.

Implementace:

  • StreamingProfile.ForceTranscoding As Boolean = False.
  • Schéma perzistence zvýšeno na v9. Soubory před v9 načtou starou globální hodnotu jednou a zkopírují ji do všech profilů, čímž zachovají staré chování po upgradu.
  • UI: odstraněno z panelu Diagnostika, přidáno do sekce Profily zařízení vedle ForceNativeStream. Obousměrné obsluhy vzájemného vyloučení (CheckedChanged na každém odhlásí druhý před přepnutím, aby se zabránilo nekonečné smyčce).
  • Místo rozhodování: Settings.ForceTranscodingstreamingProfile.ForceTranscoding v WriteAudioFileDIDL.

F05 - "Vynutit little-endian PCM" pro každý profil

Co: PCM streamy (mime typy L16/L24) jsou podle specifikace big-endian. Některá zařízení chybně očekávají little-endian a přehrávají bílý šum, když dostanou správná big-endian data. F05 přepíná pořadí bajtů pro každý profil.

Proč: bez toho některá zařízení vydávají stěnu statického šumu. Symptom je dramatický a příčina neviditelná bez znalosti kódování PCM – přepínač dává uživatelům možnost opravy metodou pokus-omyl.


F06 - "Nepoužívat Raw PCM" pro každý profil

Co: když zařízení tvrdí, že podporuje raw PCM, plugin to použije. Některá zařízení lžou – přijmou SOAP handshake, ale zkomolí skutečná raw PCM data, zatímco správně zpracovávají PCM zabalené v kontejneru WAVE. F06 vynutí PCM-over-Wave bez ohledu na to, co zařízení inzeruje.

Proč: konkrétně některé modely Marantz – inzerují raw PCM, ale funguje pouze WAVE. Bez toho jsou raw PCM streamy zkreslené, bez chybové zprávy, která by na to poukázala.


F07 - "Délka obsahu" pro každý profil

Co: jakou hodnotu odeslat v HTTP hlavičce Content-Length. Čtyři možnosti:

  • Výchozí – skutečný počet bajtů, pokud je znám, vynechat, pokud je neznámý.
  • Žádné – nikdy neodesílat hlavičku (pouze chunked encoding).
  • Pouze PCM – odesílat pouze pro raw PCM; vynechat pro vše ostatní.
  • Pevné – odeslat UInt32.MaxValue - 8192 (sentinel pro "obrovskou neznámou délku").

Proč: UPnP/DLNA zařízení se divoce liší v tom, jak reagují na Content-Length. Některá potřebují přesné číslo, některá to u streamů nenávidí, některá potřebují sentinel "opravdu velkou" hodnotu, aby udržela bufferování. Toto bylo později rozšířeno z pouze PCM na všechny výstupní formáty, protože stejné problémy se objevily u transkódovaných MP3/AAC streamů.


F08 - "Nevymazávat NextURI" pro každý profil

Co: normálně plugin vymaže zařízení zařazené NextURI, když se fronta vyprázdní (odesláním SetNextAVTransportURI s prázdnou URL). Některá zařízení (zejména Denon) interpretují prázdné NextURI jako "zastavit vše" a okamžitě zastaví přehrávání. F08 zabraňuje pluginu v jeho vymazání.

Proč: bez toho majitelé Denonu zažívají, že zařízení přeruší přehrávání uprostřed skladby, když se fronta vyprázdní. S zaškrtnutým F08 zařízení udržuje zastaralé NextURI v paměti (neškodné – jednoduše se přepíše, až bude příště něco zařazeno do fronty).


F09 - FLAC jako výstupní formát transkódování

Co: rozbalovací nabídka formátu transkódování v profilech zařízení nyní nabízí FLAC vedle PCM 16/24, MP3, AAC, Ogg. Jeho výběr směruje BASS kodér přes standardní příkazový řádek pro převod FLAC MusicBee (stejný mechanismus, který již používají MP3/AAC/Ogg).

Proč: pro zařízení, která dobře zpracovávají FLAC, ale nedokážou dekódovat zdrojový kodek (např. Eversolo přijímající knihovnu WMA z MusicBee převedenou na FLAC), to zachovává bezztrátovou kvalitu tam, kde by MP3/AAC zahodily zvuková data. Odblokuje N02 (ovládání downmixu 5.1), které by nebylo možné řešit bez možnosti bezztrátového transkódování.

Implementace: jednořádkové přidání do bloku Select Case Codec v Encoder.StartEncode – FLAC se připojuje k MP3/AAC/Ogg ve větvi řízené příkazovým řádkem. Rozbalovací nabídka UI získává "FLAC" jako 6. možnost. Mapování načítání/ukládání v SettingsDialog se rozšiřuje tak, aby rozpoznalo FileCodec.FlacSelectedIndex = 5. Typ Mime, DLNA typ a funkce kódování byly již propojeny v ItemManager.GetMimes / GetDlnaType / GetEncodeFeature z dřívější práce (F21, F26).


Přehrávání bez mezer (SetNextAVTransportURI)

F10 - Jádro SetNextAVTransportURI / NextURI

Co: skutečné přehrávání bez mezer. Když zařízení inzeruje podporu pro SetNextAVTransportURI ve svém popisu UPnP služby, plugin předem zařadí další skladbu do fronty na zařízení, než skončí ta aktuální. Zařízení interně přechází bez slyšitelné mezery mezi skladbami – to, co slyšíte na CD přehrávači. Toto není hack "nepřetržitého streamu" (který vše zřetězí do jednoho dlouhého streamu a ztrácí metadata pro jednotlivé skladby).

Proč: vlajková loď funkce Tier-2. Alba nahraná jako nepřetržité živé vystoupení (živé nahrávky, klasické skladby, DJ sety) zní špatně, když je mezi skladbami půlsekundové ticho. Řešení tohoto problému správně je vlajková loď funkce, nyní v tomto forku.

Poznámky: zařazený zvuk je obsluhován přes HTTP server pluginu pomocí streamHandle=0 (režim načítání knihovny), což znamená, že zvukový engine MusicBee není zapojen do smyčky pro zařazenou skladbu. Kompromis: efekty ReplayGain/DSP/EQ se nevztahují na další skladbu. Přijatelné, když je zapnuto "vynutit nativní stream" (výchozí).


F11 - "Zakázat podporu NextURI" pro každý profil

Co: i když zařízení inzeruje SetNextAVTransportURI, toto zaškrtávací políčko nutí plugin ignorovat tuto reklamu a vrátit se k přehrávání jedné skladby po druhé.

Proč: některá zařízení inzerují NextURI, ale mají chybnou implementaci (pády, poloviční přechody, zamrzání). Namísto reverzního inženýrství každého rozbitého zařízení dostane uživatel přepínač "prostě to zde vypni".


F12 - Životní cyklus NextURI v seznamu právě přehrávaných

Co: když MusicBee spustí NowPlayingListChanged, plugin znovu vyhodnotí, co by mělo být zařazeno do fronty pro přechod bez mezer. Požádá MusicBee o novou "další" skladbu přes NowPlayingList_GetNextIndex(1) + NowPlayingList_GetListFileUrl, porovná ji s tím, co je aktuálně zařazeno na zařízení (sledováno přes nové pole nextPlaySourceUrl), a znovu zařadí, pokud se změnila (nebo vymaže frontu, pokud MusicBee říká, že není žádná další skladba).

Proč: bez F12 zařízení pokračovalo v přehrávání zastaralého NextURI, když uživatel odstranil/přeskupil zařazenou skladbu. To historicky trvalo několik iterací, protože každá mutace seznamu vyžaduje odlišné zpracování – my jsme to zjednodušili důvěrou v NowPlayingList_GetNextIndex (který již respektuje náhodné přehrávání a opakování všech skladeb), takže všechny varianty procházejí stejným porovnáním.

Implementace:

  • Nové pole nextPlaySourceUrl ukládá URL knihovny MusicBee toho, co je zařazeno do fronty (streamovací URL s příponou handle není srovnatelná s cestou knihovny).
  • Nová Public Sub RefreshQueuedNextUri() na MediaRendererDevice. Tři výsledky: žádné NextURI ve frontě → no-op; zařazené odpovídá novému "dalšímu" → no-op; zařazené se liší → volání QueueNext s novou URL (nebo QueueNext("") pro vymazání – což respektuje F08 DoNotClearNextUri).
  • Propojeno v Plugin.ReceiveNotification pod NotificationType.NowPlayingListChanged.

F13 - NextURI zpomalení při selhání

Co: po 4 po sobě jdoucích selháních SetNextAVTransportURI na stejném zařízení plugin zakáže přehrávání bez mezer pro toto zařízení, dokud se MusicBee nerestartuje.

Proč: pokud je zařízení skutečně rozbité pro NextURI (přerušované SOAP chyby, síťové závady), plugin by jinak stále opakoval pokusy u každé skladby. F13 zastaví šum a tiše se vrátí k přehrávání jedné skladby po druhé.


F14 - Integrace režimu opakování + NextURI

Co: F14 se dělí na dva případy zpracované detektorem přechodu F15 v OnAvTransportStatusCheck:

  • Opakovat vše: MusicBee předává správnou "zabalovací" URL (skladba 1 na konci seznamu) samotnému Plugin.QueueNext. Není potřeba žádná speciální logika pluginu – zařízení na ni přejde a detektor F15 volá Player_PlayNextTrack jako obvykle, což vrátí index NPL MusicBee zpět na 0.
  • Opakovat jednu: MusicBee předává STEJNOU URL skladby Plugin.QueueNext. Zařízení na ni přejde (nový stream handle, stejný zdroj). Detektor F15 nyní dotazuje Player_GetRepeat() – pokud je to RepeatMode.One, přeskočí volání Player_PlayNextTrack, takže MusicBee neposune index NPL pryč od opakující se skladby.

Proč: bez přeskočení Repeat-One by volání Player_PlayNextTrack při přechodu bez mezer posunulo MusicBee na další skladbu v seznamu (Repeat-One ovlivňuje pouze chování automatického posunu na konci skladby v uživatelském rozhraní přehrávače – Další skladba se vždy posune vpřed), což by bylo v rozporu s tím, co znamená Repeat-One.

Upozornění k počtu přehrání: v režimu Repeat-One závisí zvýšení počtu přehrání na tom, zda MusicBee 3.7.9563+ zaznamená opakované přehrávání. Starší verze MusicBee přehrávají opakování bez mezer správně, ale nezaznamenají zvýšení počtu přehrání. Zdokumentováno; neblokující.


F15 - Stavový automat detekce přechodu skladeb

Co: když zařízení interně přechází z aktuální skladby na NextURI, plugin to musí zaznamenat a říct MusicBee, aby posunul svůj index právě přehrávané skladby. Jinak si MusicBee myslí, že je stále na předchozí skladbě a počty přehrání / UI / scrobbling se rozcházejí.

Implementace: dotazuje GetPositionInfo.TrackURI při každém tiknutí časovače stavu. Když nahlášené URI odpovídá tomu, které jsme zařadili přes NextURI, voláme Player_PlayNextTrack na MusicBee a nastavíme suppressNextSoapCall, aby výsledné PlayToDevice znovu neodeslalo SetAVTransportURI (což by přerušilo přehrávání bez mezer).

Proč: bez F15 zařízení přehrává další skladbu, ale uživatelské rozhraní MusicBee říká, že je stále na předchozí. Matoucí, narušuje scrobbling, narušuje sledování počtu přehrání. Detekce přechodu skladeb vyžaduje dlouhou iteraci pro každý renderer, protože každá značka rendereru má své vlastní zvláštnosti v tom, kdy hlásí změnu URI (některé hlásí nejprve TRANSITIONING, některé přeskočí rovnou na PLAYING s novým URI, některé mají krátké STOPPED mezi tím).

Poznámky: naše první verze funguje na rendereru BubbleUPnP. Okrajové případy pro jednotlivá zařízení zůstávají v B6.


F16 - Oprava prasknutí při přechodu bez mezer

Co: prasknutí nastane, když se formát zdroje (vzorkovací frekvence / kanály / kodek) zařazené skladby liší od aktuálně přehrávané skladby, což nutí DAC zařízení k opětovnému uzamčení při přechodu. F16 přidává diagnostiku NextUri:FormatChange, která se spustí v době zařazení do fronty, kdykoli se formáty liší, a pojmenuje obě strany – takže uživatelé slyšící prasknutí mohou korelovat.

Diagnostika také ukazuje na zmírnění: zaškrtněte Vynutit transkódování v profilu zařízení. To homogenizuje každou skladbu na jeden transkódovací kodek/vzorkovací frekvenci/bitovou hloubku, čímž zcela eliminuje rozdíl ve formátu zdroje.

Proč odloženo pro skutečnou opravu transkódování na shodu: strukturální oprava (transkódování zařazené skladby tak, aby odpovídala formátu přehrávané skladby) vyžaduje změny v URL schématu HTTP serveru pluginu – aktuálně /encode/{id}0.{ext} obsluhuje zařazený soubor nativně. Budoucí v2 F16 by přidala trasy /encode/{id}0_{rate}_{depth}.{ext} pro každý formát a propojila je přes kodér. To je větší architektonická změna, kterou stojí za to provést, pokud skutečné zařízení vykazuje prasknutí poté, co ForceTranscoding nestačí.

Implementace dnes:

  • Pole lastSourceUrl sleduje aktuálně přehrávanou zdrojovou URL.
  • QueueNext čte FilePropertyType.SampleRate/Channels/Kind pro aktuální i zařazené skladby a zaznamenává NextUri:FormatChange při neshodě.

F17 - Resynchronizace ukazatele průběhu po vyhledávání

Co: funkce Seek() již volala GetPlayPositionInformation() po úspěšném Seek SOAP, což opravuje případ "žádná resynchronizace vůbec". F17 řeší zbývající posun až o 1 sekundu způsobený 1sekundovou kvantizací RelTime UPnP: když se hlášená pozice zařízení zaokrouhlí na méně než 1 sekundu od požadovaného cíle uživatele, plugin nyní důvěřuje uživatelově subsekundově přesné hodnotě namísto zkrácení zařízením. Pouze když zařízení hlásí něco dramaticky odlišného (>1s mimo), použijeme jeho hodnotu (vyhledávání přistálo jinde, než bylo požadováno, např. skok na klíčový snímek u některých kodeků).

Proč: bez toho by vyhledávání na 2:30.500 ukotvené proti hlášení zařízení "2:30" způsobilo, že by ukazatel průběhu ukazoval ~500ms za realitou. Po F17 se ukazatel shoduje se záměrem uživatele pro běžný případ posunu uvnitř skladby a stále respektuje hlášení zařízení pro odlehlý případ skoku na klíčový snímek.


F18 - Blokování nepřetržitého streamu / NextURI

Co: nyní jsou zavedeny dvě blokády:

  1. Za běhu: QueueNext vrátí False dříve, když je zapnuto Settings.ContinuousOutput. Nepřetržitý stream je jeho vlastní mechanismus bez mezer (jeden dlouhý zřetězený stream); odesílání SetNextAVTransportURI navrch mate zařízení ohledně toho, zda je každá skladba diskrétní URI nebo součástí nepřetržitého toku.
  2. UI: když uživatel zaškrtne globální zaškrtávací políčko nepřetržitého streamu, forceNativeStream aktuálně zobrazeného profilu se automaticky odškrtne. Nepřetržitý stream vždy transkóduje, takže vynucení nativního streamu je v kombinaci bezvýznamné.

Proč: zabraňuje uživateli povolit dva konfliktní mechanismy přehrávání bez mezer současně. Bez F18 by zařízení obdrželo jak URI nepřetržitého streamu, tak NextURI pro každou následující skladbu, s nedefinovaným chováním v závislosti na rendereru.


F19 - Ignorování prázdných chyb NextURI

Co: když je SetNextAVTransportURI voláno s prázdnou URL (např. poslední skladba v seznamu), některá zařízení vrátí SOAP chybu. F19 tyto chyby tiše potlačí – zaznamená je, ale nešíří je jako chyby.

Proč: podmínka "žádná další skladba" je normální, nikoli chyba. Považování za fatální znečišťuje protokol a (v některých tocích) spouští bouře opakovaných pokusů.


Mime typy a DLNA metadata

F20 - MP3 mime → audio/mpeg

Co: standardům odpovídající MP3 mime typ je audio/mpeg, nikoli audio/mp3. Ten druhý je běžný nesprávný název, který většina zařízení toleruje, ale přísnější renderery jej odmítají.

Proč: tiše opravuje přehrávání na přísnějších zařízeních, která dodržují standard. Kódová základna yaiol to již měla správně; žádná změna nebyla potřeba.


F21 - Pořadí mime typů: nejprve varianta bez x-

Co: když zařízení inzeruje audio/flac i audio/x-flac, plugin vrátí nejprve variantu bez x-. Totéž platí pro jakýkoli kodek se standardními i experimentálními mime typy.

Proč: předpona x- označuje experimentální/neoficiální mime typy. Některé renderery se chovají lépe se standardní formou. Malé přeřazení, reálný dopad.


F22 - Podpora mime typu Opus

Co: rozpoznává Opus jako streamovatelný zvukový kodek; odesílá audio/opus mime při obsluze Opus skladeb.

Proč: Opus je nyní běžný (moderní kompromisní kodek pro řeč/hudbu). Bez F22 by plugin odmítl streamovat soubory Opus i do zařízení, která je zpracovávají.


F23 - Podpora zdrojových souborů Monkey Audio (APE)

Co: rozpoznává soubory .ape jako platný zdrojový kodek pro streamování/transkódování.

Proč: APE je bezztrátový formát s malou, ale loajální uživatelskou základnou. Jeho přidání stojí málo a odemyká knihovnu pro tyto uživatele.


F24 - AAC / ALAC mime fallback

Co: pokud zařízení podporuje AAC nebo ALAC, ale explicitně je neinzeruje ve svém popisu UPnP služby, plugin je přesto nabízí jako fallback.

Proč: několik zařízení, která AAC zpracovávají dobře, zapomnělo jej uvést ve svém XML s možnostmi. Bez F24 se plugin ani nepokusí, čímž vynutí transkódování. S F24 se plugin pokusí a nechá zařízení, aby to zpracovalo nativně, pokud to dokáže.


F25 - Příznak typu DLNA pro nativní + kódované WAV streamy

Co: příznak typu DLNA (identifikátor profilu jako LPCM, WAVE, MP3) musí odpovídat tomu, co zařízení přijímá. F25 zajišťuje, že nativní streamy a kódované WAV streamy jsou správně označeny.

Proč: neshodný typ DLNA způsobuje, že některá zařízení zcela odmítnou přehrávání nebo použijí špatný dekodér.


F26 - DLNA hlavička pro soubory FLAC

Co: FLAC streamy získávají správný identifikátor DLNA profilu ve svých hlavičkách.

Proč: bez toho některá zařízení, která podporují FLAC, stream jako takový nerozpoznají.


F27 - Oprava výpočtu bitrate v metadatech

Co: res@bitrate nepřetržitého streamu bylo počítáno jako (sampleRate * channels * bitsPerSample) / 1000 – kbps, což bylo mimo o faktor ~125 od specifikace UPnP DIDL, která definuje atribut jako bajty za sekundu. Nyní se dělí 8 namísto 1000.

Proč: špatné zobrazení bitrate na zařízení – kosmetické u většiny rendererů, ale některé alokují streamovací buffery z hodnoty a zadrhávají se u streamů, které vypadají ~125× menší, než ve skutečnosti jsou. Cesta k nespojenému zdrojovému souboru to již měla správně ((bitrate_kbps * 1000) \ 8 = bajty/s); špatná byla pouze cesta nepřetržitého streamu.


F28 - Oprava formátu času metadat (Marantz)

Co: res@duration v DIDL bylo formátováno jako H:MM:SS (např. 0:03:42). Specifikace UPnP DIDL definuje formát jako H+:MM:SS[.F+] – striktně s volitelnými, ale doporučenými zlomkovými sekundami; některá zařízení Marantz považují holou formu za neplatnou a nechávají zobrazení délky prázdné. Nyní formátováno jako H:MM:SS.fff (např. 0:03:42.000).

Proč: problém zobrazení specifický pro značku; konformní formát ve stylu ISO se zlomkovými sekundami to opravuje, aniž by ovlivnil jakékoli jiné zařízení. Aplikováno na obou místech emise DIDL (cesta zdrojového souboru + cesta kódovaného streamu v WriteAudioFileDIDL).

Bonusová oprava ve stejném průchodu: pv:addedTime a pv:lastPlayedTime používaly hh (12hodinový formát) ve svých formátovacích řetězcích DateTime namísto HH (24hodinový). Jakákoli skladba přidaná nebo přehrávaná mezi 13:00 a 23:59 by se zobrazila s chybnou hodinou (např. 17:42 → "05:42") na zařízeních, která toto pole zobrazují. Nyní používá HH.


F29 - Podpora vyhledávání v kódovaných MP3 (CBR)

Co: transkódované MP3 streamy nyní inzerují DLNA.ORG_OP=11 (vyhledávání podle bajtů i času) namísto DLNA.ORG_OP=10 (pouze podle bajtů). Zařízení, která dříve odmítala vyhledávání podle času u transkódovaných MP3, nyní mohou normálně ovládat svůj ukazatel průběhu/vyhledávací UI.

Proč: transkodér MusicBee produkuje MP3 s konstantním bitrate při předvolbě HighQuality, takže mapování bajtů ↔ času je lineární – zařízení může převést požadavek na vyhledávání podle času na HTTP Range vyhledávání podle bajtů samo, bez jakékoli podpory na straně kodéru. Inzerování OP=11 odemyká toto UI na zařízení. Bez F29 uživatelé, kteří vyhledávali uvnitř transkódovaného MP3, buď měli vyhledávání tiše ignorováno, nebo byli přesměrováni na začátek skladby.

Implementace: restrukturalizováno GetEncodeFeature v ItemManager.vb tak, aby se inline If rozdělilo na čitelný řetězec If/ElseIf/Else. MP3 explicitně dostává OP=11; ostatní non-PCM kodeky si ponechávají OP=10. Žádná změna pro AAC/FLAC/atd. – ty by vyžadovaly ověření CBR-ness specifické pro kodek, což MusicBee nezaručuje.


F30 - Zpracování přípony souboru .mpeg

Co: soubory s příponou .mpeg (a ještě vzácnější .mpe) jsou nyní rozpoznány jako FileCodec.Mp3 v GetCodec. Před F30 vracely FileCodec.Unknown a byly tiše odmítnuty z knihovny / nemohly být zdrojem pro transkódování.

Proč: staré archivy MPEG-1 Layer 3 někdy používaly .mpeg namísto .mp3 (specifikace umožňuje obojí). Hrsta souborů v knihovně o 300 tisících je dost na to, aby uživatel cítil "MusicBee je ukazuje, ale plugin ne" – matoucí pro uživatele.


Chování přehrávání

F31 - Rádiové streamy automaticky používají nepřetržitý režim

Co: WriteAudioFileDIDL nyní zkoumá vlastnost Kind zdrojové URL přes Library_GetFileProperty a považuje jakýkoli soubor, jehož Kind končí na "Stream" (MusicBee hlásí "MP3 Stream", "Internet Stream" atd. pro rádio) za nepřetržitý bez ohledu na globální přepínač Settings.ContinuousOutput. Používá se větev DIDL pro nepřetržitý stream (Název: "Nepřetržitý stream", id="continuousstream", pevný PCM/Wave výstup); zařízení vidí jeden stream nekonečného stylu.

Proč: rádiové streamy nemají hranice skladeb, pevnou délku ani možnost vyhledávání. Zacházení s nimi jako s diskrétními soubory v DIDL způsobilo, že plugin inzeroval rozsahy bajtů a délky, které neexistují. Automatické přepínání, když nám MusicBee již řekl "toto je stream", odstraňuje problém, o kterém by uživatel neměl přemýšlet.

Rozsah: platí pouze, když MusicBee řídí přehrávání (musicBeePlayToMode). Cesta načítání knihovny (procházení UPnP klientem) je beze změny – URL rádií jsou tam vzácné a chování pro uživatele by se nemělo měnit bez explicitního testování.


F32 - Fallback inzerce kodeků

Co: pokud zařízení neinzeruje určité kodeky (nebo plugin nemůže parsovat XML s možnostmi zařízení), plugin stream okamžitě neodmítne. Místo toho se pokusí jej obsloužit a nechá zařízení rozhodnout.

Proč: mnoho zařízení má neúplné nebo nečitelné XML s možnostmi, ale ve skutečnosti kodek zpracovávají bez problémů. F32 vyměňuje malé "nejlepší odhad a zkusit" za přímé odmítnutí.


F33 - Zlepšení synchronizace ukazatele průběhu

Co: pozice mezi dotazy je již extrapolována podle reálného času z jednoho kotvícího bodu (currentPlayStartTicks), takže ukazatel průběhu se plynule aktualizuje s subsekundovou frekvencí. Zbývajícím zdrojem chvění byl počáteční kotvící bod pro nově spuštěnou skladbu: předchozí kód předpokládal position=0 v okamžiku, kdy časovač stavu poprvé zaznamenal, že stav přešel na Přehrávání, ale do té doby mohlo zařízení přehrávat 100-500 ms (jeden interval dotazování). Ukazatel průběhu MusicBee by začal na 0, poté by skočil dopředu, když se realita dohnala.

Oprava F33: při prvním přechodu do stavu Přehrávání u nové skladby (currentPlayStartTimeEstimated=True) zavolejte GetPlayPositionInformation(), abyste získali skutečnou aktuální pozici zařízení, a poté se proti ní ukotvěte. UPnP hlásí pouze rozlišení 1 sekundy, takže kotva je stále kvantizovaná, ale je mnohem blíže pravdě než předpokládat 0.

Proč: plynulejší + přesnější zobrazení průběhu, zejména hned po změně skladby. Není cesty, jak obejít samotné 1sekundové rozlišení hlášení UPnP – to je specifikace.


F34 - Chvění ukazatele průběhu po změně skladby

Co: když je volána PlayToDevice pro novou skladbu, plugin dříve ponechával currentPlayPositionMs a currentPlayStartTicks na jejich hodnotách z předchozí skladby po dobu ~100ms okna mezi SOAP-Play a prvním dotazem časovače stavu detekujícím nový stav Přehrávání. Ukazatel průběhu MusicBee by krátce zobrazil konec předchozí skladby, poté by se vrátil na 0 a poté stoupal. F34 vynuluje obě hodnoty při vstupu do PlayToDevice – v okamžiku, kdy víme, že dochází ke změně skladby, před jakoukoli prací SOAP.

Proč: vizuální chyba při rychlém přeskakování (ruční další nebo přechod bez mezer). Nyní první dotaz MusicBee na PlayPositionMs po Play vrátí čistě 0, poté GetPlayPositionInformation z F33 upřesní na skutečnou pozici zařízení při prvním tiknutí změny stavu.

Implementace: čtyři řádky na začátku PlayToDevice, spárované s přesným ukotvením F33 v době přechodu.


F35 - Chyba "Vynutit transkódování"

Co: vynucené transkódování mohlo stále přeskočit transkódování v určitých kombinacích. Po přepracování F04 pro každý profil byly uzavřeny dvě specifické mezery:

  1. Priorita s ForceNativeStream. Když byly obě True (což se může stát při migraci schématu nebo částečném souboru nastavení), ForceTranscoding nyní jednoznačně vyhrává (If streamingProfile.ForceTranscoding Then forceEncode = True ElseIf streamingProfile.ForceNativeStream Then forceEncode = False). Vzájemné vyloučení v UI zabraňuje uživateli zaškrtnout obě, ale runtime ochrana řeší jakýkoli stav, který se načetl nekonzistentně z disku.
  2. Logika bypassTranscodeDecision. Dříve: streamingProfile.ForceNativeStream AndAlso Not Settings.ForceTranscoding. Nyní: streamingProfile.ForceNativeStream AndAlso Not streamingProfile.ForceTranscoding – stejné pravidlo priority, ale ve stejném rozsahu pro každý profil.

Proč: "vynutit" by mělo znamenat vynutit. Pokud uživatel explicitně povolil ForceTranscoding pro zařízení, plugin nesmí nikdy tiše přejít na nativní streamování, bez ohledu na to, jak se ostatní příznaky zkombinují.


F36 - Výjimka zavřeného rendereru

Co: obaleno Plugin.ReceiveNotification v top-level Try/Catch, které zaznamenává jakoukoli nezachycenou výjimku namísto toho, aby ji nechalo šířit zpět do notifikační pumpy MusicBee.

Proč: oznámení z MusicBee (PlayStateChanged, VolumeMuteChanged atd.) se odesílají do ControlPointManager, který komunikuje s rendererem přes SOAP. Jednotlivá místa volání již měla Try/Catch kolem svých SOAP volání, ale dostatečně zvláštní časový případ (např. renderer umírající mezi dvěma SOAP voláními ve stejném obslužném programu oznámení) by stále mohl uniknout. Top-level wrapper je poslední záchranná síť, takže uživatel nikdy neuvidí generické vyskakovací okno "TargetInvocationException" z MusicBee.

Implementace: přejmenováno stávající tělo na ReceiveNotificationInternal a přidán tenký wrapper ReceiveNotification, který provádí Try { ReceiveNotificationInternal(...) } Catch { LogError(...) }. Již existující infrastruktura Try/Catch pro každou metodu uvnitř ControlPointManager (kolem každého volání PostSoapRequest) zůstává – F36 je pojistka navíc.


F37 - Vyhledávání v dlouhé skladbě spouštějící falešný přechod

Co: vyhledávání uvnitř dlouhé skladby může na některých rendererech vyvolat krátký cyklus Zastaveno→Přehrávání. Bez rozlišení ProcessNewPlayState.Stopped to považuje za přirozený konec skladby a volá Player_PlayNextTrack, čímž posune MusicBee, když uživatel chtěl pouze posunout. F37 označuje lastUserInitiatedSeek v Seek() a přidává 5sekundovou ochranu v obsluze Zastaveno (zrcadlící existující okno lastUserInitiatedStop).

Proč: tiché přeskočení na další skladbu během vyhledávání je jednou z těch chyb, u kterých nikdo nemůže uhodnout příčinu – uživatel si myslí "divné, zkusil jsem posunout vpřed a teď hraje další píseň". Oprava je mechanická: stejný vzor jako již zavedené rozlišení uživatelského zastavení.


F38 - Vylepšené zpracování vyhledávání pro kodeky náchylné k pádům

Co: pád BubbleUPnP při vyhledávání v MP3 byl kanonickým symptomem. Po auditu stávající kód vyhledávání yaiol již dělá správné věci – nativní cesta správně zpracovává HTTP Range (206, Content-Range, AcceptRanges), kódovaná cesta inzeruje X-AvailableSeekRange a parsuje příchozí hlavičky timeSeekRange.dlna.org / npt, příznaky DLNA.ORG_OP odrážejí skutečné možnosti streamu (s DisablePcmTimeSeek opt-out pro problémová zařízení Platinum). Uživatelsky testováno na aktuálním BubbleUPnP 4.6.4: žádné pády nebyly pozorovány.

Proč: pád BubbleUPnP při vyhledávání v MP3 byl hlášen kolem roku 2024 a aplikace od té doby prošla ~16 měsíci oprav. F29 (kódované MP3 OP=11) byla nová proměnná, která by to mohla znovu odhalit; na testovaných verzích se tak nestalo.

Pokud se pád vrátí: tvar opravy by byl přepínač "omezené vyhledávání" pro každý profil, který vynutí DLNA.ORG_OP=10 (pouze bajty) u označených kodeků – zrcadlící, jak již DisablePcmTimeSeek funguje pro PCM. Přidat pak, ne preventivně.


UI a protokolování

F39 - Tlačítko "Přidat" vybere nový profil

Co: kliknutí na "Přidat" v seznamu profilů zařízení vytvoří nový profil A automaticky jej vybere, takže uživatel může okamžitě upravovat pole. Naše refaktorování sekčního dialogu to již dělá – jak přímá cesta Přidat, tak cesta z šablony končí Me.activeStreamingProfiles.SelectedIndex = Me.activeStreamingProfiles.Items.Count - 1. Kontrola potvrdila, že náš fork to již zpracovává – nic se nemění.

Proč: malý UX problém, který se zde ukázal jako již vyřešený.


F40 - Větší maximální počet připojení + varovný protokol

Co: limit souběžných streamů pluginu (SemaphoreSlim kolem Sockets_Stream_File / Sockets_Encoder_Start) byl pevně nastaven na 4. F40 jej činí uživatelsky konfigurovatelným na stránce Obecná nastavení (výchozí 16, rozsah 1-256), přidává řádek protokolu MaxConnections, když požadavek musí čekat na slot, A zobrazuje červený ⚠ odznak Max Conn v levém dolním rohu dialogového okna nastavení, pokud byl limit dosažen alespoň jednou od spuštění MusicBee.

Proč: když zařízení spouští paralelní požadavky (některé Marantz/Linn během skenování obalů, metadata sondy BubbleUPnP vedle aktivního přehrávání), další požadavky se tiše blokovaly za semaforem – uživatel viděl "zařízení pomalé" bez viditelné příčiny. Řádek protokolu je dobrý pro technické ladění, ale netechničtí uživatelé protokoly nikdy nečtou. Viditelný odznak v dialogovém okně nastavení činí podmínku dosažení limitu zjistitelnou pro každého, kdo otevře předvolby pluginu.

Implementace:

  • Centralizováno čekání v WaitOnSendBarrier(logTag) v MusicBeeUpnp.vb; obě místa volání (MediaServerDevice.GetFile, Encoder.StartEncode) jej používají.
  • Settings.MaxConnections perzistováno ve v8 schématu nastavení.
  • Plugin.MaxConnectionsHit je příznak trvalé relace nastavený uvnitř WaitOnSendBarrier; resetuje se pouze při restartu MusicBee.
  • SettingsDialog.maxConnectionsBadge je červený tučný popisek na (16, 410), který se zobrazí pouze, když je Plugin.MaxConnectionsHit True. Má tooltip vysvětlující příčinu a nápravu.
  • Semafor je inicializován jednou při načtení typu, takže změna nastavení vyžaduje restart MusicBee (uvedeno v popisku pole).

F41 - Zaznamenat "kódování kvůli ReplayGain/DSP"

Co: namísto samostatných řádků protokolu "kódování pro RG" / "kódování pro DSP" obsahuje jediný řádek StreamDecision z F42 MB-DSP/EQ, MB-ReplayGain, Profile-DSP/EQ, Profile-ReplayGain jako kumulované důvody. Stejná diagnostická hodnota, méně šumu.

Proč: uživatelé vidí všechny důvody, proč dochází k transkódování pro danou skladbu, na jednom řádku protokolu, nikoli roztroušené. Úplné podrobnosti viz F42.


F42 - Zaznamenat "renderer nepodporuje zdrojový kodek"

Co: přidán řádek protokolu StreamDecision pro každou skladbu přehrávanou do zařízení, který říká buď "nativní CODEC" nebo "transkódovat CODEC→CODEC důvod=…". Pole důvodu kumuluje každou podmínku, která spustila transkódování: MB-DSP/EQ, MB-ReplayGain, Profile-DSP/EQ, Profile-ReplayGain, WebFile, VirtualFile, ForceTranscoding(globální), SampleRate<min/SampleRate>max, DownmixToStereo, DeviceLacksCodec(X), BandwidthConstrained.

Proč: uživatelé byli zmateni neočekávanými špičkami CPU u souborů, které očekávali streamovat nativně. Jeden řádek protokolu pro každou skladbu jim přesně řekne, která podmínka způsobila transkódování – a pokud pole ukazuje DeviceLacksCodec(Flac), okamžitě vědí, že informace o protokolu zařízení byly neúplné a mohou chtít, aby se spustil fallback F32.

Implementace: jediný akumulační řetězec sestavený inkrementálně přes rozhodovací řetězec; zaznamenán jednou na konci. Omezeno na Settings.LogDebugInfo, aby se zabránilo šumu v protokolu v produkci.


F43 - Protokol SetNextAVTransport zobrazuje zdrojovou URL

Co: záznamy protokolu QueueNext nyní obsahují source=<cesta knihovny MusicBee> vedle stream=<HTTP streamovací URL>. Stejná změna aplikována na úspěšnou cestu i na cestu selhání (QueueNext:Failed).

Proč: při ladění problému se zařazenou skladbou je streamovací URL (/encode/aabbccdd0.flac) sama o sobě neprůhledná – stejná pro každou skladbu. Zdrojová URL je lidsky čitelná cesta knihovny, která vám přesně řekne, který soubor se MusicBee pokusil zařadit do fronty.


F44 - Lepší protokolování chyb mime-typu

Co: dva nové záznamy protokolu během Activate:

  • Activate:MimeUnverified – spustí se pro každou chybně formátovanou položku v odpovědi GetProtocolInfo zařízení, pojmenovávající, kterou položku nebylo možné parsovat (takže uživatel může vidět např. "Marantz vrátil http-get:*::* pro nějaký kodek – schopnost je neověřená, fallback F32 bude hádat").
  • Activate:NoSinkInfo – spustí se jednou, pokud zařízení nevrátilo žádný prvek <Sink>. Znamená to, že SupportedMimeTypes zůstane Nothing a IsCodecSupported se degraduje na "předpokládat, že vše funguje" – užitečný kontext, když se později objeví chyby "zařízení odmítlo stream".

Proč: před F44 tyto tiché propady schopností nechaly uživatele hádat, proč byly jejich skladby buď transkódovány proti očekávání, nebo odmítnuty zařízením. Nyní jediný grep pro Activate: ukazuje, zda byly informace o schopnostech zařízení použitelné.


F45 - Lepší protokolování chyb metadat

Co: protokol výjimek Browse v ContentDirectoryService.vb byl již obohacen v dřívější práci yaiol (oprava chyby Alia Vox) o ObjectID a stack trace. F45 jej dále rozšiřuje o BrowseFlag (metadata vs děti), Filter (které atributy klient požadoval), sortCriteria a partialResultLength (kolik bajtů DIDL bylo vyprodukováno před selháním – ukazuje, jak daleko v dávce se nachází špatná skladba).

Proč: když se něco pokazí uprostřed DIDL, hodnota částečné délky vám řekne, zda k selhání došlo u první skladby dávky (partial=0) nebo v průběhu (partial=N) – v kombinaci s startingIndex dávky můžete identifikovat index chybné skladby. Filter a BrowseFlag vysvětlují, jaký druh procházení klient chtěl; někdy procházení pouze metadat selže tam, kde procházení dětí pro stejné ID uspěje.


Sítě

F46 - Automatický režim se ohlašuje pouze na adaptérech skutečné sítě

Co: v režimu rozhraní Automaticky se plugin dříve ohlašoval (SSDP) na každém funkčním adaptéru IPv4. Na počítači, kde běží také tunel VPN (NordLynx) nebo virtuální přepínač (Hyper-V / WSL / Docker), byla stejná knihovna ohlašována i na každém z těchto adaptérů, takže control point, ze kterého vysíláte, objevil server dvakrát nebo třikrát a knihovnu zobrazil jako duplicitní kopie. Automatický režim nyní ponechává pouze adaptéry se skutečnou výchozí bránou IPv4 (HasIPv4Gateway) - kterou adaptéry tunelů a virtuálních přepínačů nemají - takže ty jsou ze seznamu ohlašování vyřazeny. Uživatelem připnutá adresa má i nadále absolutní přednost (ohlašuje se pouze na tomto rozhraní), a pokud žádný adaptér bránu nehlásí, výběr se vrátí ke všem adaptérům, takže seznam ohlašovaných adres není nikdy prázdný a plugin se nemůže stát neviditelným.

Proč: duplicita není způsobena tím, že „jste na VPN" - je způsobena současným ohlašováním na adaptéru LAN a na adaptéru tunelu/virtuálním adaptéru, takže jeden control point vidí stejný server na dvou adresách. Spotřebitelská VPN (NordVPN/NordLynx) tuneluje pouze provoz směřující na internet; renderer DLNA žije na LAN a provoz místní podsítě tunel obchází, takže adaptér tunelu se k rendereru stejně nikdy nedostane - jeho vyřazení odstraní fantomovou kopii, nikdy funkční cestu. Test brány je levný a spolehlivý signál, který odliší skutečný adaptér LAN/Wi-Fi od tunelu nebo virtuálního přepínače. Doplňuje N05 (který opravil, jak se ohlášení na takových spojích odesílají - multicast místo broadcastu); F46 řídí, na kterých adaptérech se vůbec ohlašuje.

Známé omezení: mesh / vzdálená VPN (Tailscale, ZeroTier, WireGuard domů), jejíž renderery skutečně žijí za tunelem, obvykle vykazuje adaptér bez výchozí brány, takže Automatický režim jej vyřadí také. Tito uživatelé místo toho připnou adresu VPN, která má před filtrem brány přednost.