MusicBee UPnP Plugin Hjelp

Hva er nytt

2.0.9 - 2026-08-23

Oppdateringsvarselet åpner sidene på ditt språk

Hva: koblingene Hva er nytt og Last ned i oppdateringsvarselet åpner nå plugin-sidene på MusicBees eget språk, i stedet for på engelsk.

Hvorfor: disse to koblingene begrenset språket til ett av fire – engelsk, fransk, spansk eller tysk – før de sendte det til nettstedet, så alle andre fikk den engelske siden selv om en oversettelse av den eksisterte. De sender nå MusicBees språk uendret og lar nettstedet bestemme hva som skal vises, noe som er det Hjelp-knappen ved siden av dem alltid har gjort.

2.0.8 - 2026-08-22

Plugin-en presenterer seg nå korrekt for appene og enhetene som oppdager den på nettverket ditt, og innstillingene for Enhetsprofiler er på linje igjen.

Enhetene dine viser riktig produsent, modell og versjon

Hva: når en kontrollapp, en telefon eller en TV finner MusicBee på nettverket ditt, presenterer den nå denne plugin-en som laget av yaiol, peker på plugin-ens egen nettside, beskriver den som dekkende alle tre rollene – server, spiller og renderer – og rapporterer versjonen du faktisk har installert.

Hvorfor: hver UPnP-enhet kunngjør hvem som laget den og hva den er, og kontrollapper viser det som enhetens identitet. Denne plugin-en kunngjorde fortsatt detaljene fra den originale plugin-en den ble forgreinet fra: en annen forfatters navn, MusicBees nettsted i stedet for sitt eget, og et modellnummer frosset til "1.0" siden den aller første utgivelsen. Fra telefonen din var det ingen måte å vite hvilken plugin du snakket med, enn si hvilken versjon av den. Disse detaljene kommer nå fra plugin-en selv, så versjonen som vises ved siden av enheten forblir korrekt med hver oppdatering.

Innstillingene for Enhetsprofiler er på linje igjen

Hva: på fanen Enhetsprofiler deler etikettene og boksene deres en venstre kant og sitter med jevn avstand, og samplingsfrekvensområdet leses som en enkelt rad.

Hvorfor: feltene hadde glidd fra hverandre etter hvert som alternativer ble lagt til fanen over tid, og "til"-etiketten for samplingsfrekvensområdet hadde endt opp med å sitte oppå boksen ved siden av – lesbart når du visste hva det sto, forvirrende første gang du så.

2.0.7 - 2026-08-08

Større spor beholder tittel og posisjonsglidebryter

Hva: Et større spor sendt fra en telefon – en lang FLAC, en høyoppløselig eller DSD-fil – viser nå riktig tittel og kan flyttes gjennom, akkurat som et lite spor. Tidligere ble noen av dem spilt over nettverket i stedet, med en nettadresse i stedet for tittelen og en glidebryter som ikke gjorde noe.

Hvorfor: Plugin-modulen venter på sin lokale kopi før den starter, men den pleide å bestemme på forhånd om en fil var verdt å vente på, basert på størrelsen. Det var egentlig et gjetning om hvor raskt nettverket ditt er, noe den ikke har noen måte å vite: et 65 MB spor ble vurdert som for stort, og var ferdig nedlastet et sekund senere – komfortabelt innenfor ventetiden den allerede hadde gitt opp på. Den overvåker nå ganske enkelt nedlastingen. Mens den fortsatt ankommer, fortsetter plugin-modulen å vente, uansett hvor lang tid det tar; den gir opp bare når overføringen genuint stopper, noe den nå merker raskere enn den gamle faste forsinkelsen gjorde.

2.0.6 - 2026-08-03

Albumer sendt fra en telefon spilles nå av uten et opphold mellom sporene, og internettradio gjenkjennes som radio i stedet for å bli behandlet som en uvanlig lang sang.

Albumer spilles av uten opphold

Hva: når du sender et helt album fra telefonen din, går MusicBee nå fra ett spor til det neste uten pause – slik at liveopptak, DJ-sett og kontinuerlige klassiske verk henger sammen.

Hvorfor: standarden lar en kontrollerende app si "her er hva som kommer neste", noe som gjør en sømløs overgang mulig. Den instruksjonen ble ikke akseptert i det hele tatt, så appen hadde ingen steder å plassere det kommende sporet og annonserte det som om det var det nåværende – årsaken til albumproblemet som ble løst i forrige utgivelse. Den er nå akseptert riktig: neste spor hentes mens det nåværende fortsatt spilles, og MusicBees egen spiller krysser grensen.

Internett-radio gjenkjennes som radio

Hva: en direktesendt stasjon sendt til MusicBee spilles av som en strøm og lastes aldri ned.

Hvorfor: å laste ned en sending gir ingen mening – den har ingen slutt, og det er ingenting å hoppe gjennom – men plugin-modulen hadde tidligere ingen måte å skille den fra en musikkfil, så den begynte å hente og stoppet når nedlastingen vokste forbi en fast størrelse. Den kontrollerende appen angir hvilken av de to den sender, og det leses nå direkte. Ingen innstilling, ingen gjetting.

Lange høyoppløselige spor beholder kopien sin

Hva: DSD-filer og lange 24-bits opptak kan nå flyttes gjennom som ethvert annet spor.

Hvorfor: de ble fanget av størrelsesgrensen ovenfor – en 20-minutters høyoppløselig sats eller et 10-minutters DSD-spor overskred begge den – så kopien deres ble forlatt og posisjonsskyveren sluttet å fungere for akkurat det materialet som mest sannsynlig var verdt å skrubbe. Med radio identifisert riktig, er ingen størrelsesgrense nødvendig.

2.0.5 - 2026-08-03

To rettelser for å styre MusicBee fra en telefon: volumet betyr nå det samme i begge ender, og casting av et helt album fortsetter å fungere etter første spor.

Volumet på telefonen din samsvarer med volumet i MusicBee

Hva: å skru volumet til maksimum på telefonen din når nå maksimum i MusicBee, og MusicBees egen innstilling leses tilbake korrekt på telefonen.

Hvorfor: plugin-modulen fortalte aldri den kontrollerende appen hva dens høyeste volum var, så hver app måtte gjette. En av dem landet på 69, noe som betydde at dens 100 % bare nådde 69 % i MusicBee, mens MusicBees 100 % kom tilbake som 144 % på telefonen – og telefonens volumknapper kunne aldri helt nå toppen. Renderereren angir nå området tydelig, slik at begge ender snakker om samme skala.

Casting av et album beholder titlene og posisjonsglidebryteren

Hva: hvert spor av et album sendt fra en telefon viser nå sin riktige tittel og kan flyttes gjennom, ikke bare det første.

Hvorfor: en kontrollerende app annonserer neste spor en brøkdel av et sekund etter det nåværende, og den annonseringen kansellerte kopien som ble hentet for sporet som skulle spilles – så de fleste sporene falt stille tilbake til å spille over nettverket, noe som mister både tittelen og muligheten til å hoppe rundt. Kopier for flere spor holdes nå ved siden av hverandre, slik at en annonsering ikke lenger kan kansellere den som er i bruk.

2.0.4 - 2026-08-02

Musikk som sendes til MusicBee fra en telefon eller en annen server, oppfører seg nå som et ekte spor: du kan flytte deg gjennom det, og det viser riktig tittel med en gang. I tillegg en fiks for hi-fi-streamere som presenterer seg som én kombinert enhet.

Flytt deg gjennom et spor sendt fra et annet sted

Hva: å dra posisjonsglidebryteren fungerer nå for et spor sendt fra telefonen din, en NAS eller en annen medieserver. For å gjøre dette mulig laster MusicBee ned en kopi av sporet til en midlertidig mappe mens det begynner å spille, og spiller av den kopien. Det tar omtrent et sekund på et hjemmenettverk, kopien slettes så snart du sender et annet spor, og eventuelle rester slettes når MusicBee starter neste gang.

Hvorfor: MusicBee kan starte og stoppe noe det lytter til over nettverket, men det kan ikke flytte seg gjennom det – så glidebryteren så ut til å hoppe og skled deretter rett tilbake til der den var, uten forklaring. Å spille av en vanlig fil på din egen disk fjerner begrensningen helt i stedet for å omgå den.

Riktig tittel og lengde fra første tone

Hva: et spor sendt av en app som ikke gir filene sine en vanlig filendelse, viser nå sin virkelige tittel og lengde så snart det starter, i stedet for å vises som en lang nettadresse.

Hvorfor: MusicBee identifiserer et spor – og finner taggene – fra filendelsen, og noen spillere deler ut adresser uten noen filendelse i det hele tatt. Den lokale kopien har alltid den riktige, så sporet gjenkjennes uansett hva den sendende appen kaller det.

Et hopp som ikke kan gjøres, sier nå ifra

Hva: hvis gjengiveren genuint ikke kan flytte til det forespurte punktet, blir den kontrollerende appen informert, og rapporterer det.

Hvorfor: den svarte tidligere "ferdig" uansett, så glidebryteren skled tilbake et sekund senere uten noe som forklarte hvorfor. Et ærlig avslag er lettere å handle på enn et stille.

Kombinerte hi-fi-streamere leses riktig

Hva: når MusicBee spiller av til en enhet som presenterer seg som én kombinert enhet – en Marantz- eller Denon-streamer, der spilleren sitter inne i en produsent-wrapper sammen med en medieserver – leser plugin-en nå spillerens egne detaljer i stedet for medieserverens.

Hvorfor: den hadde spurt feil halvdel av enheten hvilke lydformater den kunne håndtere, fikk ingen brukbare svar, og fortsatte uten å sjekke – akkurat den maskinvaren der formathåndtering mest trenger å være riktig. En enhets modellbeskrivelse tas nå også i betraktning når den matches med en enhetsprofil; den ble lest fra feil sted og forkastet.

2.0.3 - 2026-08-02

Play-to-rollen vokser: MusicBee kan nå motta musikk som ikke allerede er i biblioteket – en fil på telefonen, på en NAS, på en annen server – i stedet for bare spor den allerede eier.

Spill musikk sendt fra telefonen, ikke bare ditt eget bibliotek

Hva: når du bruker en kontrollapp som Symfonium eller BubbleUPnP til å sende musikk til MusicBee, trenger ikke sporet lenger å komme fra MusicBees eget bibliotek. En fil lagret på selve telefonen, på en NAS eller på en annen medieserver spilles nå av. Tittelen og lengden kommer fra appen som sendte den, slik at sporet vises riktig selv om MusicBee aldri har sett filen.

Hvorfor: play-to-rollen ble bygget for tilfellet der du blar gjennom denne PC-ens bibliotek fra telefonen og trykker på en sang – sporet var allerede på PC-en, så MusicBee spilte ganske enkelt sin egen fil. Alt som kom fra et annet sted ble stille forkastet, noe som gjorde funksjonen ubrukelig for det like naturlige tilfellet med å skyve musikk fra telefonen til de gode høyttalerne.

Et spor som ikke kan spilles av, sier ifra

Hva: hvis rendereren faktisk ikke kan spille av det den ble sendt, rapporterer den nå det tilbake til appen som sendte det.

Hvorfor: den svarte tidligere "mottatt" til alt, så kontrollappen fortsatte og trykket spill. Uten at noe faktisk ble lastet, startet MusicBee på nytt det sporet som hadde blitt liggende igjen fra før – og hvis den filen var borte, klaget den over at dens kilde ikke kunne finnes. Feilen navnga et urelatert spor og pekte ingen steder i nærheten av det virkelige problemet.

Å sende et nytt spor mens det er satt på pause, spiller nå av det sporet

Hva: hvis MusicBee er satt på pause og kontrollappen din sender den noe nytt, starter det nye sporet.

Hvorfor: gjenopptakelse tok prioritet over lasting, så det pausede sporet fortsatte der det slapp, og sporet du nettopp hadde valgt ble droppet uten et ord.

2.0.2 - 2026-08-01

Søk er temaet: det fungerer nå etter artist, returnerer de riktige resultatene, og er raskt på et stort bibliotek. Pluss en ny måte å rette kontrollappens blanding på, og en løsning for tre knapper som ikke førte noe sted.

Søk etter artist fungerer faktisk

Hva: søk etter en artist fra kontrollappen din returnerer nå musikk fra den artisten. Søket samsvarer både med sporets Artist og albumets Album Artist, slik at en samling blir funnet enten du skriver inn utøverens navn eller navnet albumet er arkivert under.

Hvorfor: et artistsøk ble tidligere feilaktig tolket som "gi meg alt av denne typen" – artisten du skrev inn ble kastet bort og hele biblioteket kom tilbake, så et søk som skulle ha matchet noen hundre spor returnerte titusenvis. Å matche bare ett av de to artistfeltene ville ha tapt halvparten av resultatene i stillhet, så begge blir sjekket.

Søkeresultatsiden blar riktig

Hva: å bla gjennom en lang liste med søkeresultater flytter seg nå gjennom den. Hver side du blar til er siden du får.

Hvorfor: serveren pleide å svare på hver forespørsel med den første håndfullen resultater mens den rapporterte det fulle antall treff, så en app som bladde etter mer fortsatte å motta de samme elementene og nådde aldri slutten.

Søk er mye raskere på et stort bibliotek

Hva: et søk kjører nå en enkelt spørring for hele resultatsettet og leser kun taggene på siden du ser på.

Hvorfor: hver side kjørte tidligere spørringen på nytt mot biblioteket og lastet deretter taggene for hvert treff – tusenvis av dem – for å vise et dusin. På en stor samling gjorde dette at hver rulling pauset. Resultatene blir også slettet når biblioteket oppdateres, slik at en redigering aldri blir servert utdatert.

Rett blandingen din mot et filter

Hva: en ny innstilling Tilfeldige avspillinger fra på fanen Bibliotekalternativer. La den stå på All musikk, og kontrollappens mapper Tilfeldige spor / Tilfeldige album oppfører seg som før; velg et av MusicBee-filtrene dine, og hver tilfeldige forespørsel trekker i stedet fra det filteret. Skjulte filtre tilbys også.

Hvorfor: en blandingsmappe ber om en del av "alt", og det er den ene forespørselen som ikke gir noen anelse om hva du mente – så den trakk alltid fra hele biblioteket, inkludert tale. Dette er hvor du sier hva "alt" betyr. Å åpne en blandingsmappe fra innsiden av et filter på enheten blander fortsatt det filteret: et valg du gjør mens du blar, vinner over innstillingen.

Hjelp, GitHub og oppdateringssjekk når ekte sider

Hva: knappene Hjelp og GitHub i innstillingsdialogen, og den automatiske sjekken for en ny versjon, åpner nå sidene de navngir.

Hvorfor: alle tre ble bygget fra en forkortet form av plugin-navnet som ingen side noensinne har eksistert på, så hver feilet i stillhet – knappene syntes å ikke gjøre noe, og oppdateringssjekken rapporterte aldri noe, uansett hvor lenge en ny versjon hadde vært ute.

2.0.1 - 2026-07-26

En runde med feilrettinger for avspilling og navigering, med fokus på podkaster og kontrollerapper (som BubbleUPnP) som styrer avspilling og blanding.

Podkaster starter avspilling uten pause

Hva: En nedlastet podkastepisode oppgir nå sin reelle lengde og filstørrelse med en gang, hentet direkte fra filen på disken og inn i mediemetadataene.

Hvorfor: Uten oppgitt varighet skanner en kontroller som BubbleUPnP hele lydstrømmen hver gang du trykker spill, bare for å finne ut hvor lang episoden er – så avspillingen begynte først etter en merkbar pause. Med lengden nå annonsert, starter den rent.

Podkaster vises når du blar etter artist

Hva: En podkasts shownavn er nå arkivert som dens artist – speilet inn i feltene Artist og Album Artist (og deres sorteringsvarianter), akkurat som det allerede fyller Album-feltet.

Hvorfor: En navigeringssti som grupperer etter et artistfelt, pleide å finne hver podkasts artist tom og ende opp i et tomt nivå. Å behandle selve showet som artisten – i samsvar med å behandle det som albumet – betyr at disse stiene nå når episodene i stedet for ingenting.

«Nylig spilt» og casting fungerer rett etter en omstart

Hva: Å spille av en podkast, lydbok, innboks eller radiospor direkte – uten først å navigere til den, slik BubbleUPnPs «Nylig spilt»-liste og cast-mål gjør – mislykkes ikke lenger. Plugin-modulen laster nå sporet ved behov når det blir bedt om via ID.

Hvorfor: Disse listene ber om et spor rett etter at MusicBee starter på nytt, før noe er blitt navigert, så plugin-modulen hadde aldri sett ID-en og svarte «Ugyldig ID». Den tvinger nå innlasting av de relevante kildene ved den første direkte forespørselen og finner sporet.

«Tilfeldige spor» og «Tilfeldige album» returnerer resultater

Hva: BubbleUPnPs «Tilfeldige spor» og «Tilfeldige album» blandingsmapper, som ber om et tilfeldig utvalg av hele biblioteket, kommer nå tilbake fylt.

Hvorfor: Dette er søk uten tittel å matche, og plugin-modulen svarte tidligere på dem fra en tom intern liste, så de viste alltid ingenting. De blir nå servert – korrekt paginert – fra den samme on-demand spørrestien som resten av navigeringen bruker.

Album med en tom tag viser sporene sine

Hva: Å åpne et album som ble gruppert på en tom verdi – for eksempel innboksspor som ikke har noe år – viser nå sporene sine.

Hvorfor: Matchen som samler et albums spor, behandlet «denne taggen er tom» som «ingen match», så ethvert album dannet fra et tomt felt navigerte til ingenting. En tom gruppeverdi matcher nå korrekt sporene som deler den.


2.0.0 - 2026-07-22

Dette er den første offentlige utgivelsen av den åpen kildekode yaiol-forken av MusicBee UPnP-plugin-modulen. Den presenteres i to deler: alt som er nytt i denne forken, deretter feilrettingene og forbedringene som er gjort i den originale plugin-modulen. Hvert element beholder Hva / Hvorfor-formen fra prosjektets interne funksjonskatalog, slik at begrunnelsen bak hver endring er på siden, ikke bare endringen.

Nytt i denne forken

MediaRenderer - spill til MusicBee

N01 - MusicBee som en avspillings-renderer

Hva: normalt fungerer denne plugin-modulen én vei: en telefon eller annen enhet blar gjennom MusicBees bibliotek og spiller av musikken på seg selv. Denne funksjonen legger til den motsatte retningen – den lar MusicBee være avspilleren. Fra en kontrollerapp på telefonen (som BubbleUPnP) kan du velge din stasjonære MusicBee som den som spiller, og deretter styre den fra hånden din: spill av, pause, stopp, hopp fremover eller bakover, hopp til et punkt i sporet, og endre volumet eller demp lyden.

Hvorfor: det gjør telefonen din til en fjernkontroll for musikken som allerede er på PC-en din. Sitt i sofaen, bla gjennom biblioteket ditt på telefonen, trykk på et spor, og det kommer ut av høyttalerne som er koblet til skrivebordet ditt – med full kontroll fra der du sitter. Den originale plugin-modulen leverte aldri dette som en fungerende funksjon.

Slå den på: den er av som standard, fordi å slå den på lar alt på hjemmenettverket ditt starte avspilling på PC-en din. Du aktiverer den med en avkrysningsboks på innstillingsdialogens Generelt-fane. Plugin-modulens tre roller har hver sin avkrysningsboks der – del biblioteket mitt (Server), la andre spille til meg (Renderer), og spill til andre enheter (Kontrollpunkt) – og dialogen viser bare innstillingsfanene som rollene du slo på faktisk trenger, slik at du aldri blir møtt med alternativer som ikke gjelder for deg.

Skille maskinene dine fra hverandre: du kan gi rendereren hvilket som helst navn du vil (det starter som "MusicBee (yaiol)"). Det navnet er det som vises i telefonens liste over avspillingsmål, så når mer enn én PC kjører MusicBee kan du se hvilken som er hvilken. En navneendring trer i kraft umiddelbart, uten omstart.

Best mulig lyd når den spiller til seg selv: når du blar gjennom MusicBees eget bibliotek fra telefonen din og sender et spor tilbake til den samme MusicBee, gjenkjenner plugin-modulen at den blir bedt om å spille av en av sine egne filer og spiller den ganske enkelt direkte fra disken din. Resultatet er nøyaktig og øyeblikkelig – bit-perfekt, med MusicBees egen equalizer og volumutjevning brukt – i stedet for meningsløst å sende lyden ut på nettverket og rett tilbake til seg selv.

Kjøre den privat: de tre rollene fungerer uavhengig, slik at du kan slå på rendereren mens du lar bibliotekdeling være av. I dette "kun renderer"-oppsettet forblir biblioteket ditt helt skjult fra nettverket – bare avspillingsmålet blir annonsert – og MusicBee vil aldri tilby å spille til seg selv.


Avspillingsatferd

N02 - 5.1 FLAC ikke automatisk nedmikset

Hva: kanaltallbegrensningen i MediaServerDevice.GetEncodedFile var If StereoOnly OrElse Not isPcmData Then channelCount = 2. Klausulen Not isPcmData nedmikset stille hver ikke-PCM-transkode (FLAC, MP3, AAC, Ogg) til stereo uavhengig av kildekanaltall, og deaktiverte 5.1-kompatible renderere når kilden var 5.1 FLAC. Nå ekskluderer den andre klausulen FLAC: Not isPcmData AndAlso encoder.Codec <> FileCodec.Flac. FLAC 5.1 passerer gjennom; MP3/AAC/Ogg tvinges fortsatt til stereo fordi MusicBees kommandolinjekodere for disse formatene forventer 2-kanals inndata.

Hvorfor: hele poenget med å transkode en 5.1 FLAC-kilde til FLAC-utdata er å bevare flerkanalsmiksen. Stille nedmiksing gjorde FLAC-transkodealternativet ubrukelig for surroundlytting. Med N02 gjør det det riktige.


Arkitektur

Den strukturelle endringen som gjør forken levedyktig på et stort bibliotek – fraværende fra den originale plugin-modulen.

N03 - Lat (on-demand) bla-tre

Hva: den originale plugin-modulen bygde hele bla-treet ved MusicBee-oppstart – enumererte hvert spor, full Library_GetFileTags per fil, samlet hele containerhierarkiet – før HTTP-porten ble åpnet. På et ekte bibliotek (50k+ spor, 5400 podcastepisoder, hundrevis av stasjoner) er det minutter med kaldstart, og treet forblir i RAM for alltid, inkludert grener ingen klient noen gang åpner. Denne forken bygger ingenting på forhånd: roten eksponerer én L:-prefikset plassholder per endepunkt (L:music, L:podcast, L:filter:…); hvert nivå beregnes bare når en klient blar inn i det (LazyBrowseEnsureLazyEndpointInMemory → per-nivå-cacher), og bibliotekendringsvarsler tømmer cachene (SetLibraryDirty).

Hvorfor: kaldstart er i hovedsak øyeblikkelig – HTTP-porten er åpen når MusicBee er ferdig med plugin-initialisering – og minnet forblir proporsjonalt med det som er blitt bladd gjennom, ikke med bibliotekstørrelsen. Kompromiss: den første bla-operasjonen inn i et endepunkt betaler lastkostnaden; gjeninntreden er bufret til neste bibliotekendring. Dette er grunnlaget alt annet avhenger av. Fullstendige notater: FIXES.md.


Nettverk og robusthet

Herding av HTTP-serverens bindesti. Den originale plugin-modulen dør stille når porten er utilgjengelig.

N04 - Selvreparerende HTTP-portbinding

Hva: plugin-modulens HTTP-server dør ikke lenger når den konfigurerte porten er utilgjengelig. Tre sammenkoblede endringer:

  1. Automatisk tilbakefall ved bindefeil. HttpServer.Start prøver den konfigurerte porten, og ved SocketException skanner oppover opptil 20 porter etter den første ledige. Den faktisk bundne porten registreres i en ny Plugin.boundServerPort, og alt som annonserer serveren – SSDP LOCATION-URL-er (NOTIFY + M-SEARCH-svar), enhets-URL-en (PrimaryHostUrl), ruterens portvideresending, og SSDP/kontrollpunktets selvfiltre – leser nå boundServerPort i stedet for Settings.ServerPort. UPnP-klienter oppdager den virkelige porten via SSDP, så en flyttet port er transparent for renderere.
  2. Brukervarsling. Når et tilbakefall skjer (den lagrede porten er ikke den som er i bruk), forteller en lokalisert MessageBox (WarnPortInUse) brukeren hvilken port som faktisk serverer og at enheter fortsatt vil finne den – fordi plugin-modulen kjører hodeløst og en melding i dialogen bare ville blitt sett av noen som allerede mistenkte et problem.
  3. Omstartsgjenoppretting. RestartServer (omstartsstien for innstillingslagring) pleide å dereferere Plugin.controller / Plugin.server blindt. Hvis den første Initialise kastet en feil før de ble opprettet (nøyaktig hva en mislykket binding forårsaket), ville neste innstillingslagring treffe en NullReferenceException – og etterlate en halvdød plugin-modul. Den gjenskaper og starter dem nå når Nothing, slik at lagring av en fungerende port gjenoppliver plugin-modulen uten en full MusicBee-omstart.

Hvorfor: utløseren var en reell brukerhendelse. Den gamle standardporten 49382 ligger i Windows' dynamiske område (49152-65535), der Hyper-V/WSL2/Docker/WinNAT reserverer store blokker som flytter seg ved hver oppstart – så binding mislyktes med WSAEACCES ("tilgang nektet") på en maskin der det hadde fungert i måneder. Endring av standard til en ledig port kolliderte deretter med Serviio (en separat DLNA-server som allerede var på den nye porten), og mislyktes med WSAEADDRINUSE. Hver feil ble svelget i Initialise, og etterlot plugin-modulen stille død og deretter NRE-ing ved neste innstillingslagring. Etter N04 selvreparerer en portkollisjon – serveren fortsetter å kjøre på neste ledige port, brukeren blir informert, og klienter oppdager den på nytt – i stedet for å ta ned hele plugin-modulen.

Implementering:

  • Standardport flyttet 493829779 (under det dynamiske området, så Windows reserverer den aldri automatisk; ikke en kjent medieserverstandard) i alle tre ServerPort-deklarasjonene + tilbakefallet for innstillingsparsefeil.
  • Plugin.boundServerPort (nytt delt felt) holder den aktive lytteporten; activeServerPort forblir det konfigurerte øyeblikksbildet slik at "Omstart påkrevd"-merkelogikken ikke utløses feilaktig ved et tilbakefall.
  • HttpServer.PortScanRange = 20; skanningen stopper ved den første vellykkede TcpListener.Start() og kaster den siste unntaket bare hvis alle forsøk mislykkes.
  • Ny EN-ressursnøkkel WarnPortInUse (oversettelser følger publiseringstidens lokaliseringspass).

N05 - SSDP-kunngjøringer over multicast-gruppen (VPN / punkt-til-punkt)

Hva: SSDP-kunngjøringer sendes til UPnP multicast-gruppen (239.255.255.250) i stedet for en IP-kringkastingsadresse. Den ufarlige "kan ikke få tilgang til et disponert objekt"-feilen som logges når et SSDP-søkesvar raser en serveromstart, undertrykkes også.

Hvorfor: på punkt-til-punkt / VPN-nettverksadaptere gjelder ikke IP-kringkasting – den gamle kringkastingssendingen mislyktes med "ugyldig argument" og kunngjøringer ble savnet, så plugin-modulen var usynlig for klienter på disse koblingene. Kunngjøring til riktig multicast-gruppe fikser oppdagelse på akkurat disse adapterne.

Biblioteknavigasjon

Disse ble levert i denne forken og er ikke i den originale plugin-modulen. De kom fra faktisk å bla gjennom plugin-modulens egen utdata fra ekte UPnP-klienter.

N06 - Filterbasert bibliotekeksponering

Hva: MusicBees filterfaner (.xautopf-filer i brukerens MusicBee-mappe) blir UPnP-rotbeholdere i plugin-modulens bibliotek. Hvert filters spor kan deretter bla gjennom i et hierarki av AlbumArtistSort → Album → Tracks.

Hvorfor: brukere med kuraterte MusicBee-filtre (f.eks. "5-stjerners spor", "Nylig lagt til", "Klassisk → Barokk") forventer å finne dem når de blar gjennom plugin-modulen fra en UPnP-klient. Original plugin-modul eksponerte bare det rå biblioteketreet.


N07 - SortAlbumArtist-feltkobling

Hva: plugin-modulen leser nå MusicBees MetaDataType 165 (Sort Album Artist) og bruker den til å gruppere/sortere artister i bla-visninger.

Hvorfor: hi-fi-nettlesere og audiofile bruker sorteringsartistnavn ("Beethoven, Ludwig van" i stedet for "Ludwig van Beethoven") for å organisere biblioteker. Standard forventning for seriøse lyttere. Mangler fra begge oppstrøms.


N08 - Håndtering av fler-verdi AlbumArtist

Hva: når et albums AlbumArtist-felt inneholder flere artister atskilt med "; " (f.eks. "yaiol; Ars Ricercata"), vises sporet nå under hver artist i bla-visninger, ikke under en enkelt Frankenstein-artist som kombinerer navnene.

Hvorfor: samarbeidsalbum og samlealbum må vises under hver samarbeidspartner. Uten dette er halvparten av søkebanene for å finne albumet ødelagt.


N09 - Album-container-kunst (upnp:albumArtURI)

Hva: album-container-noder i DIDL Browse-svar inkluderer nå et upnp:albumArtURI-element som peker på albumomslaget.

Hvorfor: uten dette viser hvert album i en UPnP-klients bla-visning et generisk ikon i stedet for albumomslaget. Visuelt signal for navigasjon; forventet av hver moderne hi-fi-nettleser.


N10 - Sporrekkefølge i filteralbum

Hva: spor i et filtereksponert album sorteres nå etter Disc Number, deretter Track Number.

Hvorfor: standard albumrekkefølge. Uten eksplisitt sortering kom spor tilbake i den rekkefølgen filteret tilfeldigvis returnerte dem – vanligvis tilfeldig utseende.


N11 - Feilretting for spillelistemappe-tre

Hva: funksjonen LoadLibraryPlaylists (opprinnelig av Steven Mayall, ~2014) klarte ikke å gå ned i nyopprettede spillelistemapper. Den første spillelisten i hver mappe, pluss eventuelle undermapper, endte opp foreldreløse på rotnivå.

Hvorfor: til stede i den originale plugin-modulen i elleve år. Synlig innen 30 sekunder etter å ha åpnet BubbleUPnP og klikket på Spillelister. Fikset i yaiol ved å korrekt rekursere inn i nyopprettede mapper under trekonstruksjon.


N12 - Sanering av XML-ugyldige kontrolltegn

Hva: ethvert spor med en tagg som inneholder et C0-kontrolltegn (f.eks. 0x19 fra en dårlig koding – UTF-8 → Latin-1 → tilbakekapping av 0x99 til 0x19) førte til at hele Browse-svaret mislyktes med Action Failed når det dårlige sporet kom inn i en paginert batch.

Hvorfor: XML 1.0 forbyr de fleste C0-kontrolltegn, og XmlWriter kaster en feil når den blir bedt om å skrive noen. Til stede i den originale plugin-modulen. Fikset ved å fjerne ugyldige tegn ved hvert Library_GetFileTags-utgangspunkt via XmlConvert.IsXmlChar.


N13 - Radiolisting deterministisk over paginert Browse

Hva: Bla for Radio-beholderen falt inn i den generiske filliste-grenen, som kalte files.Sort(AlbumFileComparer) ved hver kall. Radiooppføringer har tomme Album/Disc/Track-tagger, så hver sammenligning returnerte 0 – List(Of T).Sort er ustabil, og produserte en annen rekkefølge hver gang den ble kalt. UPnP-kontrollpunkter paginerer (BubbleUPnP henter 0..15 deretter 16..slutt); mellom de to kallene ble listen omorganisert, slik at noen stasjoner dukket opp på begge sidene (duplikater) og noen på ingen (manglende) – og så tilfeldig ut ved hver oppdatering.

Hvorfor: til stede i den originale plugin-modulen (forfatteren blar aldri radio via UPnP). Fikset her med en dedikert ContainerCategory.Radio-gren i Browse, ingen sortering per kall; radioFiles sorteres én gang ved lastetid etter Tittel (stabil). Paginert bla ser nå en deterministisk rekkefølge; side 1 og side 2 er disjunkte.


N14 - UPnP Search album-klasse returnerer album-containere

Hva: UPnP Search for album-klasse spørringer (upnp:class = "object.container.album.musicAlbum", f.eks. BubbleUPnPs "Random Albums") returnerte hele sporlisten i stedet for album-containere, så klienten viste null album. Den originale håndtereren analyserte bare parentesiserte kriterier, og dumpet deretter alle spor uavhengig av den forespurte klassen.

Hvorfor: fikset her – album-klasse spørringer enumererer nå distinkte album (gruppert etter AlbumArtist+Album) og sender ut hver som en riktig musicAlbum-container med omslagskunst, adresserbar via Salb<idx> virtuell-ID-rom slik at klienten kan bore inn i et resultat og spille det av.


N15 - Fungerende, omfang-bevisst UPnP-søk med klikk-gjennom

Hva: originalen annonserte ingen søkemuligheter (GetSearchCapabilities returnerte tom), så klienter nektet å sende et søk; og den gamle backend leste fra musicFiles, permanent tom i den late-tre-æraen. Denne forken annonserer de virkelige søkbare egenskapene, implementerer spor-etter-tittel og album-etter-tittel mot det late biblioteket (HandleLazySearch), omfang spørringen til klientens nåværende gren når en ekte container-ID sendes (ellers erstatter L:music slik at topplinjesøk ikke drar inn podcast/radio/lydbokstøy), og gjør albumresultater klikkbare via syntetiske Ssrch_alb_*-ID-er som en Browse-tidlig-gren mapper tilbake til albumets spor. (Album-klasse-resultater-som-containere-delen er N14.)

Hvorfor: søk i BubbleUPnP gikk fra "Biblioteket støtter ikke søk" til å returnere nyttige, omfang-begrensede, spillbare resultater. Full design + avviste tilnærminger: SEARCH.md.


N16 - UPnP cache-invalidisering (SystemUpdateID)

Hva: originalen returnerte en konstant SystemUpdateID=0 – UPnP ContentDirectory cache-invalidiseringskontrakten – så spesifikasjonskompatible klienter (BubbleUPnP) behandlet biblioteket som aldri-endrende: utdaterte bla-resultater, 404-miniatyrbilder etter en URL-skjemaendring, og "start MusicBee to ganger for å se endringer"-dansen. Denne forken sår SystemUpdateID fra epoch-sekunder ved lasting (så hver omstart er strengt tatt foran den forrige) og øker den ved hver bibliotekmutasjon og innstillingsendring (SetLibraryDirty / ResetCacheBumpSystemUpdateId).

Hvorfor: klienter plukker pålitelig opp redigeringer, nye filer og innstillingsendringer ved neste bla. Kjent begrensning: abonnerte klienter blir ikke aktivt re-pushet den nye verdien via GENA (parkert som fremtidig arbeid); de ser den fortsatt ved neste bla.


N17 - Podcast-abonnement-kunst

Hva: podcast-fliser viste ingen bilder – hver /PodcastThumbnail/-forespørsel 404'd. To stablede feil: oppløsningskjeden sjekket aldri MusicBees faktiske kunstcache (%LocalAppData%\MusicBee\InternalCache\Subscriptions\<name>.jpg, der skrivebords-UI-en laster fra), og HTTP-lagets unescape+lowercase ødela feed-URL-rutenøkkelen ned til det siste banesegmentet. Denne forken løser kunst fra MBs InternalCache og ruter oppslag via en URL-sikker slug som overlever HTTP-laget intakt (PodcastSlug / podcastSubIdBySlug).

Hvorfor: abonnementskunst gjengis nå i bla-visninger (alle 22 tidligere 404-forespørsler løses).


N18 - Hierarkisk (avgrenset) tag-browsing

Hva: ethvert felt kan merkes som hierarkisk på fanen Bibliotekalternativer og gis en enkelttegn-avgrenser (en feltvelger + avgrenserboks med legg til/fjern, lagret i plugin-innstillingene). Sett Gruppering til / og en verdi som Jazz/Cool Jazz blar deretter som Jazz › Cool Jazz i stedet for en flat oppføring. Spor tagget nøyaktig ved en gren (bare Jazz) får sin egen [Jazz]-node slik at ingenting er skjult, en gren med et enkelt barn kollapser av seg selv, og ; nektes som avgrenser fordi det er MusicBees egen fler-verdi-separator.

Hvorfor: dype tag-taksonomier en bruker allerede har kodet i et enkelt felt (sjanger-trær, stemningshierarkier, "Klassisk/Barokk/Konsert") blar endelig som treet taggen beskriver, i stedet for en flat vegg av skråstrek-separerte strenger brukeren må lese ende-til-ende.


N19 - Enkelt rotsti merket med sitt grupperingsfelt

Hva: en enkelt bla-sti ved roten er merket med sitt grupperingsfelt (f.eks. "Sjanger") i stedet for sin fulle korte sti, som samsvarer med hvordan sammenslåtte førstefeltgrupper navngis.

Hvorfor: bla-treet leses konsekvent – én navngivningsregel enten en rotpost står alene eller ble slått sammen med søsken (N20) – i stedet for at en ensom rotpost viser en detaljert intern sti mens dens sammenslåtte naboer viser et rent feltnavn.


N20 - Slå sammen bla-stier som deler et første felt

Hva: to bla-stier som deler det samme første feltet – "Sjanger / Sorter albumartist" og "Sjanger / Podcast-personer" – kollapser til en enkelt Sjanger-rotmappe som først lister opp sjangerverdiene og deretter deler seg i de to visningene, i stedet for to nesten-dupliserte "Sjanger / …"-oppføringer side om side ved roten.

Hvorfor: en bruker med flere relaterte visninger nestet under et felles felt så roten rotete med nesten identiske toppnivåoppføringer. Å slå dem sammen holder roten lesbar og grupperer de relaterte visningene der de hører hjemme – under deres delte felt.


N21 - Kategoritypede bla-stier (Standard / Radio / Podcast)

Hva: hver bla-sti er typet etter kategori – Standard, Radio eller Podcast. Mal-listen er gruppert i disse tre seksjonene, hver mals feltvelger tilbyr bare feltene som kategoriens data faktisk kan levere, og en mal kan bare brukes på matchende noder i visningstreet (inkompatible noder blir grået ut og kan ikke merkes). De reserverte Radio- og Podcast-malene kan ikke slettes, så deres kategoriseksjon forsvinner aldri.

Hvorfor: uten typingen kunne en bruker bygge et oppsett som stille kom opp tomt – en radiostasjon har ingen "album", en podcastepisode har ingen "albumartist" – og bare oppdage det ved å bla til en død mappe fra en UPnP-klient. Å begrense feltmenyen og anvendelsesmålene til kategoriens virkelige data gjør tomme oppsett umulig å bygge.


N22 - Grupper podcaster etter publiseringsår

Hva: hver podcastepisodes publiseringsdato leses inn, slik at en podcast-bla-sti med et År-nivå bøtter episoder etter år i stedet for å kollapse dem under en enkelt "Ukjent".

Hvorfor: store podcast-abonnementer blir navigerbare etter år som resten av biblioteket, i stedet for at hver episode lander i en udaterte haug fordi plugin-modulen aldri så på publiseringsdatoen per episode.


N23 - Kollaps enkeltresultatgrupperingsnivåer

Hva: et grupperingsnivå som løser seg til en enkelt verdi – et Record Type-nivå som bare viser "LP" for en artist som bare laget LP-er, eller et bokstavnivå med en enkelt bokstav – hoppes over automatisk, og slipper brukeren rett inn i innholdet.

Hvorfor: å bla gjennom en mappe som inneholder nøyaktig én mappe er ren friksjon. Å kollapse enkeltvalgsnivået fjerner det døde klikket uten å endre hva brukeren kan nå.


N24 - Årsgruppering/søk mot MusicBees datofelt

Hva: årskondisjonen spør ikke lenger MusicBees full-dato "År"-felt med en bar firesifret verdi, og den hardkodede år-felt-aliasingen er borte slik at hvert grupperingsfelt nå løses generisk fra stidefinisjonen.

Hvorfor: for biblioteker hvis År-tagg inneholder en komplett dato, returnerte gruppering eller søk etter år tidligere ingenting – den firesifrede spørringen matchet aldri full-dato-feltet. Spørring av riktig felt gjør at årsgruppering og søk finner sporene igjen.


N25 - Separate "År" og "År (åååå)" grupperingsfelt

Hva: albumgruppering og bla-stier eksponerer nå begge MusicBees egne årsfelt – År (hele datotaggen) og År (åååå) (bare det firesifrede året) – slik at brukeren kan velge enten når de definerer en albumgruppering eller en bla-sti.

Hvorfor: de to feltene betyr forskjellige ting i MusicBee, og å kollapse dem mistet den distinksjonen. Å vise begge lar en bruker samle hver utgivelse av et år sammen (åååå) eller beholde eksakt-dato-rekkefølge (full År-tagg), som de har til hensikt.


N32 - Festede filtre og spillelister gruppert etter type ved roten

Hva: et festet filter vises nå direkte under Filtre-mappen ved bla-roten, og en festet spilleliste direkte under Spillelister-mappen, i stedet for at alle fester samles i en klump på slutten av roten. Hver festet snarvei sitter med sin egen type.

Hvorfor: når en bruker fester flere snarveier, blir en enkelt etterfølgende klump med blandede filtre og spillelister vanskeligere å skanne og skiller hver snarvei fra mappen den tilhører. Gruppering av festede elementer under sin egen kategori holder roten lesbar og holder hver snarvei ved siden av tingene den tilhører.

Innstillingsdialog og pakking

N26 - Seksjonert innstillingsdialog

Hva: Innstillinger-siden fikk et venstre-nav-oppsett med seksjoner: Generelt / Avspilling / Bibliotek / Enhetsprofiler / Diagnostikk.

Hvorfor: originalen var en enkelt høy, flat liste over alle innstillinger – greit for utvikleren som bygde den, forvirrende for alle andre. Seksjonering grupperer relaterte alternativer og gjør at dialogen føles mer som moderne appinnstillinger.


Assembly + plugin-navneendring (ingen F-id - pakkenotat)

Hva: den kompilerte DLL-en heter mb_UPnP_yaiol.dll og plugin-modulen rapporterer seg selv som "MusicBee UPnP (yaiol)". Forskjellig fra den originale mb_Upnp.dll.

Hvorfor: brukere kan installere yaiol sammen med den originale plugin-modulen og sammenligne atferd side om side.


Merkesystem - synliggjøring av kjøretidsstatus (mekanisme bak F40)

Hva: et generisk UI-mønster for å synliggjøre viktige kjøretidsforhold som synlige fargede merker i innstillingsdialogen. Nåværende forekomster:

  • ⚠ Maks tilkoblinger (N04) - utløses når maks-tilkoblingsgrensen ble nådd minst én gang siden MusicBee startet. Klebrig sesjonsflagg Plugin.MaxConnectionsHit. Satt inne i WaitOnSendBarrier når ingen spor er ledig.
  • ⚠ Omstart påkrevd - utløses når en lagret innstilling krever en MusicBee-omstart for å tre i kraft. Klebrig sesjonsflagg Plugin.RestartRequired. Satt i dialogens Lagre-håndterer når den nye vedvarende verdien avviker fra kjøretidsøyeblikksbildet (Plugin.activeMaxConnections, Plugin.activeServerPort, Plugin.activeIpAddress). Omstart-påkrevde innstillinger er begrenset til de som genuint ikke kan hot-reloades - HTTP-serverens bindeparametere og SemaphoreSlim bygget én gang ved Initialise.

Hvorfor: plugin-modulens loggfil er fin for tekniske brukere som feilsøker, men en ikke-teknisk bruker som ser på "enheten høres feil ut" eller "avspillingen er treg" vil aldri åpne Diagnostikk → Vis logg. Merker fanger opp tilfellene der brukeren trenger å vite at noe skjedde og synliggjør det neste gang de åpner plugin-modulen - oppdagbart uten å lese noe.

Gjenbrukbart for fremtiden:

  • Profiluoverensstemmelse oppdaget (enhetens brukeragent matchet aldri noen profil, falt tilbake til Generisk).
  • NextURI-tilbakekobling utløst (F13 - gapless deaktivert for økten på en ustabil enhet).
  • Bibliotekskanning mislyktes / delvis.
  • Renderer-tilkobling mistet midt i økten.
  • Enhver annen tilstand der "skjedde én gang, brukeren bør vite" slår "logget stille blant 1000 andre linjer".

Implementeringskonvensjoner:

  • Merkebeskrivelser lever på dialognivå (ikke inne i noe panel) slik at de er synlige uavhengig av hvilken seksjon brukeren er på.
  • Plassert langs nederste rad nær Lagre/Avbryt (nåværende: y=410 horisontalt stablet).
  • Hvert merke har et tilsvarende klebrig sesjonsflagg i Plugin som blir Sann når tilstanden oppstår og tilbakestilles bare ved MusicBee-omstart.
  • Ressurser: <Condition>Badge (etiketttekst, prefiks med ⚠) + <Condition>BadgeTip (verktøytips som forklarer årsak + løsning).
  • For "lagret innstilling krever omstart"-merker, ta et kjøretidsøyeblikksbilde ved Plugin.Initialise() og sammenlign med Settings.* etter Settings.SaveSettings() i dialogens Lagre-håndterer.

N27 - Avbryt forkaster sti-/malredigeringer

Hva: redigeringer gjort på stier og maler i innstillingsdialogen blir nå forkastet når brukeren klikker Avbryt, i stedet for å stille forbli anvendt, og eventuelle reserverte maler som ble fjernet under økten, blir gjenopprettet. (Maler lagres ellers live mens de redigeres – det er ingen egen Lagre-knapp på Stier-fanen.)

Hvorfor: Avbryt skal bety avbryt. Tidligere fant en bruker som eksperimenterte med sti-/malendringer og trakk seg tilbake, at endringene allerede var utført, uten mulighet til å angre dem annet enn å gjøre hver enkelt manuelt.


N28 - Bokstavelige ampersander i feltvelger-menyen

Hva: et felt hvis navn inneholder "&" – f.eks. "Stemning & Kontekst" – gjengir ampersanden bokstavelig i feltvelger-menyen i stedet for å svelge den som et Alt-mnemonisk prefiks.

Hvorfor: feltnavn med en ampersand ble vist feil (tegnet forsvant og neste bokstav ble en akselerator), noe som gjorde menyoppføringen vanskelig å gjenkjenne.


N29 - Stabil, uoversatt innstillingsvindutittel

Hva: innstillingsvinduets tittel er fastsatt til merkevarestrengen "MusicBee UPnP Plugin" og varierer ikke lenger med grensesnittspråket; den språkspesifikke DialogTitle-strengen ble fjernet fra alle lokaliseringspakker.

Hvorfor: en vindutittel som endret ordlyd per språk var en oversettbar overflate uten fordeler – tittelen er et varemerke. Å feste den holder den stabil og konsekvent overalt.

Lokalisering

Den originale plugin-modulen er kun på engelsk. Denne forken er fullt lokaliserbar – hver brukerrettede streng flyter gjennom en ressursbunt, og plugin-modulen oppdager automatisk MusicBees eget UI-språk.

N30 - Flerspråklig UI (oversettelser venter)

Hva: lokaliseringsmekanismen er komplett og sendes ut. Localisation.vb leser MusicBees valgte språk fra MusicBee3Settings.ini (<SystemLanguage> endonym) og bruker den matchende .NET-kulturen på tråden, slik at My.Resources.Resources.* returnerer den lokaliserte strengen. Hver brukerrettede etikett/knapp/melding er koblet til en ressursnøkkel (designer-kontroller via ApplyDesignerExtras + sync-en-locale.js; kjøretidsstrenger som WarnPortInUse manuelt lagt til). Det som ikke er gjort ennå, er den faktiske oversettelsen: bare den engelske kildebunten (Resources.resx) eksisterer – satellittbunter for de andre språkene produseres i en enkelt batch når plugin-modulen er funksjonskomplett (å oversette stykkevis mens strenger fortsatt endres, er bortkastet arbeid).

Målspråk (settet MusicBee selv tilbyr, matchet 1:1 av endonymToCulture slik at plugin-modulen følger MusicBees språk automatisk):

Arabisk (ar) Tsjekkisk (cs) Tysk (de) Gresk (el)
Spansk (es) Fransk (fr) Ungarsk (hu) Italiensk (it)
Koreansk (ko) Nederlandsk (nl) Norsk (nb) Polsk (pl)
Portugisisk BR (pt-BR) Portugisisk PT (pt-PT) Svensk (sv) Tyrkisk (tr)
Ukrainsk (uk) Russisk (ru) Japansk (ja) Forenklet kinesisk (zh-CN)
Tradisjonell kinesisk (zh-TW) Engelsk (en, kilde)

Variantpolicy (i henhold til arbeidsområdets lokaliseringsregel): PT og ZH er delt inn i distinkte bunter fordi vokabular/skript genuint avviker (pt-BR/pt-PT, zh-CN/zh-TW). EN er en enkelt bunt – MusicBees "English(US)" (en-US) faller tilbake til en via .NETs kulturkjede, så ingen separat US-bunt produseres. ES og FR er likeledes enkelt-lokale.

Hvorfor: innstillingene for en UPnP-plugin ("ikke bruk rå PCM", "tving little-endian PCM", port-tilbakekoblingsadvarsler) er kryptiske nok på ens morsmål. Å følge MusicBees eget UI-språk – i stedet for å tvinge engelsk – er forskjellen mellom et verktøy en ikke-engelsk bruker kan konfigurere og et de ikke kan. Ingen av oppstrøms forsøkte dette.


N31 - Hjelpelink åpnes i fullt grensesnittspråk

Hva: å åpne Hjelp-lenken fra plugin-modulen respekterer brukerens komplette grensesnittspråk (f.eks. pt-BR, zh-CN) i stedet for å kollapse til grunnleggende språk, og sender en tydeligere oppdateringskontrollidentifikator.

Hvorfor: en bruker som kjører MusicBee i en regional variant (brasiliansk portugisisk, forenklet kinesisk) ble sendt til hjelpesiden for grunnleggende språk. Å bære hele kulturen lander dem på hjelpesiden i nøyaktig det språket de bruker.

Feilrettinger og forbedringer av den originale plugin-modulen

Kjerneprotokoll og avspilling

F01 - Oppdaterte standard DLNA-enhetsprofiler

Hva: leverer nye standardprofiler for PlayStation 4, Xbox 360/One og moderne BubbleUPnP, med kapasitetsflagg (samplingsfrekvenser, bitdybder, kodeker) som gjenspeiler hva disse enhetene faktisk støtter i dag.

Hvorfor: den originale plugin-modulens standardinnstillinger var frosset rundt 2014. PS4/Xbox/BubbleUPnP har siden fått støtte for høyoppløselig lyd. Ut av esken spiller en ny installasjon best i klassen på disse enhetene uten at brukeren trenger å endre enhetsprofilinnstillingene.


F02 - Kontroller enheter som annonserer MediaRenderer:3

Hva: plugin-modulen undersøker en renderers UPnP-tjenestebeskrivelse for å avgjøre om MusicBee kan drive den. Originalen matchet bare urn:schemas-upnp-org:device:MediaRenderer:1. Moderne enheter annonserer :2 eller :3. F02 utvider matchen.

Hvorfor: uten dette vises nyere Sonos / WiiM / Eversolo-enheter rett og slett ikke som mål i MusicBees "Spill til"-enhetsliste – selv om de snakker samme protokoll. En enkel streng-prefiks-match-fikser låser opp hele den moderne enhetsgenerasjonen.


F03 - "Tving native stream" per-profil-alternativ (standard PÅ)

Hva: når avkrysset, sender plugin-modulen de originale filbytene til enheten med ingen transkoding, ingen DSP, ingen ReplayGain-behandling anvendt. Bare den rå filen brukeren valgte, byte for byte (modulo HTTP-innramming).

Hvorfor: ifølge forumvitnesbyrd er dette den største enkeltstående forbedringen i avspillingskvalitet. Hi-fi-brukere som kjøper dyre renderere ønsker eksplisitt bit-perfekt utdata; enhver DSP-berøring ødelegger poenget. Standard PÅ fordi de fleste moderne enheter håndterer hvilken som helst kodek brukeren kastet på dem, og ReplayGain/EQ bør være opt-in. Det er per-profil slik at du kan beholde transkoding for en gammel Xbox mens du sender native til en hi-fi DAC.


F04 - "Tving transkoding" per-profil

Hva: per-profil overstyring som tvinger hver strøm til denne enheten gjennom transkoderen, uavhengig av native-kodekstøtte. Det motsatte av F03 (ForceNativeStream). Gjensidig eksklusiv med F03 – UI-en fjerner automatisk avkryssingen for den andre når en av dem er slått på.

Hvorfor: en enkelt global veksling ville være motstridende med per-profil ForceNativeStream (F03). Virkelig tilfelle: enhet A er en hi-fi DAC som ønsker bit-perfekte native strømmer; enhet B er en gammel AV-mottaker som kveles av FLAC. Med en global veksling må brukeren velge – på bekostning av den andre enheten. Med per-profil får hver enhet riktig svar.

Implementering:

  • StreamingProfile.ForceTranscoding As Boolean = False.
  • Vedvarende skjema økt til v9. Filer før v9 laster den eldre globale verdien én gang og kopierer den inn i alle profiler, og bevarer den gamle atferden gjennom oppgraderingen.
  • UI: fjernet fra Diagnostikk-panelet, lagt til i Enhetsprofiler-seksjonen ved siden av ForceNativeStream. To-veis gjensidig eksklusjonsbehandlere (CheckedChanged på hver avmelder den andre før den veksler, for å unngå en uendelig løkke).
  • Beslutningssted: Settings.ForceTranscodingstreamingProfile.ForceTranscoding i WriteAudioFileDIDL.

F05 - "Tving little-endian PCM" per-profil

Hva: PCM-strømmer (L16/L24 mime-typer) er big-endian i henhold til spesifikasjonen. Noen enheter forventer feilaktig little-endian og spiller av hvit støy når de får riktige big-endian-data. F05 veksler byte-rekkefølgen per-profil.

Hvorfor: uten dette produserer visse enheter en vegg av statisk støy. Symptomet er dramatisk og årsaken usynlig uten kunnskap om PCM-koding – vekslingen gir brukerne en gjett-og-sjekk-fiks.


F06 - "Ikke bruk rå PCM" per-profil

Hva: når enheten hevder den støtter rå PCM, bruker plugin-modulen det. Noen enheter lyver – de aksepterer SOAP-håndtrykket, men forvrenger faktiske rå PCM-data, mens de håndterer PCM pakket i en WAVE-beholder riktig. F06 tvinger PCM-over-Wave uavhengig av hva enheten annonserer.

Hvorfor: spesifikt visse Marantz-modeller – de annonserer rå PCM, men bare WAVE fungerer. Uten dette kommer rå PCM-strømmer ut forvrengt, uten feilmelding som peker på årsaken.


F07 - "Innholdslengde" per-profil

Hva: hvilken verdi som skal sendes i HTTP Content-Length-headeren. Fire alternativer:

  • Standard - faktisk byte-antall når kjent, utelat når ukjent.
  • Ingen - send aldri headeren (kun chunked encoding).
  • Kun PCM - send kun for rå PCM; utelat for alt annet.
  • Fast - send UInt32.MaxValue - 8192 (en markør for "veldig stor ukjent lengde").

Hvorfor: UPnP/DLNA-enheter varierer vilt i hvordan de reagerer på Content-Length. Noen trenger et eksakt tall, noen hater det på strømmer, noen trenger en markør "veldig stor" verdi for å fortsette buffering. Dette ble senere utvidet fra kun PCM til alle utdataformater fordi de samme problemene dukket opp i transkodede MP3/AAC-strømmer.


F08 - "Ikke tøm NextURI" per-profil

Hva: normalt tømmer plugin-modulen enhetens køede NextURI når køen tømmes (sender SetNextAVTransportURI med en tom URL). Noen enheter (spesielt Denon) tolker en tom NextURI som "stopp alt" og stopper avspillingen umiddelbart. F08 forhindrer plugin-modulen fra å tømme den.

Hvorfor: uten dette opplever Denon-eiere at enheten kutter av midt i sporet når køen tømmes. Med F08 avkrysset beholder enheten den utdaterte NextURI i minnet (ufarlig – den blir bare overskrevet neste gang noe blir køet).


F09 - FLAC som transkode-utdataformat

Hva: nedtrekksmenyen for transkodeformat i Enhetsprofiler tilbyr nå FLAC sammen med PCM 16/24, MP3, AAC, Ogg. Å velge det ruter BASS-koderen gjennom MusicBees standard FLAC-konverteringskommandolinje (samme mekanisme som MP3/AAC/Ogg allerede bruker).

Hvorfor: for enheter som håndterer FLAC godt, men ikke kan dekode kildekodeken (f.eks. en Eversolo som mottar MusicBees WMA-bibliotek konvertert til FLAC), bevarer dette tapsfri kvalitet der MP3/AAC ville kastet bort lyddata. Blokkerer N02 (5.1 nedmikskontroll), som ikke kunne adresseres uten et tapsfritt transkodealternativ.

Implementering: én-linjes tillegg til Encoder.StartEncodes Select Case Codec-blokk – FLAC slutter seg til MP3/AAC/Ogg i den kommandolinjedrevne grenen. UI-nedtrekksmenyen får "FLAC" som et 6. alternativ. Last/lagre-mapping i SettingsDialog utvides til å gjenkjenne FileCodec.FlacSelectedIndex = 5. Mime, DLNA-type og encode-funksjon var allerede koblet i ItemManager.GetMimes / GetDlnaType / GetEncodeFeature fra tidligere arbeid (F21, F26).


Gapless (SetNextAVTransportURI)

F10 - SetNextAVTransportURI / NextURI kjerne

Hva: ekte gapless avspilling. Når enheten annonserer støtte for SetNextAVTransportURI i sin UPnP-tjenestebeskrivelse, forhåndskøer plugin-modulen neste spor på enheten før det nåværende sporet slutter. Enheten overgår internt uten hørbar pause mellom sporene – det du hører på en CD-spiller. Dette er ikke "kontinuerlig strøm"-hacken (som sammenføyer alt til én lang strøm og mister metadata per spor).

Hvorfor: flaggskipets Tier-2-funksjon. Album innspilt som en kontinuerlig liveopptreden (liveplater, klassiske satser, DJ-sett) høres feil ut når det er en halv sekunds stillhet mellom sporene. Å løse dette ordentlig er en flaggskipfunksjon, nå i denne forken.

Merknader: den køede lyden serveres via plugin-modulens HTTP-server ved hjelp av streamHandle=0 (bibliotek-hentemodus), noe som betyr at MusicBees lydmotor ikke er med i loopen for det køede sporet. Kompromiss: ReplayGain/DSP/EQ-effekter gjelder ikke for neste spor. Akseptabelt når "tving native stream" er på (standard).


F11 - "Deaktiver NextURI-støtte" per-profil

Hva: selv om en enhet annonserer SetNextAVTransportURI, tvinger denne avkrysningsboksen plugin-modulen til å ignorere den annonseringen og falle tilbake til avspilling ett spor om gangen.

Hvorfor: noen enheter annonserer NextURI, men har en buggy implementasjon (krasjer, halvoverganger, henger). I stedet for å reversere hver ødelagte enhet, får brukeren en "bare slå den av her"-veksling.


F12 - NextURI livssyklus på nå-spiller-listen

Hva: når MusicBee utløser NowPlayingListChanged, evaluerer plugin-modulen på nytt hva som skal køes for gapless overgang. Den ber MusicBee om det nye "neste" sporet via NowPlayingList_GetNextIndex(1) + NowPlayingList_GetListFileUrl, sammenligner med det som er køet på enheten (sporet via det nye nextPlaySourceUrl-feltet), og køer på nytt hvis det endret seg (eller tømmer køen hvis MusicBee sier det ikke er noe neste spor).

Hvorfor: uten F12 fortsatte enheten å spille en utdatert NextURI når brukeren fjernet/omorganiserte det køede sporet. Dette tok historisk sett flere iterasjoner fordi hver liste-mutasjon trenger forskjellig håndtering – vi forenklet ved å stole på NowPlayingList_GetNextIndex (som allerede respekterer shuffle og repeat-all wrap-around), så alle varianter kanaliseres gjennom den samme sammenligningen.

Implementering:

  • Nytt nextPlaySourceUrl-felt lagrer MusicBee-bibliotek-URL-en til det som er køet (strømme-URL-en med håndtakssuffiks kan ikke sammenlignes med en biblioteksti).
  • Ny Public Sub RefreshQueuedNextUri()MediaRendererDevice. Tre utfall: ingen NextURI køet → ingen operasjon; køet samsvarer med ny "neste" → ingen operasjon; køet avviker → kall QueueNext med den nye URL-en (eller QueueNext("") for å tømme – som respekterer F08 DoNotClearNextUri).
  • Koblet i Plugin.ReceiveNotification under NotificationType.NowPlayingListChanged.

F13 - NextURI feil tilbakekobling

Hva: etter 4 påfølgende SetNextAVTransportURI-feil på samme enhet, deaktiverer plugin-modulen gapless for den enheten til MusicBee starter på nytt.

Hvorfor: hvis en enhet er genuint ødelagt for NextURI (intermitterende SOAP-feil, nettverksfeil), ville plugin-modulen ellers fortsette å prøve på nytt for hvert spor. F13 stopper støyen og faller tilbake til ett-spor-om-gangen stille.


F14 - Gjenta-modus + NextURI-integrasjon

Hva: F14 deles i to tilfeller som håndteres ved F15-overgangsdetektoren i OnAvTransportStatusCheck:

  • Gjenta alle: MusicBee sender den korrekte "wrap"-URL-en (spor 1 ved slutten av listen) til Plugin.QueueNext selv. Ingen spesiell plugin-logikk er nødvendig – enheten overgår til den, og F15-detektoren kaller Player_PlayNextTrack som vanlig, som pakker MusicBees NPL-indeks tilbake til 0.
  • Gjenta én: MusicBee sender den SAMME spor-URL-en til Plugin.QueueNext. Enheten overgår til den (ny strømhåndtak, samme kilde). F15-detektoren spør nå Player_GetRepeat() – hvis det er RepeatMode.One, hopper den over Player_PlayNextTrack-kallet slik at MusicBee ikke flytter NPL-indeksen bort fra det loppende sporet.

Hvorfor: uten Repeat-One-hoppet ville kall av Player_PlayNextTrack ved gapless overgang flytte MusicBee til neste spor i listen (Repeat-One påvirker bare automatisk fremføring ved slutten av sporet i avspillerens UI – Neste spor beveger seg alltid fremover), noe som motsier hva Repeat-One betyr.

Spilleantall-forbehold: i Repeat-One avhenger økningen i spilleantall av at MusicBee 3.7.9563+ merker den loppende avspillingen. Eldre MusicBee-versjoner spiller den gapless gjentakelsen korrekt, men går glipp av økningen i spilleantall. Dokumentert; ikke blokkerende.


F15 - Sporovergangsdeteksjons-tilstandsmaskin

Hva: når enheten internt overgår fra gjeldende spor til NextURI, må plugin-modulen merke det og fortelle MusicBee å flytte sin nåværende avspillingsindeks. Ellers tror MusicBee at den fortsatt er på forrige spor, og avspillingsantall / UI / scrobbling driver ut av synkronisering.

Implementering: spør GetPositionInfo.TrackURI ved hver status-timer-tick. Når den rapporterte URI-en samsvarer med den vi køet via NextURI, kaller vi Player_PlayNextTrack på MusicBee og setter suppressNextSoapCall slik at den resulterende PlayToDevice ikke sender SetAVTransportURI på nytt (noe som ville avbryte den gapless avspillingen).

Hvorfor: uten F15 spiller enheten neste spor, men MusicBees UI sier at den fortsatt er på forrige. Forvirrende, bryter scrobbling, bryter sporing av avspillingsantall. Sporovergangsdeteksjon krever lang, per-renderer-iterasjon fordi hvert renderer-merke har sine egne særegenheter i når det rapporterer URI-endringen (noen rapporterer TRANSITIONING først, noen hopper rett til PLAYING med ny URI, noen har en kort STOPPED imellom).

Merknader: vårt første utkast fungerer på BubbleUPnP-renderer. Per-enhet-kanttilfeller forblir i B6.


F16 - Pop-on-gapless-overgangsretting

Hva: poppen skjer når kildeformatet (samplingsfrekvens / kanaler / kodek) for det køede sporet avviker fra det som spilles av, noe som tvinger enhetens DAC til å låse seg på nytt ved overgangen. F16 legger til en NextUri:FormatChange-diagnostikk som utløses ved køtid når formatene avviker, og navngir begge sider – slik at brukere som hører popper kan korrelere.

Diagnostikken peker også på løsningen: kryss av Tving transkoding på enhetsprofilen. Det homogeniserer hvert spor til en enkelt transkodekodek/samplingsfrekvens/bitdybde, og eliminerer kildeformatforskjellen helt.

Hvorfor utsatt for den faktiske transkode-til-match-rettingen: den strukturelle rettingen (transkode det køede sporet for å matche det spillende sporet sitt format) krever endringer i plugin-modulens HTTP-server-URL-skjema – for øyeblikket serverer /encode/{id}0.{ext} den køede filen nativt. En fremtidig v2 av F16 ville legge til per-format /encode/{id}0_{rate}_{depth}.{ext}-ruter og koble dem gjennom koderen. Det er en større arkitektonisk endring verdt å gjøre hvis en ekte enhet viser poppen etter at ForceTranscoding ikke er tilstrekkelig.

Implementering i dag:

  • lastSourceUrl-feltet sporer den nåværende spillende kilde-URL-en.
  • QueueNext leser FilePropertyType.SampleRate/Channels/Kind for både de nåværende og køede sporene og logger NextUri:FormatChange ved uoverensstemmelse.

F17 - Fremdriftslinje resynkronisering etter søk

Hva: Seek()-funksjonen kalte allerede GetPlayPositionInformation() etter en vellykket Seek SOAP, noe som fikser "ingen resynkronisering i det hele tatt"-tilfellet. F17 lukker den gjenværende opptil 1s drift forårsaket av UPnPs 1-sekunds RelTime-kvantisering: når enhetens rapporterte posisjon avrundes til innenfor 1 sekund av brukerens forespurte mål, stoler plugin-modulen nå på brukerens sub-sekund-nøyaktige verdi i stedet for enhetens avkorting. Bare når enheten rapporterer noe dramatisk annerledes (>1s avvik) bruker vi dens verdi (søket landet et annet sted enn spurt, f.g. snap-to-keyframe på noen kodeker).

Hvorfor: uten dette ville søk til 2:30.500 forankret mot enhetens "2:30"-rapport få fremdriftslinjen til å vise ~500ms bak virkeligheten. Etter F17 samsvarer linjen med brukerens intensjon for det vanlige in-track-skrubbetilfellet, og respekterer fortsatt enhetens rapport for snap-to-keyframe-utliggeren.


F18 - Kontinuerlig strøm / NextURI-sperre

Hva: to sperrer er nå på plass:

  1. Kjøretid: QueueNext returnerer tidlig False når Settings.ContinuousOutput er på. Kontinuerlig strøm er sin egen gapless mekanisme (én lang sammenkoblet strøm); å sende SetNextAVTransportURI på toppen av det forvirrer enheten om hvorvidt hvert spor er en diskret URI eller en del av den kontinuerlige flyten.
  2. UI: når brukeren krysser av den globale kontinuerlig-strøm-avmerkingsboksen, fjernes automatisk avkryssingen for den nåværende viste profilens forceNativeStream. Kontinuerlig strøm transkoder alltid, så force-native er meningsløst i kombinasjon.

Hvorfor: forhindrer brukeren fra å aktivere to motstridende gapless mekanismer samtidig. Uten F18 ville enheten motta både en kontinuerlig strøm-URI OG en NextURI for hvert påfølgende spor, med udefinert atferd avhengig av rendereren.


F19 - Tomme NextURI-feil ignoreres

Hva: når SetNextAVTransportURI kalles med en tom URL (f.eks. siste spor i listen), returnerer noen enheter en SOAP-feil. F19 svelger disse stille – logges, men propageres ikke som feil.

Hvorfor: "ingen neste spor"-tilstanden er normal, ikke en feil. Å behandle den som fatal forurenser loggen og (i noen flyter) utløser gjentatte feil.


Mime-typer og DLNA-metadata

F20 - MP3 mime → audio/mpeg

Hva: den standardkonforme MP3 mime-typen er audio/mpeg, ikke audio/mp3. Sistnevnte er en vanlig feilbetegnelse de fleste enheter tolererer, men strengere renderere avviser den.

Hvorfor: fikser stille avspilling på strengere enheter som følger standarden. Yaiol-kodebasen hadde dette allerede korrekt; ingen endring nødvendig.


F21 - Mime-type rekkefølge: ikke-x- variant først

Hva: når en enhet annonserer både audio/flac og audio/x-flac, returnerer plugin-modulen den ikke-x- varianten først. Samme for enhver kodek med både standard og eksperimentelle mimer.

Hvorfor: x--prefikset markerer eksperimentelle/uoffisielle mimer. Noen renderere oppfører seg bedre med standardformen. Liten omorganisering, reell innvirkning.


F22 - Opus mime-type støtte

Hva: gjenkjenner Opus som en strømbar lydkodek; sender audio/opus mime når den serverer Opus-spor.

Hvorfor: Opus er nå vanlig (moderne kompromisskodek for tale/musikk). Uten F22 ville plugin-modulen nekte å strømme Opus-filer selv til enheter som håndterer dem.


F23 - Monkey Audio (APE) kilde filstøtte

Hva: gjenkjenner .ape-filer som en gyldig kildekodek for strømming/transkoding.

Hvorfor: APE er et tapsfritt format med en nisje, men lojal brukerbase. Å legge det til koster lite og låser opp biblioteket for disse brukerne.


F24 - AAC / ALAC mime tilbakefall

Hva: hvis en enhet støtter AAC eller ALAC, men ikke eksplisitt annonserer dem i sin UPnP-tjenestebeskrivelse, tilbyr plugin-modulen dem likevel som et tilbakefall.

Hvorfor: flere enheter som håndterer AAC fint, glemte å liste det i sin kapasitets-XML. Uten F24 vil plugin-modulen ikke engang prøve, og tvinger transkoding. Med F24 prøver plugin-modulen og lar enheten håndtere det nativt hvis den kan.


F25 - DLNA typeflagg for native + kodede WAV-strømmer

Hva: DLNA-typeflagget (en profilidentifikator som LPCM, WAVE, MP3) må samsvare med det enheten mottar. F25 sikrer at native strømmer og kodede WAV-strømmer flagges korrekt.

Hvorfor: feil DLNA-type fører til at noen enheter nekter avspilling helt eller bruker feil dekoder.


F26 - DLNA-header for FLAC-filer

Hva: FLAC-strømmer får riktig DLNA-profilidentifikator i sine headere.

Hvorfor: uten det gjenkjenner ikke noen enheter som støtter FLAC strømmen som sådan.


F27 - Bitrateberegningsfeil i metadata

Hva: den kontinuerlige strømmens res@bitrate ble beregnet som (sampleRate * channels * bitsPerSample) / 1000 – kbps, avvikende med en faktor på ~125 fra UPnP DIDL-spesifikasjonen som definerer attributtet som bytes per sekund. Deler nå med 8 i stedet for 1000.

Hvorfor: feil bitratevisning på enheten – kosmetisk på de fleste renderere, men noen allokerer strømmebuffere fra verdien og hakker på strømmer som ser ~125× mindre ut enn de er. Den ikke-kontinuerlige kilde-filstien hadde dette allerede riktig ((bitrate_kbps * 1000) \ 8 = bytes/sek); bare den kontinuerlige strøm-stien var feil.


F28 - Metadata tidsformat fikser (Marantz)

Hva: res@duration i DIDL var formatert som H:MM:SS (f.eks. 0:03:42). UPnP DIDL-spesifikasjonen definerer formatet som H+:MM:SS[.F+] – strengt tatt med brøksekunder valgfritt, men anbefalt; noen Marantz-enheter behandler den bare formen som ugyldig og lar varighetsvisningen være tom. Nå formatert som H:MM:SS.fff (f.eks. 0:03:42.000).

Hvorfor: visningsproblem spesifikt for et merke; konform ISO-stilformat med brøksekunder fikser det uten å påvirke andre enheter. Anvendt på begge DIDL-utslippssteder (kilde-filsti + kodet-strømsti i WriteAudioFileDIDL).

Bonusfiks i samme pass: pv:addedTime og pv:lastPlayedTime brukte hh (12-timers klokke) i sine DateTime-formatstrenger i stedet for HH (24-timers). Ethvert spor lagt til eller spilt mellom 13:00 og 23:59 ville gjengis med en feil time (f.eks. 17:42 → "05:42") på enheter som viser feltet. Bruker nå HH.


F29 - Kodet MP3 søkestøtte (CBR)

Hva: transkodede MP3-strømmer annonserer nå DLNA.ORG_OP=11 (både byte- og tidsøk) i stedet for DLNA.ORG_OP=10 (kun byte). Enheter som tidligere nektet tidsøk på transkodede MP3 kan nå drive fremdriftslinjen/søk-UI-en normalt.

Hvorfor: MusicBees transkoder produserer konstant-bitrate MP3 ved HighQuality-forhåndsinnstillingen, så byte ↔ tidsmapping er lineær – enheten kan konvertere en tidsøk-forespørsel til en HTTP Range byte-øk selv uten noen koder-side-støtte. Annonsering av OP=11 låser opp den UI-en på enheten. Uten F29 ble brukere som søkte i en transkodet MP3 enten søket stille ignorert eller de ble droppet til sporstart.

Implementering: omstrukturert GetEncodeFeature i ItemManager.vb for å bryte den inline If til en lesbar If/ElseIf/Else-kjede. MP3 får OP=11 eksplisitt; andre ikke-PCM-kodeker beholder OP=10. Ingen endring for AAC/FLAC/etc. – disse ville trenge kodek-spesifikk verifisering av CBR-het som MusicBee ikke garanterer.


F30 - .mpeg-filutvidelse håndteres

Hva: filer med .mpeg (og den enda sjeldnere .mpe) utvidelsen gjenkjennes nå som FileCodec.Mp3 i GetCodec. Før F30 returnerte de FileCodec.Unknown og ble stille avvist fra biblioteket / ute av stand til å være transkodekilder.

Hvorfor: gamle MPEG-1 Layer 3-arkiver brukte noen ganger .mpeg i stedet for .mp3 (spesifikasjonen tillater begge). En håndfull filer i et 300k-bibliotek er nok til å føle "MusicBee viser dem, men plugin-modulen gjør det ikke" – forvirrende for brukeren.


Avspillingsatferd

F31 - Radiostrømmer bruker automatisk kontinuerlig modus

Hva: WriteAudioFileDIDL undersøker nå kilde-URL-ens Kind-egenskap via Library_GetFileProperty og behandler enhver fil hvis Kind slutter med "Stream" (MusicBee rapporterer "MP3 Stream", "Internet Stream", etc. for radio) som kontinuerlig uavhengig av den globale Settings.ContinuousOutput-vekslingen. Den kontinuerlige strøm-DIDL-grenen (Tittel: "Kontinuerlig strøm", id="continuousstream", fast PCM/Wave-utgang) brukes; enheten ser en enkelt uendelig-stil strøm.

Hvorfor: radiostrømmer har ingen sporgrenser, ingen fast lengde, ingen søk. Å behandle dem som diskrete filer i DIDL førte til at plugin-modulen annonserte byte-områder og varigheter som ikke eksisterer. Automatisk veksling når MusicBee allerede fortalte oss "dette er en strøm" fjerner en fot-pistol brukeren ikke burde måtte tenke på.

Omfang: gjelder kun når MusicBee driver avspilling (musicBeePlayToMode). Bibliotek-hentestien (UPnP-klient som blar) er uendret – radio-URL-er der er sjeldne, og brukerrettet atferd bør ikke endres uten eksplisitt testing.


F32 - Kodek-annonserings-tilbakefall

Hva: hvis en enhet ikke annonserer visse kodeker (eller plugin-modulen ikke kan parse enhetens kapasitets-XML), avviser plugin-modulen ikke strømmen umiddelbart. I stedet prøver den å servere den og lar enheten bestemme.

Hvorfor: mange enheter har ufullstendig eller uleselig kapasitets-XML, men håndterer faktisk kodeken fint. F32 bytter en liten "best-gjetning og prøv" mot et direkte avslag.


F33 - Forbedring av fremdriftslinjesynkronisering

Hva: posisjonen mellom avstemningene er allerede veggklokke-ekstrapolert fra et enkelt anker (currentPlayStartTicks), slik at fremdriftslinjen oppdateres jevnt med sub-sekund hastighet. Den gjenværende jitterkilden var det initiale ankeret for et nystartet spor: den forrige koden antok position=0 i det øyeblikket status-timeren først merket at tilstanden gikk til Playing, men da kan enheten ha spilt i 100-500ms (ett avstemningsintervall). MusicBees fremdriftslinje ville starte på 0, deretter hoppe fremover når virkeligheten tok igjen.

F33-fiks: når du går over til Playing for første gang på et nytt spor (currentPlayStartTimeEstimated=True), kall GetPlayPositionInformation() for å få enhetens faktiske nåværende posisjon, og anker deretter mot det. UPnP rapporterer bare 1-sekunds oppløsning, så ankeret er fortsatt kvantisert, men det er mye nærmere sannheten enn å anta 0.

Hvorfor: jevnere + mer nøyaktig fremdriftsvisning, spesielt rett etter sporbytte. Ingen vei utenom 1-sekunds UPnP-rapporteringsoppløsningen i seg selv – det er spesifikasjon.


F34 - Fremdriftslinje-jitter etter sporbytte

Hva: når PlayToDevice kalles for et nytt spor, pleide plugin-modulen å la currentPlayPositionMs og currentPlayStartTicks stå på sine forrige-spor-verdier i ~100ms-vinduet mellom SOAP-Play og den første status-timer-avstemningen som oppdaget den nye Playing-tilstanden. MusicBees fremdriftslinje ville kort vise slutten av forrige spor, deretter hoppe tilbake til 0, deretter klatre. F34 nullstiller begge ved PlayToDevice-inngang – i det øyeblikket vi vet at et sporbytte skjer, før noe av SOAP-arbeidet.

Hvorfor: visuell feil ved raske hopp-brukstilfeller (manuell neste eller gapless overgang). Nå returnerer MusicBees første PlayPositionMs-spørring etter Play rent 0, deretter forbedrer F33s GetPlayPositionInformation det til enhetens faktiske posisjon ved første tilstandsendringstikk.

Implementering: fire linjer øverst i PlayToDevice, sammenkoblet med F33s overgangstid nøyaktig forankring.


F35 - "Tving transkoding"-feil

Hva: tvungen transkoding kunne fortsatt hoppe over transkoding i visse kombinasjoner. Etter F04 per-profil-omarbeidelsen ble to spesifikke hull forseglet:

  1. Prioritet med ForceNativeStream. Når begge var Sann (noe som kan skje over en skjema-migrering eller en delvis innstillingsfil), vinner ForceTranscoding nå direkte (If streamingProfile.ForceTranscoding Then forceEncode = True ElseIf streamingProfile.ForceNativeStream Then forceEncode = False). UI gjensidig eksklusjon forhindrer brukeren fra å krysse av begge, men kjøretidsvakten håndterer enhver tilstand som ble lastet inkonsekvent fra disk.
  2. bypassTranscodeDecision-logikk. Tidligere: streamingProfile.ForceNativeStream AndAlso Not Settings.ForceTranscoding. Nå: streamingProfile.ForceNativeStream AndAlso Not streamingProfile.ForceTranscoding – samme prioritet, men på samme per-profil-omfang.

Hvorfor: "tving" skal bety tving. Hvis brukeren eksplisitt aktiverte ForceTranscoding for en enhet, må plugin-modulen aldri stille falle gjennom til native strømming, uavhengig av hvordan andre flagg tilfeldigvis kombineres.


F36 - Renderer-lukket unntak

Hva: pakket Plugin.ReceiveNotification inn i en toppnivå Try/Catch som logger eventuelle ufangete unntak i stedet for å la det spre seg tilbake til MusicBees varslingspumpe.

Hvorfor: varsler fra MusicBee (PlayStateChanged, VolumeMuteChanged, etc.) sendes til ControlPointManager som kommuniserer med rendereren over SOAP. Individuelle kallesteder hadde allerede Try/Catch rundt sine SOAP-kall, men et tilstrekkelig merkelig tidstilfelle (f.eks. renderer dør mellom to SOAP-kall i samme varslingshåndterer) kunne fortsatt unnslippe. Toppnivå-wrapperen er det endelige sikkerhetsnettet slik at brukeren aldri ser en generisk "TargetInvocationException"-popup fra MusicBee.

Implementering: omdøpte den eksisterende kroppen til ReceiveNotificationInternal og la til en tynn wrapper ReceiveNotification som gjør Try { ReceiveNotificationInternal(...) } Catch { LogError(...) }. Den eksisterende per-metode Try/Catch-infrastrukturen inne i ControlPointManager (rundt hvert PostSoapRequest-kall) forblir – F36 er belte + bukseseler.


F37 - Lang-spor-søk utløser falsk overgang

Hva: søk i et langt spor kan produsere en kort Stopped→Playing-syklus på noen renderere. Uten diskriminering behandler ProcessNewPlayState.Stopped det som naturlig-slutt-på-spor og kaller Player_PlayNextTrack, og flytter MusicBee fremover når brukeren bare ville skrubbe. F37 stempler lastUserInitiatedSeek i Seek() og legger til en 5-sekunders vakt i Stopped-håndtereren (speiler det eksisterende lastUserInitiatedStop-vinduet).

Hvorfor: stille hopp-til-neste-spor under et søk er en av de feilene ingen kan gjette årsaken til – brukeren tenker "rart, jeg prøvde å skrubbe fremover og nå spiller den neste sang". Fiksen er mekanisk: samme mønster som bruker-stopp-diskrimineringen som allerede er på plass.


F38 - Forbedret søkehåndtering for krasjutsatte kodeker

Hva: BubbleUPnP som krasjet ved MP3-søk var det kanoniske symptomet. Etter revisjon gjør den nåværende yaiol-søkekoden allerede de riktige tingene – native sti håndterer HTTP Range korrekt (206, Content-Range, AcceptRanges), kodet sti annonserer X-AvailableSeekRange og parser innkommende timeSeekRange.dlna.org / npt-headere, DLNA.ORG_OP-flagg gjenspeiler de faktiske strømkapasitetene (med DisablePcmTimeSeek opt-out for problematiske Platinum-enheter). Brukertestet på nåværende BubbleUPnP 4.6.4: ingen krasj observert.

Hvorfor: BubbleUPnP MP3-søk-krasjen ble rapportert rundt 2024, og appen har hatt ~16 måneder med fikser siden. F29 (kodet MP3 OP=11) var den nye variabelen som kunne ha re-eksponert den; gjør det ikke, på testede versjoner.

Hvis et krasj returnerer: fiks-formen ville være en per-profil "begrenset søk"-veksling som tvinger DLNA.ORG_OP=10 (kun byte) på flaggede kodeker – speiler hvordan DisablePcmTimeSeek allerede fungerer for PCM. Legg til da, ikke forebyggende.


UI og logging

F39 - "Legg til"-knappen velger den nye profilen

Hva: å klikke "Legg til" i enhetsprofil-listen oppretter en ny profil OG velger den automatisk slik at brukeren umiddelbart kan redigere felt. Vår seksjonerte dialog-refaktorering gjør allerede dette – både den direkte-Legg til-stien og fra-mal-stien slutter med Me.activeStreamingProfiles.SelectedIndex = Me.activeStreamingProfiles.Items.Count - 1. En sjekk bekreftet at vår fork allerede håndterer dette – ingenting å endre.

Hvorfor: liten UX-papirkutt som viste seg å allerede ikke være en papirkutt her.


F40 - Større maks-tilkoblinger + advarselslogg

Hva: plugin-modulens samtidige strømgrense (SemaphoreSlim rundt Sockets_Stream_File / Sockets_Encoder_Start) var hardkodet til 4. F40 gjør den brukerkonfigurerbar på Generelt-innstillingssiden (standard 16, område 1-256), legger til en MaxConnections-logglinje når en forespørsel må vente på en plass, OG viser et rødt ⚠ Maks tilkoblinger-merke nederst til venstre i innstillingsdialogen hvis grensen ble nådd minst én gang siden MusicBee startet.

Hvorfor: når en enhet sender parallelle forespørsler (noen Marantz/Linn under kunstverksskanninger, BubbleUPnPs metadata-sonderinger sammen med aktiv avspilling), ble ytterligere forespørsler blokkert stille bak semaforen – brukeren så "enheten treg" uten synlig årsak. Logglinjen er bra for teknisk feilsøking, men ikke-tekniske brukere leser aldri logger. Det synlige merket i innstillingsdialogen gjør tilstanden med nådd grense oppdagbar for alle som åpner plugin-modulens preferanser.

Implementering:

  • Sentraliserte ventingen i WaitOnSendBarrier(logTag) i MusicBeeUpnp.vb; begge kallesteder (MediaServerDevice.GetFile, Encoder.StartEncode) bruker den.
  • Settings.MaxConnections lagret i v8 av innstillingsskjemaet.
  • Plugin.MaxConnectionsHit er et klebrig sesjonsflagg satt inne i WaitOnSendBarrier; tilbakestilles bare ved MusicBee-omstart.
  • SettingsDialog.maxConnectionsBadge er en rød fet etikett på (16, 410) som bare vises når Plugin.MaxConnectionsHit er Sann. Har et verktøytips som forklarer årsak og løsning.
  • Semaforen initialiseres én gang ved type-lasting, så endring av innstillingen krever en MusicBee-omstart (merket i feltetiketten).

F41 - Logg "koding på grunn av ReplayGain/DSP"

Hva: i stedet for separate "koding for RG" / "koding for DSP" logglinjer, inkluderer den enkelte StreamDecision-linjen fra F42 MB-DSP/EQ, MB-ReplayGain, Profile-DSP/EQ, Profile-ReplayGain som akkumulerte årsaker. Samme diagnostiske verdi, mindre støy.

Hvorfor: brukere ser alle årsakene til at transkoding skjer for et gitt spor på én logglinje, ikke spredt. Se F42 for fullstendige detaljer.


F42 - Logg "renderer støtter ikke kildekodek"

Hva: la til en StreamDecision-logglinje per spor som spilles til enhet som sier enten "native CODEC" eller "transkode CODEC→CODEC reason=…". Årsaksfeltet akkumulerer hver tilstand som utløste transkoding: MB-DSP/EQ, MB-ReplayGain, Profile-DSP/EQ, Profile-ReplayGain, WebFile, VirtualFile, ForceTranscoding(global), SampleRate<min/SampleRate>max, DownmixToStereo, DeviceLacksCodec(X), BandwidthConstrained.

Hvorfor: brukere var forvirret av uventede CPU-topper på filer de forventet å strømme nativt. Én logglinje per spor forteller dem nøyaktig hvilken tilstand som forårsaket transkoding – og hvis feltet viser DeviceLacksCodec(Flac), vet de umiddelbart at enhetens protokollinformasjon var ufullstendig og kanskje vil at F32s tilbakefall skal tre i kraft.

Implementering: enkelt akkumulatorstreng bygget trinnvis gjennom beslutningskjeden; logget én gang på slutten. Gated på Settings.LogDebugInfo for å unngå loggstøy i produksjon.


F43 - SetNextAVTransport-logg viser kilde-URL

Hva: QueueNext-loggoppføringer inkluderer nå source=<MusicBee library path> sammen med stream=<HTTP streaming URL>. Samme endring brukt på suksessstien og feilstien (QueueNext:Failed).

Hvorfor: ved feilsøking av et køet-spor-problem er strømme-URL-en (/encode/aabbccdd0.flac) ugjennomsiktig i seg selv – samme for hvert spor. Kilde-URL-en er den menneske-grep-bare bibliotekstien som forteller deg nøyaktig hvilken fil MusicBee prøvde å køe.


F44 - Bedre feillogging for mime-type

Hva: to nye loggoppføringer under Activate:

  • Activate:MimeUnverified - utløses per feilformet oppføring i enhetens GetProtocolInfo-svar, og navngir hvilken oppføring som ikke kunne parses (slik at brukeren kan se f.eks. "Marantz returnerte http-get:*::* for en kodek - kapasiteten er uverifisert, F32s tilbakefall vil gjette").
  • Activate:NoSinkInfo - utløses én gang hvis enheten returnerte ingen <Sink>-element i det hele tatt. Betyr at SupportedMimeTypes forblir Nothing og IsCodecSupported degraderes til "antar at alt fungerer" - nyttig kontekst når senere "enhet nektet strøm"-feil vises.

Hvorfor: før F44 etterlot disse stille kapasitets-gjennomfallene brukere som gjettet hvorfor sporene deres enten ble transkodet mot forventningene eller nektet av enheten. Nå viser et enkelt grep for Activate: om enhetens kapasitetsinformasjon var brukbar.


F45 - Bedre feillogging for metadata

Hva: Browse-unntaksloggen i ContentDirectoryService.vb ble allerede beriket i tidligere yaiol-arbeid (Alia Vox-feiløkten) med ObjectID og stakksporing. F45 utvider den ytterligere med BrowseFlag (metadata vs barn), Filter (hvilke attributter klienten ba om), sortCriteria, og partialResultLength (hvor mange byte DIDL som ble produsert før feilen – peker på hvor langt gjennom batchen det dårlige sporet sitter).

Hvorfor: når noe går galt midt i DIDL, forteller partial-length-verdien deg om feilen var på det første sporet i batchen (partial=0) eller et stykke ut i (partial=N) – kombinert med batchens startingIndex, kan du identifisere den fornærmende sporindeksen. Filter og BrowseFlag forklarer hvilken type bla klienten ønsket; noen ganger mislykkes en metadata-bare bla der en barn-bla for samme ID lykkes.


Nettverk

F46 - Automatisk modus annonserer kun på ekte nettverksadaptere

Hva: i Automatisk grensesnittmodus pleide plugin-modulen å annonsere seg selv (SSDP) på hver operasjonell IPv4-adapter. På en maskin som også kjører en VPN-tunnel (NordLynx) eller en virtuell svitsj (Hyper-V / WSL / Docker), ble det samme biblioteket annonsert på hver av disse adapterne også, slik at kontrollpunktet du kastet fra oppdaget serveren to eller tre ganger og listet biblioteket som dupliserte kopier. Automatisk modus beholder nå bare adaptere som har en ekte IPv4 standard gateway (HasIPv4Gateway) – noe tunnel- og virtuell-svitsj-adapterne ikke har – så disse droppes fra annonseringslisten. En brukerfestet adresse vinner fortsatt direkte (annonser kun på det grensesnittet), og hvis ingen adapter rapporterer en gateway, faller velgeren tilbake til hver adapter, slik at den annonserte adresselisten aldri er tom og plugin-modulen ikke kan bli usynlig.

Hvorfor: duplikaten er ikke forårsaket av "å være på en VPN" – den er forårsaket av å annonsere på LAN-adapteren og tunnel-/virtuell-adapteren samtidig, slik at ett kontrollpunkt ser samme server på to adresser. En forbruker-VPN (NordVPN/NordLynx) tunnelerer kun internett-bundet trafikk; DLNA-rendereren lever på LAN, og lokal-subnett-trafikk omgår tunnelen, så tunneladapteren når uansett aldri en renderer – å droppe den fjerner en fantomkopi, aldri en fungerende bane. Gateway-testen er det billige, pålitelige signalet som skiller en ekte LAN/Wi-Fi-adapter fra en tunnel eller virtuell svitsj. Komplementerer N05 (som fikset hvordan annonseringer sendes på slike koblinger – multicast i stedet for kringkasting); F46 styrer hvilke adaptere som annonseres på i det hele tatt.

Kjent begrensning: en mesh / fjernaksess-VPN (Tailscale, ZeroTier, WireGuard-to-home) hvis renderere genuint lever over tunnelen, presenterer vanligvis en adapter uten standard gateway, så automatisk modus dropper den også. Disse brukerne fester VPN-adressen i stedet, som har forrang over gateway-filteret.

Innhold