Co nowego
2.0.9 - 2026-08-23
Powiadomienie o aktualizacji otwiera swoje strony w Twoim języku
Co: linki Co nowego i Pobierz w powiadomieniu o aktualizacji otwierają teraz strony wtyczki w języku MusicBee, a nie w języku angielskim.
Dlaczego: te dwa linki zawężały język do jednego z czterech – angielskiego, francuskiego, hiszpańskiego lub niemieckiego – przed wysłaniem go na stronę internetową, więc wszyscy inni otrzymywali stronę angielską, nawet jeśli istniało jej tłumaczenie. Teraz przekazują język MusicBee bez zmian i pozwalają stronie internetowej zdecydować, co wyświetlić, co przycisk Pomoc obok nich zawsze robił.
2.0.8 - 2026-08-22
Wtyczka poprawnie przedstawia się aplikacjom i urządzeniom, które ją wykrywają w Twojej sieci, a ustawienia profili urządzeń są ponownie wyrównane.
Twoje urządzenia pokazują właściwego producenta, model i wersję
Co: gdy aplikacja sterująca, telefon lub telewizor znajdzie MusicBee w Twojej sieci, teraz przedstawia tę wtyczkę jako stworzoną przez yaiol, wskazuje na własną stronę wtyczki, opisuje ją jako obejmującą wszystkie trzy role — serwer, odtwarzacz i renderer — i zgłasza wersję, którą faktycznie masz zainstalowaną.
Dlaczego: każde urządzenie UPnP ogłasza, kto je stworzył i czym jest, a aplikacje sterujące pokazują to jako tożsamość urządzenia. Ta wtyczka nadal ogłaszała szczegóły oryginalnej wtyczki, z której została rozwidlona: nazwisko innego autora, stronę internetową MusicBee zamiast własnej, oraz numer modelu zamrożony na "1.0" od pierwszej wersji. Z telefonu nie było sposobu, aby stwierdzić, z którą wtyczką rozmawiasz, nie mówiąc już o jej wersji. Te szczegóły pochodzą teraz z samej wtyczki, więc wersja wyświetlana obok urządzenia pozostaje poprawna przy każdej aktualizacji.
Ustawienia profili urządzeń są ponownie wyrównane
Co: na karcie Profile urządzeń etykiety i ich pola mają jedną lewą krawędź i są równomiernie rozmieszczone, a zakres częstotliwości próbkowania jest wyświetlany w jednym wierszu.
Dlaczego: pola rozeszły się, gdy z czasem dodawano opcje do karty, a etykieta "do" zakresu częstotliwości próbkowania znalazła się na górze pola obok niej — czytelna, gdy już wiedziałeś, co mówiła, ale zagadkowa za pierwszym razem, gdy na nią spojrzałeś.
2.0.7 - 2026-08-08
Większe utwory zachowują swój tytuł i suwak pozycji
Co: większy utwór wysłany z telefonu — długi plik FLAC, plik wysokiej rozdzielczości lub DSD — teraz wyświetla swój właściwy tytuł i można go przewijać, tak jak mały. Wcześniej niektóre z nich były odtwarzane przez sieć, z adresem internetowym zamiast tytułu i suwakiem, który nic nie robił.
Dlaczego: wtyczka czeka na swoją lokalną kopię przed rozpoczęciem, ale wcześniej z góry decydowała, czy warto czekać na plik, na podstawie jego rozmiaru. Było to tak naprawdę zgadywanie, jak szybka jest Twoja sieć, czego wtyczka nie ma jak wiedzieć: utwór o rozmiarze 65 MB został uznany za zbyt duży, a następnie zakończył pobieranie sekundę później — wygodnie w ramach czasu oczekiwania, z którego już zrezygnowała. Teraz po prostu obserwuje pobieranie. Dopóki plik nadal się pobiera, wtyczka czeka, niezależnie od tego, ile to zajmie; rezygnuje tylko wtedy, gdy transfer faktycznie się zatrzyma, co teraz zauważa szybciej niż stary stały opóźnienie.
2.0.6 - 2026-08-03
Albumy wysłane z telefonu odtwarzają się teraz bez przerw między utworami, a radio internetowe jest rozpoznawane jako radio, zamiast być traktowane jako niezwykle długa piosenka.
Albumy odtwarzają się bez przerw
Co: gdy wysyłasz cały album z telefonu, MusicBee przechodzi teraz z jednego utworu do następnego bez pauzy — dzięki czemu nagrania na żywo, sety DJ-skie i ciągłe utwory klasyczne pozostają spójne.
Dlaczego: standard pozwala aplikacji sterującej powiedzieć „oto, co następuje”, co umożliwia płynne przejście. Ta instrukcja nie była w ogóle akceptowana, więc aplikacja nie miała gdzie umieścić nadchodzącego utworu i ogłaszała go tak, jakby był bieżącym — co było przyczyną problemu z albumami naprawionego w poprzedniej wersji. Jest teraz poprawnie akceptowana: następny utwór jest pobierany, gdy bieżący jest jeszcze odtwarzany, a własny odtwarzacz MusicBee przekracza granicę.
Radio internetowe jest rozpoznawane jako radio
Co: stacja na żywo wysłana do MusicBee jest odtwarzana jako strumień i nigdy nie jest pobierana.
Dlaczego: pobieranie audycji nie ma sensu — nie ma końca i nie ma przez co przeskakiwać — ale wtyczka wcześniej nie miała sposobu, aby odróżnić ją od pliku muzycznego, więc zaczynała pobierać i zatrzymywała się, gdy pobieranie przekroczyło stały rozmiar. Aplikacja sterująca określa, którą z tych dwóch wysyła, a to jest teraz odczytywane bezpośrednio. Bez ustawień, bez zgadywania.
Długie utwory wysokiej rozdzielczości zachowują swoją kopię
Co: pliki DSD i długie nagrania 24-bitowe można teraz przewijać jak każdy inny utwór.
Dlaczego: zostały one objęte powyższym limitem rozmiaru — 20-minutowy utwór wysokiej rozdzielczości lub 10-minutowy utwór DSD przekraczały go — więc ich kopia została porzucona, a suwak pozycji przestał działać dokładnie dla materiału, który najprawdopodobniej warto było przewijać. Dzięki prawidłowemu rozpoznawaniu radia, limit rozmiaru nie jest potrzebny.
2.0.5 - 2026-08-03
Dwie poprawki dotyczące sterowania MusicBee z telefonu: głośność oznacza teraz to samo na obu końcach, a przesyłanie całego albumu działa prawidłowo po pierwszym utworze.
Głośność w telefonie odpowiada głośności w MusicBee
Co: ustawienie maksymalnej głośności w telefonie powoduje teraz osiągnięcie maksymalnej głośności w MusicBee, a ustawienie MusicBee jest poprawnie odczytywane w telefonie.
Dlaczego: wtyczka nigdy nie informowała aplikacji sterującej o swojej najwyższej głośności, więc każda aplikacja musiała zgadywać. Jedna z nich ustawiła 69, co oznaczało, że jej 100% osiągało tylko 69% w MusicBee, podczas gdy 100% MusicBee wracało jako 144% w telefonie — a przyciski głośności telefonu nigdy nie mogły osiągnąć maksimum. Renderer podaje teraz zakres jasno, więc oba końce mówią o tej samej skali.
Przesyłanie albumu zachowuje jego tytuły i suwak pozycji
Co: każdy utwór z albumu wysłanego z telefonu wyświetla teraz swój właściwy tytuł i można go przewijać, a nie tylko pierwszy.
Dlaczego: aplikacja sterująca ogłasza następny utwór ułamek sekundy po bieżącym, a to ogłoszenie anulowało kopię pobieraną dla utworu, który miał się odtworzyć — więc większość utworów cicho wracała do odtwarzania przez sieć, co powodowało utratę zarówno tytułu, jak i możliwości przeskakiwania. Kopie kilku utworów są teraz przechowywane obok siebie, więc ogłoszenie nie może już anulować tej używanej.
2.0.4 - 2026-08-02
Muzyka wysłana do MusicBee z telefonu lub innego serwera zachowuje się teraz jak prawdziwy utwór: możesz się po nim poruszać, a jego właściwy tytuł jest od razu wyświetlany. Dodatkowo poprawka dla streamerów hi-fi, które prezentują się jako jedno połączone urządzenie.
Poruszanie się po utworze wysłanym z innego miejsca
Co: Przeciąganie suwaka pozycji działa teraz dla utworu wysłanego z telefonu, NAS-a lub innego serwera multimediów. Aby to umożliwić, MusicBee pobiera kopię utworu do folderu tymczasowego podczas odtwarzania i odtwarza tę kopię. Zajmuje to około sekundy w sieci domowej, kopia jest usuwana natychmiast po wysłaniu kolejnego utworu, a wszelkie pozostałości są usuwane przy następnym uruchomieniu MusicBee.
Dlaczego: MusicBee może uruchamiać i zatrzymywać coś, czego słucha przez sieć, ale nie może się po tym poruszać — więc suwak wydawał się skakać, a następnie wracał prosto do poprzedniego miejsca, bez wyjaśnienia. Odtwarzanie zwykłego pliku na własnym dysku całkowicie usuwa to ograniczenie, zamiast je obchodzić.
Prawidłowy tytuł i długość od pierwszej nuty
Co: Utwór wysłany przez aplikację, która nie nadaje swoim plikom zwykłego rozszerzenia, pokazuje teraz swój prawdziwy tytuł i długość natychmiast po uruchomieniu, zamiast pojawiać się jako długi adres internetowy.
Dlaczego: MusicBee identyfikuje utwór — i znajduje jego tagi — na podstawie rozszerzenia pliku, a niektórzy odtwarzacze podają adresy bez żadnego rozszerzenia. Lokalna kopia zawsze ma właściwe rozszerzenie, więc utwór jest rozpoznawany niezależnie od tego, jak nazywa go aplikacja wysyłająca.
Skok, którego nie można wykonać, jest teraz zgłaszany
Co: Jeśli renderer naprawdę nie może przejść do żądanego punktu, aplikacja sterująca jest o tym informowana i zgłasza to.
Dlaczego: Wcześniej odpowiadał „gotowe” niezależnie od sytuacji, więc suwak przesuwał się z powrotem sekundę później, bez wyjaśnienia, dlaczego. Uczciwa odmowa jest łatwiejsza do podjęcia działań niż milcząca.
Połączone streamery hi-fi są odczytywane prawidłowo
Co: Gdy MusicBee odtwarza na urządzeniu, które prezentuje się jako jedna połączona jednostka — streamer Marantz lub Denon, gdzie odtwarzacz znajduje się w obudowie producenta wraz z serwerem multimediów — wtyczka odczytuje teraz szczegóły samego odtwarzacza, a nie serwera multimediów.
Dlaczego: Wcześniej pytała niewłaściwą połowę urządzenia, jakie formaty audio może obsługiwać, nie otrzymując użytecznej odpowiedzi i kontynuując bez sprawdzania — dokładnie w sprzęcie, gdzie obsługa formatów musi być najbardziej prawidłowa. Opis modelu urządzenia jest również teraz brany pod uwagę przy dopasowywaniu go do profilu urządzenia; był odczytywany z niewłaściwego miejsca i odrzucany.
2.0.3 - 2026-08-02
Rola odtwarzania dojrzewa: MusicBee może teraz odtwarzać muzykę, której nie ma jeszcze w swojej bibliotece — plik z telefonu, z NAS-a, z innego serwera — zamiast tylko utworów, które już posiada.
Odtwarzaj muzykę wysłaną z telefonu, a nie tylko z własnej biblioteki
Co: gdy używasz aplikacji sterującej, takiej jak Symfonium lub BubbleUPnP, aby wysłać muzykę do MusicBee, utwór nie musi już pochodzić z własnej biblioteki MusicBee. Plik przechowywany na samym telefonie, na NAS-ie lub na innym serwerze multimediów jest teraz odtwarzany. Tytuł i długość pochodzą z aplikacji, która go wysłała, więc utwór wyświetla się poprawnie, mimo że MusicBee nigdy nie widział tego pliku.
Dlaczego: rola odtwarzania została stworzona dla przypadku, gdy przeglądasz bibliotekę tego komputera z telefonu i dotykasz utworu — utwór był już na komputerze, więc MusicBee po prostu odtwarzał swój własny plik. Wszystko, co pochodziło z innego miejsca, było cicho odrzucane, co sprawiało, że funkcja była bezużyteczna w równie naturalnym przypadku przesyłania muzyki z telefonu do dobrych głośników.
Utwór, którego nie można odtworzyć, informuje o tym
Co: jeśli renderer faktycznie nie może odtworzyć tego, co zostało mu wysłane, teraz zgłasza to z powrotem do aplikacji, która to wysłała.
Dlaczego: wcześniej odpowiadał „mam to” na wszystko, więc aplikacja sterująca kontynuowała i naciskała odtwarzanie. Bez faktycznie załadowanego niczego, MusicBee ponownie uruchamiał utwór, który pozostał z poprzedniego razu — a jeśli ten plik zniknął, narzekał, że jego źródło nie zostało znalezione. Błąd nazywał niepowiązany utwór i wskazywał nigdzie blisko prawdziwego problemu.
Wysyłanie nowego utworu podczas pauzy teraz odtwarza ten utwór
Co: jeśli MusicBee jest wstrzymany, a Twoja aplikacja sterująca wysyła mu coś nowego, nowy utwór rozpoczyna się.
Dlaczego: wznowienie miało pierwszeństwo przed ładowaniem, więc wstrzymany utwór kontynuował od miejsca, w którym został przerwany, a utwór, który właśnie wybrałeś, został odrzucony bez słowa.
2.0.2 - 2026-08-01
Wyszukiwanie to motyw przewodni: działa teraz według wykonawcy, zwraca prawidłowe wyniki i jest szybkie w przypadku dużej biblioteki. Dodatkowo nowy sposób kierowania losowego odtwarzania w aplikacji sterującej oraz poprawka dla trzech przycisków, które prowadziły donikąd.
Wyszukiwanie według wykonawcy faktycznie działa
Co: wyszukiwanie wykonawcy z aplikacji sterującej zwraca teraz muzykę tego wykonawcy. Wyszukiwanie pasuje zarówno do pola Artist utworu, jak i Album Artist albumu, więc kompilacja zostanie znaleziona niezależnie od tego, czy wpiszesz imię wykonawcy, czy nazwę, pod którą album jest skatalogowany.
Dlaczego: wyszukiwanie wykonawcy było wcześniej mylone z „daj mi wszystko tego rodzaju” — wpisany wykonawca był ignorowany, a zwracana była cała biblioteka, więc wyszukiwanie, które powinno pasować do kilkuset utworów, zwracało dziesiątki tysięcy. Dopasowanie tylko jednego z dwóch pól wykonawcy cicho straciłoby połowę wyników, dlatego sprawdzane są oba.
Strona wyników wyszukiwania prawidłowo
Co: przewijanie długiej listy wyników wyszukiwania teraz faktycznie przez nią przechodzi. Każda strona, do której przewijasz, jest stroną, którą otrzymujesz.
Dlaczego: serwer odpowiadał na każde żądanie pierwszą garścią wyników, jednocześnie zgłaszając pełną liczbę dopasowań, więc aplikacja przewijająca w poszukiwaniu więcej ciągle otrzymywała te same elementy i nigdy nie docierała do końca.
Wyszukiwanie jest znacznie szybsze w dużej bibliotece
Co: wyszukiwanie uruchamia teraz jedno zapytanie dla całego zestawu wyników i odczytuje tylko tagi strony, którą przeglądasz.
Dlaczego: każda strona wcześniej ponownie uruchamiała zapytanie względem biblioteki, a następnie ładowała tagi każdego dopasowania — tysiące z nich — aby wyświetlić kilkanaście. W przypadku dużej kolekcji powodowało to pauzę przy każdym przewijaniu. Wyniki są również usuwane za każdym razem, gdy biblioteka jest odświeżana, więc edycja nigdy nie jest serwowana jako nieaktualna.
Skieruj losowe odtwarzanie na filtr
Co: nowe ustawienie Losowe odtwarzanie z na karcie Library Options. Pozostaw je na Cała muzyka, a foldery Losowe utwory / Losowe albumy w aplikacji sterującej będą działać jak poprzednio; wybierz jeden ze swoich filtrów MusicBee, a każde losowe żądanie będzie pobierać z tego filtra. Oferowane są również ukryte filtry.
Dlaczego: folder losowego odtwarzania prosi o wycinek „wszystkiego” i jest to jedyne żądanie, które nie zawiera żadnej wskazówki, co miałeś na myśli — więc zawsze pobierało z całej biblioteki, w tym słowa mówionego. To tutaj mówisz, co oznacza „wszystko”. Otworzenie folderu losowego odtwarzania wewnątrz filtra na urządzeniu nadal losuje ten filtr: wybór dokonany podczas przeglądania ma pierwszeństwo przed ustawieniem.
Pomoc, GitHub i sprawdzanie aktualizacji prowadzą do prawdziwych stron
Co: przyciski Pomoc i GitHub w oknie dialogowym ustawień oraz automatyczne sprawdzanie nowej wersji otwierają teraz strony, które nazywają.
Dlaczego: wszystkie trzy były zbudowane ze skróconej formy nazwy wtyczki, pod którą nigdy nie istniała żadna strona, więc każda z nich cicho zawodziła — przyciski wydawały się nic nie robić, a sprawdzanie aktualizacji nigdy nic nie zgłaszało, niezależnie od tego, jak długo nowa wersja była dostępna.
2.0.1 - 2026-07-26
Seria poprawek odtwarzania i przeglądania, skupiająca się na podcastach i aplikacjach kontrolerów (takich jak BubbleUPnP), które sterują odtwarzaniem i losowym odtwarzaniem.
Podcasty zaczynają odtwarzanie bez pauzy
Co: pobrany odcinek podcastu podaje teraz swoją rzeczywistą długość i rozmiar pliku z góry, przeniesione bezpośrednio z pliku na dysku do metadanych multimediów.
Dlaczego: bez podanego czasu trwania, kontroler taki jak BubbleUPnP ponownie skanuje cały strumień audio za każdym razem, gdy naciśniesz odtwarzanie, tylko po to, aby ustalić, jak długi jest odcinek — więc odtwarzanie rozpoczynało się dopiero po zauważalnej pauzie. Z reklamowaną teraz długością, rozpoczyna się płynnie.
Podcasty pojawiają się podczas przeglądania według artysty
Co: nazwa programu podcastu jest teraz zapisywana jako jego artysta — odzwierciedlona w polach Artysta i Artysta Albumu (oraz ich wariantach sortowania), dokładnie tak, jak już wypełnia pole Album.
Dlaczego: ścieżka przeglądania, która grupuje według pola artysty, znajdowała wcześniej artystę każdego podcastu jako pustego i kończyła się na pustym poziomie. Traktowanie samego programu jako artysty — spójne z traktowaniem go jako albumu — oznacza, że te ścieżki docierają teraz do odcinków zamiast do niczego.
„Ostatnio odtwarzane” i przesyłanie działają poprawnie po ponownym uruchomieniu
Co: odtwarzanie podcastu, audiobooka, skrzynki odbiorczej lub utworu radiowego bezpośrednio — bez wcześniejszego przeglądania go, tak jak robią to listy „Ostatnio odtwarzane” i cele przesyłania BubbleUPnP — nie kończy się już niepowodzeniem. Wtyczka ładuje teraz utwór na żądanie, gdy jest o to proszona przez identyfikator.
Dlaczego: te listy żądają utworu zaraz po ponownym uruchomieniu MusicBee, zanim cokolwiek zostało przeglądane, więc wtyczka nigdy nie widziała identyfikatora i odpowiadała „Zły identyfikator”. Teraz wymusza ładowanie odpowiednich źródeł na to pierwsze bezpośrednie żądanie i znajduje utwór.
„Losowe utwory” i „Losowe albumy” zwracają wyniki
Co: foldery losowego odtwarzania „Losowe utwory” i „Losowe albumy” BubbleUPnP, które proszą o losowy wycinek całej biblioteki, wracają teraz wypełnione.
Dlaczego: są to wyszukiwania bez tytułu do dopasowania, a wtyczka wcześniej odpowiadała na nie z pustej wewnętrznej listy, więc zawsze pokazywały nic. Są teraz obsługiwane — poprawnie stronicowane — z tej samej ścieżki zapytań na żądanie, której używa reszta przeglądania.
Albumy z pustą listą tagów wyświetlają swoje utwory
Co: otwarcie albumu, który był zgrupowany na pustej wartości — na przykład utwory ze skrzynki odbiorczej, które nie mają roku — pokazuje teraz jego utwory.
Dlaczego: dopasowanie, które zbiera utwory albumu, traktowało „ten tag jest pusty” jako „brak dopasowania”, więc każdy album utworzony z pustego pola przeglądał do niczego. Pusta wartość grupy teraz poprawnie dopasowuje utwory, które ją współdzielą.
2.0.0 - 2026-07-22
To jest pierwsze publiczne wydanie otwartego kodu yaiol, forka wtyczki MusicBee UPnP. Jest ono przedstawione w dwóch częściach: wszystko, co jest nowe w tym forku, a następnie poprawki i ulepszenia wprowadzone do oryginalnej wtyczki. Każdy element zachowuje formę Co / Dlaczego z wewnętrznego katalogu funkcji projektu, dzięki czemu uzasadnienie każdej zmiany jest widoczne na stronie, a nie tylko sama zmiana.
Nowości w tym forku
MediaRenderer - odtwarzanie do MusicBee
N01 - MusicBee jako renderer do odtwarzania
Co: normalnie ta wtyczka działa w jedną stronę: telefon lub inne urządzenie przegląda bibliotekę MusicBee i odtwarza muzykę na sobie. Ta funkcja dodaje przeciwny kierunek - pozwala MusicBee być odtwarzaczem. Z aplikacji kontrolera na telefonie (takiej jak BubbleUPnP) możesz wybrać MusicBee na swoim komputerze jako urządzenie odtwarzające, a następnie sterować nim z ręki: odtwarzać, pauzować, zatrzymywać, przewijać do przodu lub do tyłu, przeskakiwać do punktu w utworze oraz zmieniać głośność lub wyciszać.
Dlaczego: zamienia to Twój telefon w pilota do muzyki już znajdującej się na Twoim komputerze. Usiądź na kanapie, przeglądaj swoją bibliotekę na telefonie, dotknij utworu, a on zostanie odtworzony z głośników podłączonych do Twojego komputera - z pełną kontrolą z miejsca, w którym siedzisz. Oryginalna wtyczka nigdy nie dostarczyła tej funkcji w działającej formie.
Włączanie: jest domyślnie wyłączone, ponieważ włączenie jej pozwala każdemu urządzeniu w Twojej sieci domowej rozpocząć odtwarzanie na Twoim komputerze. Włączasz ją, zaznaczając pole wyboru na karcie Ogólne w oknie ustawień. Trzy role wtyczki mają tam swoje własne pola wyboru - udostępnij moją bibliotekę (Serwer), pozwól innym odtwarzać do mnie (Renderer) i odtwarzaj do innych urządzeń (Punkt kontrolny) - a okno dialogowe pokazuje tylko te karty ustawień, które są faktycznie potrzebne dla włączonych ról, więc nigdy nie masz do czynienia z opcjami, które Cię nie dotyczą.
Rozróżnianie maszyn: możesz nadać rendererowi dowolną nazwę (domyślnie "MusicBee (yaiol)"). Ta nazwa pojawia się na liście celów odtwarzania w Twoim telefonie, więc gdy więcej niż jeden komputer uruchamia MusicBee, możesz rozróżnić, który jest który. Zmiana nazwy wchodzi w życie natychmiast, bez ponownego uruchamiania.
Najlepszy możliwy dźwięk podczas odtwarzania do siebie: gdy przeglądasz własną bibliotekę MusicBee z telefonu i wysyłasz utwór z powrotem do tego samego MusicBee, wtyczka rozpoznaje, że jest proszona o odtworzenie jednego z własnych plików i po prostu odtwarza go bezpośrednio z dysku. Wynik jest dokładny i natychmiastowy - bit-perfect, z zastosowanym własnym korektorem i wyrównywaniem głośności MusicBee - zamiast bezcelowego wypychania dźwięku do sieci i z powrotem do siebie.
Uruchamianie prywatne: trzy role działają niezależnie, więc możesz włączyć renderer, pozostawiając wyłączone udostępnianie biblioteki. W tej konfiguracji "tylko renderer" Twoja biblioteka pozostaje całkowicie ukryta przed siecią - ogłaszany jest tylko cel odtwarzania - a MusicBee nigdy nie zaoferuje odtwarzania do siebie.
Zachowanie odtwarzania
N02 - 5.1 FLAC nie jest automatycznie miksowany w dół
Co: ograniczenie liczby kanałów w MediaServerDevice.GetEncodedFile było If StereoOnly OrElse Not isPcmData Then channelCount = 2. Klauzula Not isPcmData cicho miksowała w dół każdą transkodowaną (FLAC, MP3, AAC, Ogg) do stereo, niezależnie od liczby kanałów źródłowych, uniemożliwiając rendererom obsługującym 5.1 odtwarzanie, gdy źródłem był 5.1 FLAC. Teraz druga klauzula wyklucza FLAC: Not isPcmData AndAlso encoder.Codec <> FileCodec.Flac. FLAC 5.1 przechodzi; MP3/AAC/Ogg nadal wymuszają stereo, ponieważ wiersz poleceń MusicBee dla tych formatów oczekuje 2-kanałowego wejścia.
Dlaczego: cały sens transkodowania źródła 5.1 FLAC do wyjścia FLAC polega na zachowaniu miksu wielokanałowego. Ciche miksowanie w dół sprawiało, że opcja transkodowania FLAC była bezużyteczna do słuchania w trybie surround. Z N02 działa to prawidłowo.
Architektura
Zmiana strukturalna, która sprawia, że fork jest wykonalny na dużej bibliotece - brak w oryginalnej wtyczce.
N03 - Leniwe (na żądanie) drzewo przeglądania
Co: oryginalna wtyczka budowała całe drzewo przeglądania przy uruchomieniu MusicBee - wyliczała każdy utwór, pełne Library_GetFileTags dla każdego pliku, składała całą hierarchię kontenerów - przed otwarciem portu HTTP. W przypadku prawdziwej biblioteki (ponad 50 tys. utworów, 5400 odcinków podcastów, setki stacji) to minuty zimnego startu, a drzewo pozostaje w pamięci RAM na zawsze, włączając gałęzie, których żaden klient nigdy nie otwiera. Ten fork niczego nie buduje z góry: korzeń eksponuje jeden symbol zastępczy z prefiksem L: na punkt końcowy (L:music, L:podcast, L:filter:…); każdy poziom jest obliczany tylko wtedy, gdy klient go przegląda (LazyBrowse → EnsureLazyEndpointInMemory → pamięci podręczne na poziomie), a powiadomienia o zmianach w bibliotece czyszczą pamięci podręczne (SetLibraryDirty).
Dlaczego: zimny start jest praktycznie natychmiastowy - port HTTP jest otwarty, zanim MusicBee zakończy inicjalizację wtyczki - a pamięć pozostaje proporcjonalna do tego, co zostało przeglądane, a nie do rozmiaru biblioteki. Kompromis: pierwsze przeglądanie punktu końcowego ponosi koszty ładowania; ponowne wejście jest buforowane do następnej zmiany biblioteki. Jest to podstawa, od której zależy wszystko inne. Pełne notatki: FIXES.md.
Sieć i niezawodność
Wzmocnienie ścieżki wiązania serwera HTTP. Oryginalna wtyczka umiera cicho, gdy jej port jest niedostępny.
N04 - Samonaprawiające się wiązanie portu HTTP
Co: serwer HTTP wtyczki nie umiera już, gdy jego skonfigurowany port jest niedostępny. Trzy powiązane zmiany:
- Automatyczne przełączanie awaryjne w przypadku błędu wiązania.
HttpServer.Startpróbuje skonfigurowanego portu, a w przypadkuSocketExceptionskanuje do 20 portów w górę w poszukiwaniu pierwszego wolnego. Rzeczywisty związany port jest zapisywany w nowymPlugin.boundServerPort, a wszystko, co reklamuje serwer - adresy URL SSDPLOCATION(NOTIFY + odpowiedź M-SEARCH), adres URL urządzenia (PrimaryHostUrl), przekierowanie portów routera oraz filtry własne SSDP/punktu kontrolnego - teraz odczytujeboundServerPortzamiastSettings.ServerPort. Klienci UPnP odkrywają rzeczywisty port za pośrednictwem SSDP, więc przeniesiony port jest przezroczysty dla rendererów. - Powiadomienie użytkownika. Gdy nastąpi przełączenie awaryjne (zapisany port nie jest używanym), zlokalizowany
MessageBox(WarnPortInUse) informuje użytkownika, który port faktycznie obsługuje i że urządzenia nadal go znajdą - ponieważ wtyczka działa bez interfejsu graficznego, a wiadomość w oknie dialogowym byłaby widoczna tylko dla kogoś, kto już podejrzewał problem. - Odzyskiwanie po ponownym uruchomieniu.
RestartServer(ścieżka ponownego uruchomienia po zapisaniu ustawień) używał do dereferencjiPlugin.controller/Plugin.serverna ślepo. Jeśli początkoweInitialisezgłosiło wyjątek przed ich utworzeniem (dokładnie to, co spowodowało nieudane wiązanie), następne zapisanie ustawień spowodowałoNullReferenceException- pozostawiając wtyczkę w połowie martwą. Teraz tworzy je i uruchamia, gdyNothing, więc zapisanie działającego portu ożywia wtyczkę bez pełnego ponownego uruchamiania MusicBee.
Dlaczego: wyzwalaczem był prawdziwy incydent użytkownika. Stary domyślny port 49382 znajduje się w zakresie dynamicznym systemu Windows (49152-65535), gdzie Hyper-V/WSL2/Docker/WinNAT rezerwują duże bloki, które zmieniają się przy każdym uruchomieniu - więc wiązanie nie powiodło się z WSAEACCES ("dostęp zabroniony") na maszynie, na której działało przez miesiące. Zmiana domyślnego portu na wolny kolidowała następnie z Serviio (oddzielny serwer DLNA już na nowym porcie), kończąc się niepowodzeniem z WSAEADDRINUSE. Każda awaria była połykana w Initialise, pozostawiając wtyczkę cicho martwą, a następnie NRE-ing przy następnym zapisie ustawień. Po N04 kolizja portów samonaprawia się - serwer nadal działa na następnym wolnym porcie, użytkownik jest informowany, a klienci ponownie go odkrywają - zamiast wyłączać całą wtyczkę.
Implementacja:
- Domyślny port przeniesiony
49382→9779(poniżej zakresu dynamicznego, więc Windows nigdy go automatycznie nie rezerwuje; nie jest znanym domyślnym portem serwera multimediów) we wszystkich trzech deklaracjachServerPort+ w przypadku błędu analizy ustawień. Plugin.boundServerPort(nowe wspólne pole) przechowuje aktywny port nasłuchu;activeServerPortpozostaje skonfigurowaną migawką, aby logika odznaki "Wymagane ponowne uruchomienie" nie wyzwalała się fałszywie w przypadku przełączenia awaryjnego.HttpServer.PortScanRange = 20; skanowanie zatrzymuje się przy pierwszym udanymTcpListener.Start()i zgłasza ostatni wyjątek tylko wtedy, gdy wszystkie próby zakończą się niepowodzeniem.- Nowy klucz zasobu EN
WarnPortInUse(tłumaczenia są zgodne z lokalizacją w czasie publikacji).
N05 - Ogłoszenia SSDP przez grupę multicast (VPN / punkt-punkt)
Co: ogłoszenia SSDP są wysyłane do grupy multicast UPnP (239.255.255.250) zamiast do adresu rozgłoszeniowego IP. Niegroźny błąd "nie można uzyskać dostępu do usuniętego obiektu" logowany, gdy odpowiedź na wyszukiwanie SSDP ściga ponowne uruchomienie serwera, jest również pomijany.
Dlaczego: na kartach sieciowych punkt-punkt / VPN rozgłaszanie IP nie ma zastosowania - stare wysyłanie rozgłoszeniowe kończyło się błędem "nieprawidłowy argument", a ogłoszenia były pomijane, więc wtyczka była niewidoczna dla klientów na tych łączach. Ogłaszanie do właściwej grupy multicast naprawia wykrywanie dokładnie na tych adapterach.
Nawigacja po bibliotece
Te funkcje zostały dostarczone w tym forku i nie ma ich w oryginalnej wtyczce. Powstały one z faktycznego przeglądania danych wyjściowych wtyczki z prawdziwych klientów UPnP.
N06 - Udostępnianie biblioteki oparte na filtrach
Co: karty filtrów MusicBee (pliki .xautopf w folderze MusicBee użytkownika) stają się kontenerami głównymi UPnP w bibliotece wtyczki. Utwory każdego filtra są następnie przeglądane w hierarchii AlbumArtistSort → Album → Tracks.
Dlaczego: użytkownicy z wyselekcjonowanymi filtrami MusicBee (np. "utwory 5-gwiazdkowe", "ostatnio dodane", "Klasyka → Barok") oczekują, że znajdą je podczas przeglądania wtyczki z klienta UPnP. Oryginalna wtyczka udostępniała tylko surowe drzewo biblioteki.
N07 - Okablowanie pola SortAlbumArtist
Co: wtyczka odczytuje teraz MetaDataType 165 (Sort Album Artist) z MusicBee i używa go do grupowania/sortowania artystów w widokach przeglądania.
Dlaczego: przeglądarki hi-fi i audiofile używają nazw artystów do sortowania ("Beethoven, Ludwig van" zamiast "Ludwig van Beethoven") do organizowania bibliotek. Standardowe oczekiwanie dla poważnych słuchaczy. Brak w obu upstreamach.
N08 - Obsługa wielu wartości AlbumArtist
Co: gdy pole AlbumArtist albumu zawiera wielu artystów oddzielonych "; " (np. "yaiol; Ars Ricercata"), utwór pojawia się teraz pod każdym artystą w widokach przeglądania, a nie pod jednym artystą Frankensteinem łączącym nazwy.
Dlaczego: albumy kolaboracyjne i kompilacje muszą być widoczne pod każdym współpracownikiem. Bez tego połowa ścieżek wyszukiwania albumu jest uszkodzona.
N09 - Okładka kontenera albumu (upnp:albumArtURI)
Co: węzły kontenerów albumów w odpowiedziach DIDL Browse zawierają teraz element upnp:albumArtURI wskazujący na okładkę albumu.
Dlaczego: bez tego każdy album w widoku przeglądania klienta UPnP pokazuje ogólną ikonę zamiast okładki albumu. Wizualna wskazówka do nawigacji; oczekiwana przez każdą nowoczesną przeglądarkę hi-fi.
N10 - Kolejność utworów w albumach filtrów
Co: utwory w albumie udostępnionym przez filtr są teraz sortowane według numeru dysku, a następnie numeru utworu.
Dlaczego: standardowa kolejność albumów. Bez jawnego sortowania utwory były zwracane w dowolnej kolejności, w jakiej filtr je zwrócił - zazwyczaj wyglądało to losowo.
N11 - Naprawa drzewa folderów playlist
Co: funkcja LoadLibraryPlaylists (pierwotnie autorstwa Stevena Mayalla, ~2014) nie schodziła do nowo utworzonych folderów playlist. Pierwsza playlista w każdym folderze, plus wszelkie podfoldery, kończyły jako osierocone na poziomie głównym.
Dlaczego: obecne w oryginalnej wtyczce przez jedenaście lat. Widoczne w ciągu 30 sekund od otwarcia BubbleUPnP i kliknięcia Playlisty. Naprawione w yaiol poprzez prawidłowe rekurencyjne wchodzenie do nowo utworzonych folderów podczas budowania drzewa.
N12 - Sanitacja nielegalnych znaków kontrolnych XML
Co: każdy utwór z tagiem zawierającym znak kontrolny C0 (np. 0x19 z błędnego kodowania - UTF-8 → Latin-1 → z powrotem obcinając 0x99 do 0x19) powodował, że cała odpowiedź Browse kończyła się błędem Action Failed, gdy zły utwór wszedł do paginowanej partii.
Dlaczego: XML 1.0 zabrania większości znaków kontrolnych C0, a XmlWriter zgłasza wyjątek, gdy zostanie poproszony o zapisanie któregokolwiek z nich. Obecne w oryginalnej wtyczce. Naprawione poprzez usunięcie nieprawidłowych znaków w każdym punkcie wyjścia Library_GetFileTags za pomocą XmlConvert.IsXmlChar.
N13 - Lista radiowa deterministyczna w paginowanym przeglądaniu
Co: przeglądanie kontenera Radio wpadało do ogólnej gałęzi listy plików, która wywoływała files.Sort(AlbumFileComparer) przy każdym wywołaniu. Wpisy radiowe mają puste tagi Album/Disc/Track, więc każde porównanie zwracało 0 - List(Of T).Sort jest niestabilne, produkując inną kolejność przy każdym wywołaniu. Punkty kontrolne UPnP paginują (BubbleUPnP pobiera 0..15, a następnie 16..koniec); między dwoma wywołaniami lista się przetasowywała, więc niektóre stacje pojawiały się na obu stronach (duplikaty), a niektóre na żadnej (brakujące) - wyglądając losowo przy każdym odświeżeniu.
Dlaczego: obecne w oryginalnej wtyczce (jej autor nigdy nie przegląda radia przez UPnP). Naprawione tutaj z dedykowaną gałęzią ContainerCategory.Radio w Browse, bez sortowania na wywołanie; radioFiles jest sortowane raz przy ładowaniu według tytułu (stabilne). Paginowane przeglądanie widzi teraz deterministyczną kolejność; strona 1 i strona 2 są rozłączne.
N14 - Wyszukiwanie UPnP klasy albumu zwraca kontenery albumów
Co: wyszukiwanie UPnP dla zapytań klasy albumu (upnp:class = "object.container.album.musicAlbum", np. "Losowe albumy" BubbleUPnP) zwracało pełną listę utworów zamiast kontenerów albumów, więc klient pokazywał zero albumów. Oryginalny handler analizował tylko kryteria w nawiasach, a następnie wyrzucał wszystkie utwory niezależnie od żądanej klasy.
Dlaczego: naprawione tutaj - zapytania klasy albumu teraz wyliczają odrębne albumy (zgrupowane według AlbumArtist+Album) i emitują każdy jako właściwy kontener musicAlbum z okładką, adresowalny za pomocą wirtualnej przestrzeni ID Salb<idx>, dzięki czemu klient może zagłębić się w wynik i go odtworzyć.
N15 - Działające, świadome zakresu wyszukiwanie UPnP z możliwością kliknięcia
Co: oryginalny nie reklamował żadnych możliwości wyszukiwania (GetSearchCapabilities zwracało puste), więc klienci odmawiali nawet wysyłania wyszukiwania; a stary backend odczytywał z musicFiles, trwale pustego w erze leniwego drzewa. Ten fork reklamuje rzeczywiste właściwości do wyszukiwania, implementuje wyszukiwanie utworów według tytułu i albumów według tytułu w oparciu o leniwą bibliotekę (HandleLazySearch), ogranicza zapytanie do bieżącej gałęzi klienta, gdy wysyłane jest rzeczywiste ID kontenera (w przeciwnym razie zastępuje L:music, aby wyszukiwania z górnego paska nie wciągały szumu podcastów/radia/audiobooków) i sprawia, że wyniki albumów są klikalne za pomocą syntetycznych ID Ssrch_alb_*, które wczesna gałąź Browse mapuje z powrotem do utworów albumu. (Część dotycząca wyników klasy albumu jako kontenerów to N14.)
Dlaczego: wyszukiwanie w BubbleUPnP przeszło od "Biblioteka nie obsługuje wyszukiwania" do zwracania użytecznych, ograniczonych, odtwarzalnych wyników. Pełny projekt + odrzucone podejścia: SEARCH.md.
N16 - Unieważnienie pamięci podręcznej UPnP (SystemUpdateID)
Co: oryginał zwracał stałe SystemUpdateID=0 - kontrakt unieważniania pamięci podręcznej UPnP ContentDirectory - więc klienci zgodni ze specyfikacją (BubbleUPnP) traktowali bibliotekę jako nigdy się nie zmieniającą: nieaktualne wyniki przeglądania, miniatury 404 po zmianie schematu URL i taniec "uruchom MusicBee dwa razy, aby zobaczyć zmiany". Ten fork inicjuje SystemUpdateID z sekund epoki przy ładowaniu (więc każde ponowne uruchomienie jest ściśle przed ostatnim) i zwiększa je przy każdej mutacji biblioteki i zmianie ustawień (SetLibraryDirty / ResetCache → BumpSystemUpdateId).
Dlaczego: klienci niezawodnie odbierają edycje, nowe pliki i zmiany ustawień przy następnym przeglądaniu. Znane ograniczenie: subskrybowani klienci nie są aktywnie ponownie wysyłani z nową wartością za pośrednictwem GENA (zaparkowane jako przyszła praca); nadal widzą ją przy następnym przeglądaniu.
N17 - Okładki subskrypcji podcastów
Co: kafelki podcastów nie wyświetlały obrazów - każde żądanie /PodcastThumbnail/ kończyło się błędem 404. Dwa nakładające się błędy: łańcuch rozwiązywania nigdy nie sprawdzał rzeczywistej pamięci podręcznej okładek MusicBee (%LocalAppData%\MusicBee\InternalCache\Subscriptions\<name>.jpg, skąd ładuje się interfejs pulpitu), a warstwa HTTP unescape+lowercase zniekształcała klucz trasy URL kanału do ostatniego segmentu ścieżki. Ten fork rozwiązuje okładki z InternalCache MB i kieruje wyszukiwania za pomocą bezpiecznego dla URL slug, który przetrwa warstwę HTTP w nienaruszonym stanie (PodcastSlug / podcastSubIdBySlug).
Dlaczego: okładki subskrypcji są teraz renderowane w widokach przeglądania (wszystkie 22 wcześniej kończące się błędem 404 żądania są rozwiązywane).
N18 - Hierarchiczne (ograniczone) przeglądanie tagów
Co: dowolne pole może być oznaczone jako hierarchiczne na karcie Opcje biblioteki i otrzymać jednoliterowy ogranicznik (selektor pola + pole ogranicznika z dodawaniem/usuwaniem, przechowywane w ustawieniach wtyczki). Ustaw Grupowanie na / i wartość taką jak Jazz/Cool Jazz, a następnie przeglądaj jako Jazz › Cool Jazz zamiast jednego płaskiego wpisu. Utwory otagowane dokładnie na gałęzi (tylko Jazz) otrzymują własny węzeł [Jazz], aby nic nie było ukryte, gałąź z jednym dzieckiem zwija się sama, a ; jest odrzucane jako ogranicznik, ponieważ jest to własny separator wielu wartości MusicBee.
Dlaczego: głębokie taksonomie tagów, które użytkownik już zakodował w jednym polu (drzewa gatunków, hierarchie nastrojów, "Klasyka/Barok/Koncert"), w końcu przeglądają się jako drzewo, które opisuje tag, zamiast płaskiej ściany ciągów oddzielonych ukośnikami, które użytkownik musi czytać od początku do końca.
N19 - Pojedyncza ścieżka główna oznaczona polem grupowania
Co: pojedyncza ścieżka przeglądania w katalogu głównym jest oznaczona polem grupowania (np. "Gatunek"), a nie pełną krótką ścieżką, co odpowiada sposobowi nazywania połączonych grup pierwszego pola.
Dlaczego: drzewo przeglądania jest spójne - jedna zasada nazewnictwa, niezależnie od tego, czy wpis główny stoi sam, czy został połączony z rodzeństwem (N20) - zamiast pojedynczego wpisu głównego pokazującego szczegółową ścieżkę wewnętrzną, podczas gdy jego połączone sąsiedzi pokazują czystą nazwę pola.
N20 - Łączenie ścieżek przeglądania, które współdzielą pierwsze pole
Co: dwie ścieżki przeglądania, które współdzielą to samo pierwsze pole - "Gatunek / Sortuj wykonawcę albumu" i "Gatunek / Osoby z podcastów" - zwijają się w jeden folder główny Gatunek, który najpierw wyświetla wartości gatunków, a następnie dzieli się na dwa widoki, zamiast dwóch prawie identycznych wpisów "Gatunek / ..." obok siebie w katalogu głównym.
Dlaczego: użytkownik z kilkoma powiązanymi widokami zagnieżdżonymi pod wspólnym polem widział katalog główny zaśmiecony prawie identycznymi wpisami najwyższego poziomu. Ich połączenie sprawia, że katalog główny jest czytelny i grupuje powiązane widoki tam, gdzie powinny być - pod ich wspólnym polem.
N21 - Ścieżki przeglądania według kategorii (Standardowe / Radio / Podcast)
Co: każda ścieżka przeglądania jest typowana według kategorii - Standardowe, Radio lub Podcast. Lista szablonów jest pogrupowana w te trzy sekcje, selektor pól każdego szablonu oferuje tylko pola, które dane tej kategorii mogą faktycznie dostarczyć, a szablon może być zastosowany tylko do pasujących węzłów w drzewie widoku (niekompatybilne węzły są wyszarzone i nie można ich zaznaczyć). Zarezerwowane szablony Radio i Podcasty nie mogą być usunięte, więc ich sekcja kategorii nigdy nie znika.
Dlaczego: bez typowania użytkownik mógłby zbudować układ, który cicho pojawia się pusty - stacja radiowa nie ma "albumu", odcinek podcastu nie ma "wykonawcy albumu" - i odkryć to tylko przeglądając do martwego folderu z klienta UPnP. Ograniczenie menu pól i celów zastosowania do rzeczywistych danych kategorii sprawia, że puste układy są niemożliwe do zbudowania.
N22 - Grupuj podcasty według roku publikacji
Co: data publikacji każdego odcinka podcastu jest odczytywana, więc ścieżka przeglądania podcastu z poziomem Roku grupuje odcinki według roku zamiast zwijać je pod jednym "Nieznanym".
Dlaczego: duże subskrypcje podcastów stają się nawigowalne według roku, jak reszta biblioteki, zamiast każdego odcinka lądującego w jednym nieoznaczonym stosie, ponieważ wtyczka nigdy nie patrzyła na datę publikacji poszczególnych odcinków.
N23 - Zwijanie poziomów grupowania z pojedynczym wynikiem
Co: poziom grupowania, który rozwiązuje się do pojedynczej wartości - poziom typu rekordu pokazujący tylko "LP" dla artysty, który tworzył tylko LP, lub poziom literowy z pojedynczą literą - jest automatycznie pomijany, przenosząc użytkownika bezpośrednio do jego zawartości.
Dlaczego: przeglądanie folderu, który zawiera dokładnie jeden folder, to czyste tarcie. Zwijanie poziomu z pojedynczym wyborem usuwa martwe kliknięcie bez zmiany tego, co użytkownik może osiągnąć.
N24 - Grupowanie/wyszukiwanie według roku w polu daty MusicBee
Co: warunek roku nie wysyła już zapytania do pełnego pola daty "Rok" MusicBee z samą czterocyfrową wartością, a twardo zakodowane aliasowanie pola roku zniknęło, więc każde pole grupowania jest teraz rozwiązywane ogólnie z definicji ścieżki.
Dlaczego: w przypadku bibliotek, których tag Rok zawiera pełną datę, grupowanie lub wyszukiwanie według roku wcześniej nie zwracało niczego - czterocyfrowe zapytanie nigdy nie pasowało do pola pełnej daty. Zapytanie do właściwego pola sprawia, że grupowanie i wyszukiwanie według roku ponownie znajduje utwory.
N25 - Oddzielne pola grupowania "Rok" i "Rok (rrrr)"
Co: ścieżki grupowania i przeglądania albumów udostępniają teraz oba własne pola roku MusicBee - Rok (pełny tag daty) i Rok (rrrr) (tylko czterocyfrowy rok) - dzięki czemu użytkownik może wybrać jedno z nich podczas definiowania grupowania albumów lub ścieżki przeglądania.
Dlaczego: te dwa pola oznaczają różne rzeczy w MusicBee, a ich połączenie powodowało utratę tej różnicy. Udostępnienie obu pozwala użytkownikowi zebrać wszystkie wydania z danego roku (rrrr) lub zachować dokładną kolejność dat (pełny tag Roku), zgodnie z jego intencjami.
N32 - Przypięte filtry i playlisty pogrupowane według rodzaju w katalogu głównym
Co: przypięty filtr pojawia się teraz bezpośrednio pod folderem Filtry w katalogu głównym przeglądania, a przypięta playlista bezpośrednio pod folderem Playlisty, zamiast wszystkich przypiętych elementów zbierających się w jednym miejscu na końcu katalogu głównego. Każdy przypięty skrót znajduje się obok swojego rodzaju.
Dlaczego: gdy użytkownik przypina więcej skrótów, pojedyncza końcowa grupa mieszanych filtrów i playlist staje się trudniejsza do skanowania i oddziela każdy skrót od folderu, do którego należy. Grupując przypięte elementy w ich własnej kategorii, katalog główny pozostaje czytelny, a każdy skrót znajduje się obok rzeczy, do których należy.
Okno ustawień i pakowanie
N26 - Podzielone okno ustawień
Co: strona Preferencje otrzymała układ z lewą nawigacją i sekcjami: Ogólne / Odtwarzanie / Biblioteka / Profile urządzeń / Diagnostyka.
Dlaczego: oryginał był jedną długą, płaską listą wszystkich ustawień - w porządku dla dewelopera, który go zbudował, ale mylący dla wszystkich innych. Podział na sekcje grupuje powiązane opcje i sprawia, że okno dialogowe bardziej przypomina nowoczesne ustawienia aplikacji.
Zmiana nazwy zestawu + wtyczki (bez F-id - uwaga dotycząca pakowania)
Co: skompilowana biblioteka DLL nosi nazwę mb_UPnP_yaiol.dll, a wtyczka zgłasza się jako "MusicBee UPnP (yaiol)". Różni się od oryginalnego mb_Upnp.dll.
Dlaczego: użytkownicy mogą zainstalować yaiol obok oryginalnej wtyczki i porównywać zachowanie obok siebie.
System odznak - wyświetlanie stanu środowiska wykonawczego (mechanizm za F40)
Co: ogólny wzorzec interfejsu użytkownika do wyświetlania ważnych warunków środowiska wykonawczego jako widocznych kolorowych odznak w oknie dialogowym Ustawienia. Obecne instancje:
- ⚠ Maks. połączeń (N04) - uruchamia się, gdy limit maksymalnej liczby połączeń został osiągnięty co najmniej raz od uruchomienia MusicBee. Flaga sesji
Plugin.MaxConnectionsHit. Ustawiana wWaitOnSendBarrier, gdy nie ma wolnego miejsca. - ⚠ Wymagane ponowne uruchomienie - uruchamia się, gdy zapisane ustawienie wymaga ponownego uruchomienia MusicBee, aby weszło w życie. Flaga sesji
Plugin.RestartRequired. Ustawiana w obsłudze zapisu okna dialogowego, gdy nowa trwała wartość różni się od migawki środowiska wykonawczego (Plugin.activeMaxConnections,Plugin.activeServerPort,Plugin.activeIpAddress). Ustawienia wymagające ponownego uruchomienia są ograniczone do tych, które naprawdę nie mogą być ponownie załadowane na gorąco - parametry wiązania serwera HTTP i SemaphoreSlim zbudowane raz przy inicjalizacji.
Dlaczego: plik dziennika wtyczki jest w porządku dla użytkowników technicznych debugujących, ale użytkownik nietechniczny, patrząc na "urządzenie brzmi źle" lub "odtwarzanie jest wolne", nigdy nie otworzy Diagnostyka → Wyświetl dziennik. Odznaki rejestrują przypadki, w których użytkownik musi wiedzieć, że coś się stało i wyświetlają to następnym razem, gdy otworzy wtyczkę - możliwe do odkrycia bez czytania czegokolwiek.
Możliwe do ponownego wykorzystania w przyszłości:
- Wykryto niezgodność profilu (user-agent urządzenia nigdy nie pasował do żadnego profilu, powrócono do Generic).
- Wyzwolono wycofanie NextURI (F13 - odtwarzanie bez przerw wyłączone dla sesji na niestabilnym urządzeniu).
- Skanowanie biblioteki nie powiodło się / częściowe.
- Utracono połączenie z rendererem w trakcie sesji.
- Każdy inny warunek, w którym "zdarzyło się raz, użytkownik powinien wiedzieć" jest lepsze niż "cicho zalogowane wśród 1000 innych linii".
Konwencje implementacji:
- Etykiety odznak znajdują się na poziomie okna dialogowego (nie w żadnym panelu), więc są widoczne niezależnie od tego, w której sekcji znajduje się użytkownik.
- Umieszczone w dolnym rzędzie w pobliżu Zapisz/Anuluj (obecnie: y=410 ułożone poziomo).
- Każda odznaka ma odpowiadającą jej flagę sesji w
Plugin, która zmienia się na True, gdy wystąpi warunek i resetuje się tylko po ponownym uruchomieniu MusicBee. - Zasoby:
<Condition>Badge(tekst etykiety, prefiks z ⚠) +<Condition>BadgeTip(podpowiedź wyjaśniająca przyczynę + rozwiązanie). - Dla odznak "zapisane ustawienie wymaga ponownego uruchomienia" wykonaj migawkę środowiska wykonawczego w
Plugin.Initialise()i porównaj zSettings.*poSettings.SaveSettings()w obsłudze zapisu okna dialogowego.
N27 - Anuluj odrzuca edycje ścieżek/szablonów
Co: edycje ścieżek i szablonów w oknie ustawień są teraz odrzucane, gdy użytkownik kliknie Anuluj, zamiast cicho pozostawać zastosowane, a każdy zarezerwowany szablon usunięty podczas sesji jest ponownie tworzony. (Szablony w przeciwnym razie zapisują się na żywo podczas edycji - nie ma oddzielnego przycisku Zapisz na karcie Ścieżki.)
Dlaczego: Anuluj powinno oznaczać anulowanie. Wcześniej użytkownik, który eksperymentował ze zmianami ścieżek/szablonów i wycofał się, stwierdził, że zmiany zostały już zatwierdzone, bez możliwości ich cofnięcia, poza ręcznym ponownym wykonaniem każdej z nich.
N28 - Dosłowne ampersandy w menu wyboru pól
Co: pole, którego nazwa zawiera "&" - np. "Nastrój & Kontekst" - renderuje ampersand dosłownie w menu wyboru pól, zamiast połykać go jako prefiks Alt-mnemonic.
Dlaczego: nazwy pól z ampersandem wyświetlały się nieprawidłowo (znak znikał, a następna litera stawała się akceleratorem), co utrudniało rozpoznanie wpisu w menu.
N29 - Stabilny, nieprzetłumaczony tytuł okna ustawień
Co: tytuł okna ustawień jest ustalony na ciąg marki "MusicBee UPnP Plugin" i nie zmienia się już wraz z językiem interfejsu; ciąg DialogTitle dla każdego języka został usunięty z każdego pakietu lokalizacyjnego.
Dlaczego: tytuł okna, który zmieniał się w zależności od języka, był powierzchnią do tłumaczenia bez korzyści - tytuł jest znakiem marki. Ustalenie go sprawia, że jest stabilny i spójny wszędzie.
Lokalizacja
Oryginalna wtyczka jest tylko w języku angielskim. Ten fork jest w pełni lokalizowalny - każdy ciąg znaków widoczny dla użytkownika przepływa przez pakiet zasobów, a wtyczka automatycznie wykrywa język interfejsu MusicBee.
N30 - Wielojęzyczny interfejs użytkownika (tłumaczenia w toku)
Co: mechanizm lokalizacji jest kompletny i dostarczany. Localisation.vb odczytuje wybrany język MusicBee z MusicBee3Settings.ini (endonim <SystemLanguage>) i stosuje pasującą kulturę .NET do wątku, więc My.Resources.Resources.* zwraca zlokalizowany ciąg. Każda etykieta/przycisk/wiadomość widoczna dla użytkownika jest podłączona do klucza zasobu (kontrolki projektanta za pośrednictwem ApplyDesignerExtras + sync-en-locale.js; ciągi środowiska wykonawczego, takie jak WarnPortInUse, dodane ręcznie). To, co nie jest jeszcze zrobione, to faktyczne tłumaczenie: istnieje tylko angielski pakiet źródłowy (Resources.resx) - pakiety satelitarne dla innych języków są produkowane w jednej partii, gdy wtyczka jest kompletna pod względem funkcji (tłumaczenie fragmentaryczne, gdy ciągi nadal się zmieniają, marnuje wysiłek).
Języki docelowe (zestaw oferowany przez samo MusicBee, dopasowany 1:1 przez endonymToCulture, więc wtyczka automatycznie podąża za językiem MusicBee):
Arabski (ar) |
Czeski (cs) |
Niemiecki (de) |
Grecki (el) |
Hiszpański (es) |
Francuski (fr) |
Węgierski (hu) |
Włoski (it) |
Koreański (ko) |
Holenderski (nl) |
Norweski (nb) |
Polski (pl) |
Portugalski BR (pt-BR) |
Portugalski PT (pt-PT) |
Szwedzki (sv) |
Turecki (tr) |
Ukraiński (uk) |
Rosyjski (ru) |
Japoński (ja) |
Chiński uproszczony (zh-CN) |
Chiński tradycyjny (zh-TW) |
Angielski (en, źródło) |
Polityka wariantów (zgodnie z zasadą lokalizacji obszaru roboczego): PT i ZH są podzielone na odrębne pakiety, ponieważ słownictwo/skrypt faktycznie się różni (pt-BR/pt-PT, zh-CN/zh-TW). EN to pojedynczy pakiet - "English(US)" (en-US) MusicBee wraca do en za pośrednictwem łańcucha kultur .NET, więc nie jest produkowany oddzielny pakiet US. ES i FR są również pojedynczymi lokalizacjami.
Dlaczego: ustawienia wtyczki UPnP ("nie używaj surowego PCM", "wymuś PCM little-endian", ostrzeżenia o przełączaniu portów) są wystarczająco enigmatyczne w języku ojczystym. Podążanie za własnym językiem interfejsu MusicBee - zamiast wymuszania angielskiego - to różnica między narzędziem, które użytkownik nieanglojęzyczny może skonfigurować, a takim, którego nie może. Żaden upstream tego nie próbował.
N31 - Link pomocy otwiera się w pełnym języku interfejsu
Co: otwarcie linku pomocy z wtyczki respektuje pełny język interfejsu użytkownika (np. pt-BR, zh-CN) zamiast zwijania do języka podstawowego i wysyła jaśniejszy identyfikator sprawdzania aktualizacji.
Dlaczego: użytkownik uruchamiający MusicBee w wariancie regionalnym (portugalski brazylijski, chiński uproszczony) był kierowany na stronę pomocy w języku podstawowym. Przeniesienie pełnej kultury kieruje go na stronę pomocy w dokładnie tym języku, którego używa.
Poprawki i ulepszenia oryginalnej wtyczki
Podstawowy protokół i odtwarzanie
F01 - Zaktualizowane domyślne profile urządzeń DLNA
Co: dostarcza świeże domyślne profile dla PlayStation 4, Xbox 360/One i nowoczesnego BubbleUPnP, z flagami możliwości (częstotliwości próbkowania, głębie bitowe, kodeki), które odzwierciedlają to, co te urządzenia faktycznie obsługują dzisiaj.
Dlaczego: domyślne ustawienia oryginalnej wtyczki były zamrożone około 2014 roku. PS4/Xbox/BubbleUPnP od tego czasu zyskały obsługę dźwięku wysokiej rozdzielczości. Po wyjęciu z pudełka, nowa instalacja działa najlepiej na tych urządzeniach bez konieczności dotykania ustawień profilu urządzenia przez użytkownika.
F02 - Sterowanie urządzeniami, które reklamują MediaRenderer:3
Co: wtyczka bada opis usługi UPnP renderera, aby zdecydować, czy MusicBee może nim sterować. Oryginał pasował tylko do urn:schemas-upnp-org:device:MediaRenderer:1. Nowoczesne urządzenia reklamują :2 lub :3. F02 rozszerza dopasowanie.
Dlaczego: bez tego, najnowsze jednostki Sonos / WiiM / Eversolo po prostu nie pojawiają się jako cele na liście urządzeń "Odtwórz do" w MusicBee - mimo że mówią tym samym protokołem. Pojedyncza poprawka dopasowania prefiksu ciągu znaków odblokowuje całą nowoczesną generację urządzeń.
F03 - Opcja "Wymuś natywny strumień" dla każdego profilu (domyślnie WŁ.)
Co: po zaznaczeniu, wtyczka wysyła oryginalne bajty pliku do urządzenia bez transkodowania, bez DSP, bez przetwarzania ReplayGain. Po prostu surowy plik wybrany przez użytkownika, bajt po bajcie (z wyjątkiem ramkowania HTTP).
Dlaczego: według świadectw na forum jest to największa pojedyncza poprawa jakości odtwarzania. Użytkownicy hi-fi kupujący drogie renderery wyraźnie chcą wyjścia bit-perfect; każde dotknięcie DSP niweczy sens. Domyślnie WŁĄCZONE, ponieważ większość nowoczesnych urządzeń obsługuje dowolny kodek, który użytkownik im podał, a ReplayGain/EQ powinno być opcjonalne. Jest to dla każdego profilu, więc możesz zachować transkodowanie dla starego Xboxa, jednocześnie wysyłając natywny strumień do przetwornika cyfrowo-analogowego hi-fi.
F04 - "Wymuś transkodowanie" dla każdego profilu
Co: nadpisanie dla każdego profilu, które wymusza transkodowanie każdego strumienia do tego urządzenia, niezależnie od obsługi natywnego kodeka. Odwrotność F03 (ForceNativeStream). Wzajemnie wykluczające się z F03 - interfejs użytkownika automatycznie odznacza drugie, gdy jedno z nich jest włączone.
Dlaczego: pojedynczy globalny przełącznik byłby sprzeczny z opcją ForceNativeStream (F03) dla każdego profilu. Rzeczywisty przypadek: urządzenie A to przetwornik cyfrowo-analogowy hi-fi, który chce bit-perfect natywnych strumieni; urządzenie B to stary amplituner AV, który dławi się FLAC. Z globalnym przełącznikiem użytkownik musi wybrać - kosztem drugiego urządzenia. Z opcją dla każdego profilu każde urządzenie otrzymuje właściwą odpowiedź.
Implementacja:
StreamingProfile.ForceTranscoding As Boolean = False.- Schemat trwałości zwiększony do v9. Pliki sprzed v9 ładują starszą wartość globalną raz i kopiują ją do wszystkich profili, zachowując stare zachowanie po aktualizacji.
- Interfejs użytkownika: usunięty z panelu Diagnostyka, dodany do sekcji Profile urządzeń obok ForceNativeStream. Dwukierunkowe wzajemnie wykluczające się obsługi (
CheckedChangedna każdym odsubskrybuje drugie przed przełączeniem, aby uniknąć nieskończonej pętli). - Miejsce decyzji:
Settings.ForceTranscoding→streamingProfile.ForceTranscodingwWriteAudioFileDIDL.
F05 - "Wymuś PCM little-endian" dla każdego profilu
Co: strumienie PCM (typy mime L16/L24) są domyślnie big-endian. Niektóre urządzenia błędnie oczekują little-endian i odtwarzają biały szum, gdy otrzymają prawidłowe dane big-endian. F05 przełącza kolejność bajtów dla każdego profilu.
Dlaczego: bez tego niektóre urządzenia emitują ścianę szumu. Objaw jest dramatyczny, a przyczyna niewidoczna bez znajomości kodowania PCM - przełącznik daje użytkownikom możliwość zgadywania i sprawdzania.
F06 - "Nie używaj surowego PCM" dla każdego profilu
Co: gdy urządzenie twierdzi, że obsługuje surowe PCM, wtyczka używa tego. Niektóre urządzenia kłamią - akceptują uzgadnianie SOAP, ale zniekształcają rzeczywiste surowe dane PCM, jednocześnie prawidłowo obsługując PCM opakowane w kontener WAVE. F06 wymusza PCM-over-Wave niezależnie od tego, co reklamuje urządzenie.
Dlaczego: konkretnie niektóre modele Marantz - reklamują surowe PCM, ale działa tylko WAVE. Bez tego surowe strumienie PCM wychodzą zniekształcone, bez komunikatu o błędzie wskazującego przyczynę.
F07 - "Długość zawartości" dla każdego profilu
Co: jaką wartość wysłać w nagłówku HTTP Content-Length. Cztery opcje:
- Domyślne - rzeczywista liczba bajtów, gdy znana, pominięta, gdy nieznana.
- Brak - nigdy nie wysyłaj nagłówka (tylko kodowanie chunked).
- Tylko PCM - wysyłaj tylko dla surowego PCM; pomiń dla wszystkiego innego.
- Stałe - wyślij
UInt32.MaxValue - 8192(strażnik dla "ogromnej nieznanej długości").
Dlaczego: urządzenia UPnP/DLNA bardzo różnie reagują na Content-Length. Niektóre potrzebują dokładnej liczby, niektóre nienawidzą jej w strumieniach, niektóre potrzebują strażnika "naprawdę dużej" wartości, aby utrzymać buforowanie. To zostało później rozszerzone z tylko PCM na wszystkie formaty wyjściowe, ponieważ te same problemy pojawiły się w transkodowanych strumieniach MP3/AAC.
F08 - "Nie czyść NextURI" dla każdego profilu
Co: normalnie wtyczka czyści zakolejkowany NextURI urządzenia, gdy kolejka się opróżnia (wysyłając SetNextAVTransportURI z pustym URL). Niektóre urządzenia (zwłaszcza Denon) interpretują pusty NextURI jako "zatrzymaj wszystko" i natychmiast zatrzymują odtwarzanie. F08 zapobiega czyszczeniu go przez wtyczkę.
Dlaczego: bez tego właściciele Denona doświadczają, że urządzenie przerywa odtwarzanie w połowie utworu, gdy kolejka się opróżnia. Z zaznaczonym F08 urządzenie utrzymuje nieaktualny NextURI w pamięci (nieszkodliwe - po prostu zostanie nadpisane następnym razem, gdy coś zostanie zakolejkowane).
F09 - FLAC jako format wyjściowy transkodowania
Co: rozwijana lista formatów transkodowania w profilach urządzeń oferuje teraz FLAC obok PCM 16/24, MP3, AAC, Ogg. Wybranie go kieruje koder BASS przez standardową linię poleceń konwersji FLAC MusicBee (ten sam mechanizm, którego już używają MP3/AAC/Ogg).
Dlaczego: dla urządzeń, które dobrze obsługują FLAC, ale nie potrafią dekodować kodeka źródłowego (np. Eversolo odbierające bibliotekę WMA MusicBee przekonwertowaną na FLAC), zachowuje to bezstratną jakość, gdzie MP3/AAC odrzuciłyby dane audio. Odblokowuje N02 (kontrola miksowania w dół 5.1), którego nie można było rozwiązać bez bezstratnej opcji transkodowania.
Implementacja: dodanie jednej linii do bloku Select Case Codec w Encoder.StartEncode - FLAC dołącza do MP3/AAC/Ogg w gałęzi sterowanej wierszem poleceń. Rozwijana lista interfejsu użytkownika otrzymuje "FLAC" jako 6. opcję. Mapowanie ładowania/zapisu w SettingsDialog rozszerza się, aby rozpoznawać FileCodec.Flac ↔ SelectedIndex = 5. Typy Mime, DLNA i funkcja kodowania były już podłączone w ItemManager.GetMimes / GetDlnaType / GetEncodeFeature z wcześniejszych prac (F21, F26).
Bez przerw (SetNextAVTransportURI)
F10 - SetNextAVTransportURI / NextURI core
Co: prawdziwe odtwarzanie bez przerw. Gdy urządzenie reklamuje obsługę SetNextAVTransportURI w swoim opisie usługi UPnP, wtyczka wstępnie kolejkuje następny utwór na urządzeniu, zanim bieżący się zakończy. Urządzenie przechodzi wewnętrznie bez słyszalnej przerwy między utworami - to, co słyszysz na odtwarzaczu CD. To nie jest hack "ciągłego strumienia" (który łączy wszystko w jeden długi strumień i traci metadane dla każdego utworu).
Dlaczego: flagowa funkcja Tier-2. Albumy nagrane jako ciągły występ na żywo (nagrania na żywo, utwory klasyczne, sety DJ-skie) brzmią źle, gdy między utworami jest półsekundowa cisza. Rozwiązanie tego problemu w sposób prawidłowy to flagowa funkcja, teraz w tym forku.
Uwagi: zakolejkowany dźwięk jest obsługiwany przez serwer HTTP wtyczki za pomocą streamHandle=0 (tryb pobierania biblioteki), co oznacza, że silnik audio MusicBee nie jest zaangażowany w zakolejkowany utwór. Kompromis: efekty ReplayGain/DSP/EQ nie mają zastosowania do następnego utworu. Akceptowalne, gdy włączona jest opcja "wymuś natywny strumień" (domyślnie).
F11 - "Wyłącz obsługę NextURI" dla każdego profilu
Co: nawet jeśli urządzenie reklamuje SetNextAVTransportURI, to pole wyboru zmusza wtyczkę do zignorowania tej reklamy i powrotu do odtwarzania utwór po utworze.
Dlaczego: niektóre urządzenia reklamują NextURI, ale mają błędną implementację (awarie, częściowe przejścia, zawieszenia). Zamiast odtwarzać inżynierię wsteczną każdego uszkodzonego urządzenia, użytkownik otrzymuje przełącznik "po prostu wyłącz to tutaj".
F12 - Cykl życia NextURI na liście odtwarzania
Co: gdy MusicBee wyzwala NowPlayingListChanged, wtyczka ponownie ocenia, co powinno być zakolejkowane do płynnego przejścia. Pyta MusicBee o nowy "następny" utwór za pośrednictwem NowPlayingList_GetNextIndex(1) + NowPlayingList_GetListFileUrl, porównuje z tym, co jest aktualnie zakolejkowane na urządzeniu (śledzone za pomocą nowego pola nextPlaySourceUrl), i ponownie kolejkuje, jeśli się zmieniło (lub czyści kolejkę, jeśli MusicBee mówi, że nie ma następnego utworu).
Dlaczego: bez F12 urządzenie odtwarzało nieaktualny NextURI, gdy użytkownik usunął/zmienił kolejność zakolejkowanego utworu. Historycznie zajęło to kilka iteracji, ponieważ każda mutacja listy wymaga innej obsługi - my uprościliśmy, ufając NowPlayingList_GetNextIndex (który już respektuje losowe odtwarzanie i powtarzanie wszystkich), więc wszystkie warianty przechodzą przez to samo porównanie.
Implementacja:
- Nowe pole
nextPlaySourceUrlprzechowuje adres URL biblioteki MusicBee zakolejkowanego utworu (adres URL strumieniowania z sufiksem uchwytu nie jest porównywalny ze ścieżką biblioteki). - Nowa
Public Sub RefreshQueuedNextUri()naMediaRendererDevice. Trzy wyniki: brak zakolejkowanego NextURI → brak operacji; zakolejkowany pasuje do nowego "następnego" → brak operacji; zakolejkowany różni się → wywołajQueueNextz nowym adresem URL (lubQueueNext(""), aby wyczyścić - co respektuje F08 DoNotClearNextUri). - Podłączone w
Plugin.ReceiveNotificationpodNotificationType.NowPlayingListChanged.
F13 - Wycofanie po awarii NextURI
Co: po 4 kolejnych awariach SetNextAVTransportURI na tym samym urządzeniu, wtyczka wyłącza odtwarzanie bez przerw dla tego urządzenia do ponownego uruchomienia MusicBee.
Dlaczego: jeśli urządzenie jest faktycznie uszkodzone dla NextURI (sporadyczne błędy SOAP, usterki sieciowe), wtyczka w przeciwnym razie ponawiałaby próbę przy każdym utworze. F13 zatrzymuje szum i cicho wraca do odtwarzania utwór po utworze.
F14 - Tryb powtarzania + integracja NextURI
Co: F14 dzieli się na dwa przypadki obsługiwane przez detektor przejścia F15 w OnAvTransportStatusCheck:
- Powtórz wszystko: MusicBee sam przekazuje prawidłowy adres URL "zawijania" (utwór 1 na końcu listy) do
Plugin.QueueNext. Nie jest potrzebna żadna specjalna logika wtyczki - urządzenie przechodzi do niego, a detektor F15 wywołujePlayer_PlayNextTrackjak zwykle, co zawija indeks NPL MusicBee z powrotem do 0. - Powtórz jeden: MusicBee przekazuje TEN SAM adres URL utworu do
Plugin.QueueNext. Urządzenie przechodzi do niego (nowy uchwyt strumienia, to samo źródło). Detektor F15 teraz wysyła zapytaniePlayer_GetRepeat()- jeśli jest toRepeatMode.One, pomija wywołaniePlayer_PlayNextTrack, aby MusicBee nie przesuwał indeksu NPL z dala od zapętlonego utworu.
Dlaczego: bez pominięcia Powtórz jeden, wywołanie Player_PlayNextTrack przy przejściu bez przerw przesunęłoby MusicBee do następnego utworu na liście (Powtórz jeden wpływa tylko na automatyczne zachowanie przewijania na końcu utworu w interfejsie odtwarzacza - Następny utwór zawsze przesuwa się do przodu), co byłoby sprzeczne z tym, co oznacza Powtórz jeden.
Uwaga dotycząca liczby odtworzeń: w trybie Powtórz jeden, zwiększenie liczby odtworzeń zależy od tego, czy MusicBee 3.7.9563+ zauważy zapętlone odtwarzanie. Starsze wersje MusicBee odtwarzają zapętlone odtwarzanie bez przerw prawidłowo, ale pomijają zwiększenie liczby odtworzeń. Udokumentowane; nie blokujące.
F15 - Automat stanów wykrywania przejścia utworu
Co: gdy urządzenie wewnętrznie przechodzi z bieżącego utworu do NextURI, wtyczka musi to zauważyć i poinformować MusicBee, aby przesunął swój indeks odtwarzania. W przeciwnym razie MusicBee myśli, że nadal odtwarza poprzedni utwór, a liczba odtworzeń / interfejs użytkownika / scrobbling rozjeżdżają się.
Implementacja: odpytuje GetPositionInfo.TrackURI przy każdym takcie timera statusu. Gdy zgłoszony URI pasuje do tego, który zakolejkowaliśmy za pośrednictwem NextURI, wywołujemy Player_PlayNextTrack na MusicBee i ustawiamy suppressNextSoapCall, aby wynikowe PlayToDevice nie wysyłało ponownie SetAVTransportURI (co przerwałoby odtwarzanie bez przerw).
Dlaczego: bez F15 urządzenie odtwarza następny utwór, ale interfejs MusicBee mówi, że nadal odtwarza poprzedni. Mylące, psuje scrobbling, psuje śledzenie liczby odtworzeń. Wykrywanie przejścia utworu wymaga długiej, iteracyjnej pracy dla każdego renderera, ponieważ każda marka renderera ma swoje własne dziwactwa w kiedy zgłasza zmianę URI (niektóre najpierw zgłaszają TRANSITIONING, niektóre przechodzą bezpośrednio do PLAYING z nowym URI, niektóre mają krótkie STOPPED pomiędzy).
Uwagi: nasza pierwsza wersja działa na rendererze BubbleUPnP. Przypadki brzegowe dla poszczególnych urządzeń pozostają w B6.
F16 - Naprawa trzasków przy przejściu bez przerw
Co: trzask pojawia się, gdy format źródłowy (częstotliwość próbkowania / kanały / kodek) zakolejkowanego utworu różni się od aktualnie odtwarzanego utworu, zmuszając przetwornik cyfrowo-analogowy urządzenia do ponownego zablokowania przy przejściu. F16 dodaje diagnostykę NextUri:FormatChange, która uruchamia się w momencie kolejkowania, gdy formaty się różnią, nazywając obie strony - dzięki czemu użytkownicy słyszący trzaski mogą skorelować.
Diagnostyka wskazuje również na rozwiązanie: zaznacz Wymuś transkodowanie w profilu urządzenia. To ujednolica każdy utwór do jednego kodeka transkodowania/częstotliwości próbkowania/głębi bitowej, całkowicie eliminując różnicę w formacie źródłowym.
Dlaczego odłożono rzeczywistą poprawkę transkodowania do dopasowania: strukturalna poprawka (transkodowanie zakolejkowanego utworu w celu dopasowania do formatu odtwarzanego utworu) wymaga zmian w schemacie URL serwera HTTP wtyczki - obecnie /encode/{id}0.{ext} obsługuje zakolejkowany plik natywnie. Przyszła wersja 2 F16 dodałaby trasy /encode/{id}0_{rate}_{depth}.{ext} dla każdego formatu i podłączyłaby je przez koder. To większa zmiana architektoniczna, którą warto zrobić, jeśli prawdziwe urządzenie wykazuje trzaski po tym, jak ForceTranscoding nie wystarcza.
Implementacja dzisiaj:
- Pole
lastSourceUrlśledzi aktualnie odtwarzany adres URL źródła. QueueNextodczytujeFilePropertyType.SampleRate/Channels/Kinddla bieżącego i zakolejkowanego utworu i logujeNextUri:FormatChangew przypadku niezgodności.
F17 - Ponowna synchronizacja paska postępu po przewinięciu
Co: funkcja Seek() już wywoływała GetPlayPositionInformation() po udanym SOAP Seek, co naprawiało przypadek "brak synchronizacji w ogóle". F17 eliminuje pozostałe opóźnienie do 1 sekundy spowodowane kwantyzacją RelTime UPnP do 1 sekundy: gdy zgłoszona pozycja urządzenia zaokrągla się do 1 sekundy od żądanego celu użytkownika, wtyczka ufa teraz wartości użytkownika z dokładnością do ułamka sekundy zamiast obcięcia urządzenia. Tylko wtedy, gdy urządzenie zgłasza coś dramatycznie innego (>1s różnicy), używamy jego wartości (przewinięcie wylądowało gdzie indziej niż żądano, np. przyciąganie do klatki kluczowej w niektórych kodekach).
Dlaczego: bez tego, przewinięcie do 2:30.500 zakotwiczone względem raportu urządzenia "2:30" sprawiłoby, że pasek postępu pokazywałby ~500ms za rzeczywistością. Po F17 pasek odpowiada intencjom użytkownika w typowym przypadku przewijania w utworze i nadal respektuje raport urządzenia w przypadku odstępstwa od przyciągania do klatki kluczowej.
F18 - Blokada strumienia ciągłego / NextURI
Co: dwie blokady są teraz na miejscu:
- Środowisko wykonawcze:
QueueNextwcześnie zwracaFalse, gdySettings.ContinuousOutputjest włączone. Strumień ciągły to własny mechanizm bez przerw (jeden długi, połączony strumień); wysyłanieSetNextAVTransportURIna wierzchu tego myli urządzenie co do tego, czy każdy utwór jest dyskretnym URI, czy częścią ciągłego przepływu. - Interfejs użytkownika: gdy użytkownik zaznaczy globalne pole wyboru strumienia ciągłego,
forceNativeStreamaktualnie wyświetlanego profilu automatycznie się odznacza. Strumień ciągły zawsze transkoduje, więc wymuszenie natywnego jest bezsensowne w połączeniu.
Dlaczego: zapobiega to włączaniu przez użytkownika dwóch sprzecznych mechanizmów bez przerw jednocześnie. Bez F18 urządzenie otrzymywałoby zarówno URI strumienia ciągłego, jak i NextURI dla każdego kolejnego utworu, z nieokreślonym zachowaniem w zależności od renderera.
F19 - Ignorowane błędy pustego NextURI
Co: gdy SetNextAVTransportURI jest wywoływane z pustym adresem URL (np. ostatni utwór na liście), niektóre urządzenia zwracają błąd SOAP. F19 cicho je połyka - logowane, ale nie propagowane jako błędy.
Dlaczego: warunek "brak następnego utworu" jest normalny, a nie błędem. Traktowanie go jako krytycznego zanieczyszcza dziennik i (w niektórych przepływach) wyzwala burze ponownych prób.
Typy mime i metadane DLNA
F20 - Typ mime MP3 → audio/mpeg
Co: zgodny ze standardami typ mime MP3 to audio/mpeg, a nie audio/mp3. Ten ostatni jest powszechnym błędnym określeniem, które większość urządzeń toleruje, ale bardziej rygorystyczne renderery go odrzucają.
Dlaczego: cicho naprawia odtwarzanie na bardziej rygorystycznych urządzeniach, które przestrzegają standardu. Kod yaiol miał to już poprawne; nie wymagało to zmian.
F21 - Kolejność typów mime: najpierw wariant bez x-
Co: gdy urządzenie reklamuje zarówno audio/flac, jak i audio/x-flac, wtyczka najpierw zwraca wariant bez x-. To samo dotyczy każdego kodeka z zarówno standardowymi, jak i eksperymentalnymi typami mime.
Dlaczego: prefiks x- oznacza eksperymentalne/nieoficjalne typy mime. Niektóre renderery zachowują się lepiej ze standardową formą. Małe przestawienie, rzeczywisty wpływ.
F22 - Obsługa typu mime Opus
Co: rozpoznaje Opus jako strumieniowalny kodek audio; wysyła typ mime audio/opus podczas obsługi utworów Opus.
Dlaczego: Opus jest obecnie powszechny (nowoczesny kodek kompromisowy dla mowy/muzyki). Bez F22 wtyczka odmówiłaby strumieniowania plików Opus nawet do urządzeń, które je obsługują.
F23 - Obsługa plików źródłowych Monkey Audio (APE)
Co: rozpoznaje pliki .ape jako prawidłowy kodek źródłowy do strumieniowania/transkodowania.
Dlaczego: APE to bezstratny format z niszową, ale lojalną bazą użytkowników. Dodanie go kosztuje niewiele i odblokowuje bibliotekę dla tych użytkowników.
F24 - Awaryjne typy mime AAC / ALAC
Co: jeśli urządzenie obsługuje AAC lub ALAC, ale nie reklamuje ich jawnie w swoim opisie usługi UPnP, wtyczka i tak je oferuje jako awaryjne.
Dlaczego: kilka urządzeń, które dobrze obsługują AAC, zapomniało umieścić je w swoim XML-u możliwości. Bez F24 wtyczka nawet nie spróbuje, wymuszając transkodowanie. Z F24 wtyczka próbuje i pozwala urządzeniu obsługiwać je natywnie, jeśli może.
F25 - Flaga typu DLNA dla natywnych i zakodowanych strumieni WAV
Co: flaga typu DLNA (identyfikator profilu, taki jak LPCM, WAVE, MP3) musi odpowiadać temu, co odbiera urządzenie. F25 zapewnia, że strumienie natywne i zakodowane strumienie WAV są prawidłowo oznaczane.
Dlaczego: niezgodny typ DLNA powoduje, że niektóre urządzenia całkowicie odmawiają odtwarzania lub stosują niewłaściwy dekoder.
F26 - Nagłówek DLNA dla plików FLAC
Co: strumienie FLAC otrzymują prawidłowy identyfikator profilu DLNA w swoich nagłówkach.
Dlaczego: bez niego niektóre urządzenia obsługujące FLAC nie rozpoznają strumienia jako takiego.
F27 - Naprawa obliczania bitrate w metadanych
Co: res@bitrate strumienia ciągłego było obliczane jako (sampleRate * channels * bitsPerSample) / 1000 - kbps, różniące się o czynnik ~125 od specyfikacji UPnP DIDL, która definiuje atrybut jako bajty na sekundę. Teraz dzieli przez 8 zamiast 1000.
Dlaczego: nieprawidłowe wyświetlanie bitrate na urządzeniu - kosmetyczne na większości rendererów, ale niektóre alokują bufory strumienia z wartości i zacinają się na strumieniach, które wyglądają na ~125 razy mniejsze niż są. Ścieżka pliku źródłowego nieciągłego miała to już poprawne ((bitrate_kbps * 1000) \ 8 = bajty/sek); tylko ścieżka strumienia ciągłego była błędna.
F28 - Naprawa formatu czasu metadanych (Marantz)
Co: res@duration w DIDL było formatowane jako H:MM:SS (np. 0:03:42). Specyfikacja UPnP DIDL definiuje format jako H+:MM:SS[.F+] - ściśle z opcjonalnymi, ale zalecanymi ułamkowymi sekundami; niektóre urządzenia Marantz traktują gołą formę jako nieprawidłową i pozostawiają wyświetlanie czasu trwania puste. Teraz formatowane jako H:MM:SS.fff (np. 0:03:42.000).
Dlaczego: problem z wyświetlaniem specyficzny dla marki; zgodny z ISO format z ułamkowymi sekundami naprawia go bez wpływu na żadne inne urządzenie. Zastosowano w obu miejscach emisji DIDL (ścieżka pliku źródłowego + ścieżka strumienia zakodowanego w WriteAudioFileDIDL).
Dodatkowa poprawka w tym samym przejściu: pv:addedTime i pv:lastPlayedTime używały hh (zegar 12-godzinny) w swoich ciągach formatu DateTime zamiast HH (24-godzinny). Każdy utwór dodany lub odtworzony między 13:00 a 23:59 byłby renderowany z błędną godziną (np. 17:42 → "05:42") na urządzeniach, które wyświetlają to pole. Teraz używa HH.
F29 - Obsługa przewijania zakodowanego MP3 (CBR)
Co: transkodowane strumienie MP3 reklamują teraz DLNA.ORG_OP=11 (przewijanie zarówno bajtowe, jak i czasowe) zamiast DLNA.ORG_OP=10 (tylko bajtowe). Urządzenia, które wcześniej odmawiały przewijania czasowego w transkodowanych MP3, mogą teraz normalnie obsługiwać pasek postępu/interfejs przewijania.
Dlaczego: transkoder MusicBee produkuje MP3 o stałej przepływności (CBR) w ustawieniu HighQuality, więc mapowanie bajt ↔ czas jest liniowe - urządzenie może samodzielnie przekonwertować żądanie przewijania czasowego na żądanie przewijania bajtowego HTTP Range bez żadnego wsparcia po stronie kodera. Reklamowanie OP=11 odblokowuje ten interfejs użytkownika na urządzeniu. Bez F29 użytkownicy przewijający w transkodowanym MP3 mieli przewijanie cicho ignorowane lub byli przenoszeni na początek utworu.
Implementacja: zreorganizowano GetEncodeFeature w ItemManager.vb, aby rozbić wbudowany If na czytelny łańcuch If/ElseIf/Else. MP3 otrzymuje jawnie OP=11; inne kodeki inne niż PCM zachowują OP=10. Brak zmian dla AAC/FLAC/itp. - te wymagałyby specyficznej dla kodeka weryfikacji CBR, czego MusicBee nie gwarantuje.
F30 - Obsługa rozszerzenia pliku .mpeg
Co: pliki z rozszerzeniem .mpeg (i jeszcze rzadszym .mpe) są teraz rozpoznawane jako FileCodec.Mp3 w GetCodec. Przed F30 zwracały FileCodec.Unknown i były cicho odrzucane z biblioteki / nie mogły być źródłami transkodowania.
Dlaczego: stare archiwa MPEG-1 Layer 3 czasami używały .mpeg zamiast .mp3 (specyfikacja dopuszcza oba). Kilka plików w bibliotece 300 tys. wystarczy, aby poczuć "MusicBee je pokazuje, ale wtyczka nie" - mylące dla użytkownika.
Zachowanie odtwarzania
F31 - Strumienie radiowe automatycznie używają trybu ciągłego
Co: WriteAudioFileDIDL teraz bada właściwość Kind adresu URL źródła za pośrednictwem Library_GetFileProperty i traktuje każdy plik, którego Kind kończy się na "Stream" (MusicBee zgłasza "MP3 Stream", "Internet Stream" itp. dla radia) jako ciągły, niezależnie od globalnego przełącznika Settings.ContinuousOutput. Używana jest gałąź DIDL strumienia ciągłego (Tytuł: "Strumień ciągły", id="continuousstream", stałe wyjście PCM/Wave); urządzenie widzi pojedynczy strumień o nieskończonym stylu.
Dlaczego: strumienie radiowe nie mają granic utworów, stałej długości, możliwości przewijania. Traktowanie ich jak dyskretnych plików w DIDL powodowało, że wtyczka reklamowała zakresy bajtów i czasy trwania, które nie istnieją. Automatyczne przełączanie, gdy MusicBee już powiedział nam "to jest strumień", usuwa pułapkę, o której użytkownik nie powinien musieć myśleć.
Zakres: dotyczy tylko sytuacji, gdy MusicBee steruje odtwarzaniem (musicBeePlayToMode). Ścieżka pobierania biblioteki (klient UPnP przeglądający) pozostaje niezmieniona - adresy URL radia są tam rzadkie, a zachowanie widoczne dla użytkownika nie powinno się zmieniać bez wyraźnych testów.
F32 - Awaryjne reklamowanie kodeków
Co: jeśli urządzenie nie reklamuje pewnych kodeków (lub wtyczka nie może przeanalizować XML-a możliwości urządzenia), wtyczka nie odrzuca natychmiast strumienia. Zamiast tego próbuje go obsłużyć i pozwala urządzeniu zdecydować.
Dlaczego: wiele urządzeń ma niekompletny lub nieczytelny XML możliwości, ale faktycznie dobrze obsługuje kodek. F32 zamienia małe "zgadnij i spróbuj" na całkowitą odmowę.
F33 - Poprawa synchronizacji paska postępu
Co: pozycja między odpytywaniami jest już ekstrapolowana z zegara ściennego z pojedynczego punktu odniesienia (currentPlayStartTicks), więc pasek postępu aktualizuje się płynnie z szybkością poniżej sekundy. Pozostałym źródłem drgań był początkowy punkt odniesienia dla świeżo rozpoczętego utworu: poprzedni kod zakładał position=0 w momencie, gdy timer statusu po raz pierwszy zauważył, że stan zmienił się na Odtwarzanie, ale do tego czasu urządzenie mogło odtwarzać przez 100-500 ms (jeden interwał odpytywania). Pasek postępu MusicBee zaczynałby od 0, a następnie przeskakiwał do przodu, gdy rzeczywistość nadrobiła zaległości.
Poprawka F33: podczas pierwszego przejścia do stanu Odtwarzanie na nowym utworze (currentPlayStartTimeEstimated=True), wywołaj GetPlayPositionInformation(), aby uzyskać rzeczywistą bieżącą pozycję urządzenia, a następnie zakotwicz się względem niej. UPnP zgłasza tylko rozdzielczość 1 sekundy, więc punkt odniesienia jest nadal skwantyzowany, ale jest znacznie bliżej prawdy niż zakładanie 0.
Dlaczego: płynniejsze + dokładniejsze wyświetlanie postępu, zwłaszcza zaraz po zmianie utworu. Nie ma sposobu na obejście samej rozdzielczości raportowania UPnP wynoszącej 1 sekundę - to jest specyfikacja.
F34 - Drgania paska postępu po zmianie utworu
Co: gdy PlayToDevice jest wywoływane dla nowego utworu, wtyczka pozostawiała currentPlayPositionMs i currentPlayStartTicks na ich poprzednich wartościach utworu przez około 100 ms między SOAP-Play a pierwszym odpytywaniem timera statusu wykrywającym nowy stan Odtwarzania. Pasek postępu MusicBee krótko pokazywałby koniec poprzedniego utworu, a następnie wracał do 0, a następnie wspinał się. F34 zeruje oba w momencie wejścia do PlayToDevice - w momencie, gdy wiemy, że następuje zmiana utworu, zanim jakakolwiek praca SOAP.
Dlaczego: usterka wizualna w przypadku szybkich pominięć (ręczne następne lub przejście bez przerw). Teraz pierwsze zapytanie MusicBee PlayPositionMs po Play zwraca czyste 0, a następnie GetPlayPositionInformation F33 udoskonala je do rzeczywistej pozycji urządzenia przy pierwszym takcie zmiany stanu.
Implementacja: cztery linie na początku PlayToDevice, sparowane z dokładnym kotwiczeniem czasu przejścia F33.
F35 - Błąd "Wymuś transkodowanie"
Co: wymuszenie transkodowania nadal mogło pomijać transkodowanie w niektórych kombinacjach. Po przeróbce F04 dla każdego profilu, dwie konkretne luki zostały usunięte:
- Pierwszeństwo z ForceNativeStream. Gdy oba były True (co może się zdarzyć podczas migracji schematu lub częściowego pliku ustawień), ForceTranscoding teraz wygrywa (
If streamingProfile.ForceTranscoding Then forceEncode = True ElseIf streamingProfile.ForceNativeStream Then forceEncode = False). Wzajemne wykluczanie interfejsu użytkownika zapobiega zaznaczeniu obu przez użytkownika, ale strażnik środowiska wykonawczego obsługuje każdy stan, który załadował się niespójnie z dysku. - Logika bypassTranscodeDecision. Wcześniej:
streamingProfile.ForceNativeStream AndAlso Not Settings.ForceTranscoding. Teraz:streamingProfile.ForceNativeStream AndAlso Not streamingProfile.ForceTranscoding- ta sama zasada pierwszeństwa, ale w tym samym zakresie dla każdego profilu.
Dlaczego: "wymuś" powinno oznaczać wymuś. Jeśli użytkownik wyraźnie włączył ForceTranscoding dla urządzenia, wtyczka nigdy nie może cicho przejść do natywnego strumieniowania, niezależnie od tego, jak inne flagi się połączą.
F36 - Wyjątek zamknięcia renderera
Co: opakowano Plugin.ReceiveNotification w najwyższego poziomu Try/Catch, który loguje każdy nieprzechwycony wyjątek, zamiast pozwalać mu propagować z powrotem do pompy powiadomień MusicBee.
Dlaczego: powiadomienia z MusicBee (PlayStateChanged, VolumeMuteChanged itp.) są wysyłane do ControlPointManager, który komunikuje się z rendererem za pośrednictwem SOAP. Poszczególne miejsca wywołań miały już Try/Catch wokół swoich wywołań SOAP, ale wystarczająco dziwny przypadek synchronizacji (np. renderer umierający między dwoma wywołaniami SOAP w tym samym handlerze powiadomień) mógł nadal uciec. Wrapper najwyższego poziomu jest ostateczną siatką bezpieczeństwa, aby użytkownik nigdy nie zobaczył ogólnego wyskakującego okienka "TargetInvocationException" z MusicBee.
Implementacja: zmieniono nazwę istniejącego ciała na ReceiveNotificationInternal i dodano cienki wrapper ReceiveNotification, który wykonuje Try { ReceiveNotificationInternal(...) } Catch { LogError(...) }. Istniejąca infrastruktura Try/Catch dla każdej metody w ControlPointManager (wokół każdego wywołania PostSoapRequest) pozostaje - F36 to pas + szelki.
F37 - Długie przewijanie utworu wyzwalające fałszywe przejście
Co: przewijanie w długim utworze może spowodować krótkotrwały cykl Stopped→Playing na niektórych rendererach. Bez rozróżnienia, ProcessNewPlayState.Stopped traktuje to jako naturalny koniec utworu i wywołuje Player_PlayNextTrack, przesuwając MusicBee, gdy użytkownik chciał tylko przewinąć. F37 stempluje lastUserInitiatedSeek w Seek() i dodaje 5-sekundową ochronę w handlerze Stopped (odzwierciedlając istniejące okno lastUserInitiatedStop).
Dlaczego: ciche pominięcie do następnego utworu podczas przewijania to jeden z tych błędów, których nikt nie potrafi odgadnąć przyczyny - użytkownik myśli "dziwne, próbowałem przewinąć do przodu, a teraz odtwarza następny utwór". Naprawa jest mechaniczna: ten sam wzorzec, co już istniejące rozróżnienie zatrzymania przez użytkownika.
F38 - Ulepszona obsługa przewijania dla kodeków podatnych na awarie
Co: awaria BubbleUPnP podczas przewijania MP3 była kanonicznym objawem. Po audycie, obecny kod przewijania yaiol już robi właściwe rzeczy - ścieżka natywna prawidłowo obsługuje HTTP Range (206, Content-Range, AcceptRanges), ścieżka zakodowana reklamuje X-AvailableSeekRange i analizuje przychodzące nagłówki timeSeekRange.dlna.org / npt, flagi DLNA.ORG_OP odzwierciedlają rzeczywiste możliwości strumienia (z opcją DisablePcmTimeSeek dla problematycznych urządzeń Platinum). Testowane przez użytkowników na aktualnym BubbleUPnP 4.6.4: nie zaobserwowano awarii.
Dlaczego: awaria BubbleUPnP podczas przewijania MP3 została zgłoszona około 2024 roku, a aplikacja od tego czasu otrzymała około 16 miesięcy poprawek. F29 (zakodowane MP3 OP=11) było nową zmienną, która mogła ją ponownie ujawnić; nie robi tego w testowanych wersjach.
Jeśli awaria powróci: kształt poprawki byłby przełącznikiem "ograniczone przewijanie" dla każdego profilu, który wymusza DLNA.ORG_OP=10 (tylko bajtowe) na oznaczonych kodekach - odzwierciedlając sposób, w jaki DisablePcmTimeSeek już działa dla PCM. Dodaj wtedy, a nie zapobiegawczo.
Interfejs użytkownika i logowanie
F39 - Przycisk "Dodaj" wybiera nowy profil
Co: kliknięcie "Dodaj" na liście profili urządzeń tworzy nowy profil ORAZ automatycznie go wybiera, dzięki czemu użytkownik może natychmiast edytować pola. Nasza refaktoryzacja okna dialogowego z sekcjami już to robi - zarówno ścieżka bezpośredniego dodawania, jak i ścieżka z szablonu kończą się Me.activeStreamingProfiles.SelectedIndex = Me.activeStreamingProfiles.Items.Count - 1. Sprawdzenie potwierdziło, że nasz fork już to obsługuje - nic do zmiany.
Dlaczego: mała niedogodność UX, która okazała się już nie być niedogodnością tutaj.
F40 - Większa liczba maksymalnych połączeń + dziennik ostrzeżeń
Co: limit równoczesnych strumieni wtyczki (SemaphoreSlim wokół Sockets_Stream_File / Sockets_Encoder_Start) był twardo zakodowany na 4. F40 sprawia, że jest on konfigurowalny przez użytkownika na stronie ustawień ogólnych (domyślnie 16, zakres 1-256), dodaje linię dziennika MaxConnections, gdy żądanie musi czekać na wolne miejsce, ORAZ wyświetla czerwoną odznakę ⚠ Maks. połączeń w lewym dolnym rogu okna dialogowego ustawień, jeśli limit został osiągnięty co najmniej raz od uruchomienia MusicBee.
Dlaczego: gdy urządzenie wysyła równoległe żądania (niektóre Marantz/Linn podczas skanowania okładek, sondy metadanych BubbleUPnP obok aktywnego odtwarzania), dodatkowe żądania były blokowane cicho za semaforem - użytkownik widział "urządzenie wolne" bez widocznej przyczyny. Linia dziennika jest dobra do debugowania technicznego, ale użytkownicy nietechniczni nigdy nie czytają dzienników. Widoczna odznaka w oknie dialogowym ustawień sprawia, że warunek osiągnięcia limitu jest wykrywalny dla każdego, kto otworzy preferencje wtyczki.
Implementacja:
- Scentralizowano oczekiwanie w
WaitOnSendBarrier(logTag)wMusicBeeUpnp.vb; oba miejsca wywołań (MediaServerDevice.GetFile,Encoder.StartEncode) go używają. Settings.MaxConnectionsutrwalone w v8 schematu ustawień.Plugin.MaxConnectionsHitto stała flaga sesji ustawiana wWaitOnSendBarrier; resetuje się tylko po ponownym uruchomieniu MusicBee.SettingsDialog.maxConnectionsBadgeto czerwona, pogrubiona etykieta na(16, 410), która wyświetla się tylko, gdyPlugin.MaxConnectionsHitjest True. Posiada podpowiedź wyjaśniającą przyczynę i rozwiązanie.- Semafor jest inicjalizowany raz przy ładowaniu typu, więc zmiana ustawienia wymaga ponownego uruchomienia MusicBee (zauważone w etykiecie pola).
F41 - Logowanie "kodowanie z powodu ReplayGain/DSP"
Co: zamiast oddzielnych linii dziennika "kodowanie dla RG" / "kodowanie dla DSP", pojedyncza linia StreamDecision z F42 zawiera MB-DSP/EQ, MB-ReplayGain, Profile-DSP/EQ, Profile-ReplayGain jako skumulowane powody. Ta sama wartość diagnostyczna, mniej szumu.
Dlaczego: użytkownicy widzą wszystkie powody transkodowania dla danego utworu w jednej linii dziennika, a nie rozproszone. Zobacz F42, aby uzyskać pełne szczegóły.
F42 - Logowanie "renderer nie obsługuje kodeka źródłowego"
Co: dodano linię dziennika StreamDecision dla każdego utworu odtwarzanego na urządzeniu, która mówi "natywny KODEK" lub "transkoduj KODEK→KODEK powód=…". Pole powodu gromadzi każdy warunek, który wyzwolił transkodowanie: MB-DSP/EQ, MB-ReplayGain, Profile-DSP/EQ, Profile-ReplayGain, WebFile, VirtualFile, ForceTranscoding(global), SampleRate<min/SampleRate>max, DownmixToStereo, DeviceLacksCodec(X), BandwidthConstrained.
Dlaczego: użytkownicy byli zdezorientowani nieoczekiwanymi skokami procesora na plikach, które spodziewali się strumieniować natywnie. Jedna linia dziennika na utwór mówi im dokładnie, który warunek spowodował transkodowanie - a jeśli pole pokazuje DeviceLacksCodec(Flac), natychmiast wiedzą, że informacje o protokole urządzenia były niekompletne i mogą chcieć, aby zadziałało awaryjne rozwiązanie F32.
Implementacja: pojedynczy ciąg akumulujący budowany przyrostowo przez łańcuch decyzyjny; logowany raz na końcu. Ograniczony przez Settings.LogDebugInfo, aby uniknąć szumu w dzienniku w produkcji.
F43 - Dziennik SetNextAVTransport pokazuje adres URL źródła
Co: wpisy dziennika QueueNext zawierają teraz source=<ścieżka biblioteki MusicBee> obok stream=<adres URL strumieniowania HTTP>. Ta sama zmiana zastosowana do ścieżki sukcesu i ścieżki awarii (QueueNext:Failed).
Dlaczego: podczas debugowania problemu z zakolejkowanym utworem, adres URL strumieniowania (/encode/aabbccdd0.flac) jest sam w sobie nieprzejrzysty - taki sam dla każdego utworu. Adres URL źródła to czytelna dla człowieka ścieżka biblioteki, która dokładnie mówi, który plik MusicBee próbował zakolejkować.
F44 - Lepsze logowanie błędów typu mime
Co: dwa nowe wpisy dziennika podczas Activate:
Activate:MimeUnverified- uruchamia się dla każdego źle sformatowanego wpisu w odpowiedziGetProtocolInfourządzenia, nazywając, który wpis nie mógł zostać przeanalizowany (aby użytkownik mógł zobaczyć np. "Marantz zwróciłhttp-get:*::*dla jakiegoś kodeka - możliwość jest niezweryfikowana, awaryjne rozwiązanie F32 będzie zgadywać").Activate:NoSinkInfo- uruchamia się raz, jeśli urządzenie w ogóle nie zwróciło elementu<Sink>. Oznacza to, żeSupportedMimeTypespozostaje Nothing, aIsCodecSupporteddegradowane jest do "założenia, że wszystko działa" - przydatny kontekst, gdy później pojawią się błędy "urządzenie odmówiło strumienia".
Dlaczego: przed F44 te ciche awaryjne przejścia możliwości pozostawiały użytkowników zgadujących, dlaczego ich utwory były transkodowane wbrew oczekiwaniom lub odrzucane przez urządzenie. Teraz pojedyncze wyszukiwanie Activate: pokazuje, czy informacje o możliwościach urządzenia były użyteczne.
F45 - Lepsze logowanie błędów metadanych
Co: dziennik wyjątków Browse w ContentDirectoryService.vb został już wzbogacony we wcześniejszych pracach yaiol (sesja błędów Alia Vox) o ObjectID i ślad stosu. F45 rozszerza go dalej o BrowseFlag (metadane vs dzieci), Filter (które atrybuty żądał klient), sortCriteria i partialResultLength (ile bajtów DIDL zostało wyprodukowanych przed awarią - wskazuje, jak daleko w partii znajduje się zły utwór).
Dlaczego: gdy coś pójdzie nie tak w trakcie DIDL, wartość partial-length mówi, czy awaria nastąpiła na pierwszym utworze partii (partial=0) czy w trakcie (partial=N) - w połączeniu z startingIndex partii, można zidentyfikować indeks utworu powodującego problem. Filter i BrowseFlag wyjaśniają, jaki rodzaj przeglądania chciał klient; czasami przeglądanie tylko metadanych kończy się niepowodzeniem, gdzie przeglądanie dzieci dla tego samego ID kończy się sukcesem.
Sieć
F46 - Tryb automatyczny reklamuje tylko na rzeczywistych adapterach sieciowych
Co: w trybie interfejsu Automatyczny wtyczka ogłaszała się (SSDP) na każdym działającym adapterze IPv4. Na maszynie, która również uruchamia tunel VPN (NordLynx) lub wirtualny przełącznik (Hyper-V / WSL / Docker), ta sama biblioteka była ogłaszana również na każdym z tych adapterów, więc punkt kontrolny, z którego nadawałeś, odkrywał serwer dwa lub trzy razy i wyświetlał bibliotekę jako zduplikowane kopie. Tryb automatyczny teraz zachowuje tylko adaptery, które mają rzeczywistą domyślną bramę IPv4 (HasIPv4Gateway) - czego tunele i adaptery wirtualnych przełączników nie mają - więc te są usuwane z listy ogłoszeń. Adres przypięty przez użytkownika nadal wygrywa (ogłaszaj tylko na tym interfejsie), a jeśli żaden adapter nie zgłasza bramy, selektor wraca do każdego adaptera, więc lista reklamowanych adresów nigdy nie jest pusta, a wtyczka nie może stać się niewidoczna.
Dlaczego: duplikat nie jest spowodowany "byciem na VPN" - jest spowodowany ogłaszaniem na adapterze LAN i adapterze tunelu/wirtualnym w tym samym czasie, więc jeden punkt kontrolny widzi ten sam serwer pod dwoma adresami. Konsumencki VPN (NordVPN/NordLynx) tuneluje tylko ruch wychodzący do internetu; renderer DLNA znajduje się w sieci LAN, a ruch w podsieci lokalnej omija tunel, więc adapter tunelu i tak nigdy nie dociera do renderera - usunięcie go usuwa fantomową kopię, nigdy działającą ścieżkę. Test bramy jest tanim, niezawodnym sygnałem, który oddziela rzeczywisty adapter LAN/Wi-Fi od tunelu lub wirtualnego przełącznika. Uzupełnia N05 (który naprawił sposób wysyłania ogłoszeń na takich łączach - multicast zamiast broadcast); F46 reguluje, które adaptery w ogóle otrzymują ogłoszenia.
Znane ograniczenie: VPN mesh / zdalnego dostępu (Tailscale, ZeroTier, WireGuard-to-home), którego renderery faktycznie znajdują się po drugiej stronie tunelu, zazwyczaj przedstawia adapter bez domyślnej bramy, więc tryb automatyczny również go usuwa. Ci użytkownicy zamiast tego przypinają adres VPN, który ma pierwszeństwo przed filtrem bramy.