MusicBee UPnP Plugin Βοήθεια

Τι νέο υπάρχει

2.0.9 - 2026-08-23

Η ειδοποίηση ενημέρωσης ανοίγει τις σελίδες της στη γλώσσα σας

Τι: οι σύνδεσμοι Τι νέο υπάρχει και Λήψη στην ειδοποίηση ενημέρωσης ανοίγουν πλέον τις σελίδες του πρόσθετου στη γλώσσα του MusicBee, αντί για τα Αγγλικά.

Γιατί: αυτοί οι δύο σύνδεσμοι περιόριζαν τη γλώσσα σε μία από τέσσερις — Αγγλικά, Γαλλικά, Ισπανικά ή Γερμανικά — πριν την αποστολή στον ιστότοπο, οπότε όλοι οι άλλοι λάμβαναν την αγγλική σελίδα ακόμα και όταν υπήρχε μετάφρασή της. Τώρα μεταβιβάζουν τη γλώσσα του MusicBee αμετάβλητη και αφήνουν τον ιστότοπο να αποφασίσει τι θα σερβίρει, κάτι που έκανε πάντα το κουμπί Βοήθεια δίπλα τους.

2.0.8 - 2026-08-22

Το πρόσθετο πλέον συστήνεται σωστά στις εφαρμογές και τις συσκευές που το ανακαλύπτουν στο δίκτυό σας, και οι ρυθμίσεις των Προφίλ Συσκευών ευθυγραμμίζονται ξανά.

Οι συσκευές σας εμφανίζουν τον σωστό κατασκευαστή, μοντέλο και έκδοση

Τι: όταν μια εφαρμογή ελέγχου, ένα τηλέφωνο ή μια τηλεόραση βρίσκει το MusicBee στο δίκτυό σας, πλέον παρουσιάζει αυτό το πρόσθετο ως κατασκευασμένο από την yaiol, παραπέμπει στον ιστότοπο του ίδιου του πρόσθετου, το περιγράφει ως καλύπτοντας και τους τρεις ρόλους — διακομιστής, αναπαραγωγέας και renderer — και αναφέρει την έκδοση που έχετε πραγματικά εγκαταστήσει.

Γιατί: κάθε συσκευή UPnP ανακοινώνει ποιος την κατασκεύασε και τι είναι, και οι εφαρμογές ελέγχου το εμφανίζουν ως την ταυτότητα της συσκευής. Αυτό το πρόσθετο εξακολουθούσε να ανακοινώνει τις λεπτομέρειες του αρχικού πρόσθετου από το οποίο είχε διακλαδωθεί: το όνομα άλλου συγγραφέα, τον ιστότοπο του MusicBee αντί του δικού του, και έναν αριθμό μοντέλου παγωμένο στο "1.0" από την πρώτη κιόλας έκδοση. Από το τηλέφωνό σας δεν υπήρχε τρόπος να καταλάβετε με ποιο πρόσθετο μιλούσατε, πόσο μάλλον ποια έκδοση του. Αυτές οι λεπτομέρειες προέρχονται πλέον από το ίδιο το πρόσθετο, οπότε η έκδοση που εμφανίζεται δίπλα στη συσκευή παραμένει σωστή με κάθε ενημέρωση.

Οι ρυθμίσεις των Προφίλ Συσκευών ευθυγραμμίζονται ξανά

Τι: στην καρτέλα Device Profiles οι ετικέτες και τα πλαίσιά τους μοιράζονται μία αριστερή άκρη και κάθονται σε ομοιόμορφη απόσταση, και το εύρος ρυθμού δειγματοληψίας διαβάζεται ως μία ενιαία σειρά.

Γιατί: τα πεδία είχαν απομακρυνθεί καθώς προστέθηκαν επιλογές στην καρτέλα με την πάροδο του χρόνου, και η ετικέτα "έως" του εύρους ρυθμού δειγματοληψίας είχε καταλήξει να κάθεται πάνω από το πλαίσιο δίπλα της — ευανάγνωστη μόλις ξέρατε τι έλεγε, μπερδευτική την πρώτη φορά που κοιτάξατε.

2.0.7 - 2026-08-08

Τα μεγαλύτερα κομμάτια διατηρούν τον τίτλο τους και τον ρυθμιστή θέσης τους

Τι: ένα μεγαλύτερο κομμάτι που αποστέλλεται από ένα τηλέφωνο — ένα μεγάλο αρχείο FLAC, υψηλής ανάλυσης ή DSD — τώρα εμφανίζει τον σωστό τίτλο του και μπορεί να μετακινηθεί, όπως ένα μικρό. Προηγουμένως, ορισμένα από αυτά αναπαράγονταν μέσω του δικτύου, με μια διεύθυνση ιστού αντί για τον τίτλο και έναν ρυθμιστή που δεν έκανε τίποτα.

Γιατί: το πρόσθετο περιμένει την τοπική του αντιγραφή πριν ξεκινήσει, αλλά συνήθιζε να αποφασίζει εκ των προτέρων αν ένα αρχείο άξιζε να περιμένει, με βάση το μέγεθός του. Αυτό ήταν στην πραγματικότητα μια εικασία για το πόσο γρήγορο είναι το δίκτυό σας, κάτι που δεν έχει τρόπο να γνωρίζει: ένα κομμάτι 65 MB κρίθηκε πολύ μεγάλο, και στη συνέχεια ολοκληρώθηκε η λήψη του ένα δευτερόλεπτο αργότερα — άνετα εντός της αναμονής που είχε ήδη εγκαταλείψει. Τώρα απλά παρακολουθεί τη λήψη. Ενώ εξακολουθεί να φτάνει, το πρόσθετο συνεχίζει να περιμένει, όσο κι αν χρειαστεί. Εγκαταλείπει μόνο όταν η μεταφορά πραγματικά σταματήσει, κάτι που τώρα παρατηρεί πιο γρήγορα από την παλιά σταθερή καθυστέρηση.

2.0.6 - 2026-08-03

Τα άλμπουμ που αποστέλλονται από ένα τηλέφωνο αναπαράγονται πλέον χωρίς κενό μεταξύ των κομματιών και το ραδιόφωνο διαδικτύου αναγνωρίζεται ως ραδιόφωνο αντί να αντιμετωπίζεται ως ένα ασυνήθιστα μεγάλο τραγούδι.

Τα άλμπουμ αναπαράγονται χωρίς κενά

Τι: όταν στέλνετε ένα ολόκληρο άλμπουμ από το τηλέφωνό σας, το MusicBee τώρα μεταβαίνει από το ένα κομμάτι στο επόμενο χωρίς παύση — έτσι οι ζωντανές ηχογραφήσεις, τα DJ sets και τα συνεχόμενα κλασικά έργα διατηρούν τη συνοχή τους.

Γιατί: το πρότυπο επιτρέπει σε μια εφαρμογή ελέγχου να λέει "εδώ είναι τι ακολουθεί", κάτι που καθιστά δυνατή μια απρόσκοπτη σύνδεση. Αυτή η οδηγία δεν γινόταν καθόλου δεκτή, οπότε η εφαρμογή δεν είχε πού να τοποθετήσει το επερχόμενο κομμάτι και το ανακοίνωνε σαν να ήταν το τρέχον — η αιτία του προβλήματος του άλμπουμ που διορθώθηκε στην προηγούμενη έκδοση. Τώρα γίνεται δεκτή σωστά: το επόμενο κομμάτι ανακτάται ενώ το τρέχον παίζει ακόμα, και ο ίδιος ο player του MusicBee διασχίζει το όριο.

Το ραδιόφωνο διαδικτύου αναγνωρίζεται ως ραδιόφωνο

Τι: ένας ζωντανός σταθμός που αποστέλλεται στο MusicBee αναπαράγεται ως ροή και δεν κατεβαίνει ποτέ.

Γιατί: η λήψη μιας εκπομπής δεν έχει νόημα — δεν έχει τέλος, και δεν υπάρχει τίποτα για να μεταπηδήσετε — αλλά το πρόσθετο προηγουμένως δεν είχε τρόπο να ξεχωρίσει ένα από ένα αρχείο μουσικής, οπότε άρχισε να το ανακτά και σταμάτησε μόλις η λήψη ξεπέρασε ένα σταθερό μέγεθος. Η εφαρμογή ελέγχου δηλώνει ποιο από τα δύο στέλνει, και αυτό διαβάζεται πλέον απευθείας. Καμία ρύθμιση, καμία εικασία.

Τα μεγάλα κομμάτια υψηλής ανάλυσης διατηρούν το αντίγραφό τους

Τι: τα αρχεία DSD και οι μεγάλες ηχογραφήσεις 24-bit μπορούν πλέον να μετακινούνται όπως οποιοδήποτε άλλο κομμάτι.

Γιατί: πιάστηκαν από το όριο μεγέθους παραπάνω — ένα 20λεπτο κομμάτι υψηλής ανάλυσης ή ένα 10λεπτο κομμάτι DSD το ξεπέρασαν και τα δύο — οπότε το αντίγραφό τους εγκαταλείφθηκε και ο ρυθμιστής θέσης σταμάτησε να λειτουργεί ακριβώς για το υλικό που ήταν πιο πιθανό να αξίζει να το μετακινήσετε. Με το ραδιόφωνο να αναγνωρίζεται σωστά, δεν χρειάζεται όριο μεγέθους.

2.0.5 - 2026-08-03

Δύο διορθώσεις για τον έλεγχο του MusicBee από ένα τηλέφωνο: η ένταση του ήχου σημαίνει πλέον το ίδιο και στα δύο άκρα, και η μετάδοση ενός ολόκληρου άλμπουμ συνεχίζει να λειτουργεί μετά το πρώτο κομμάτι.

Η ένταση στο τηλέφωνό σας ταιριάζει με την ένταση στο MusicBee

Τι: η ρύθμιση της έντασης στο μέγιστο στο τηλέφωνό σας φτάνει πλέον στο μέγιστο στο MusicBee, και η ρύθμιση του MusicBee διαβάζεται σωστά στο τηλέφωνο.

Γιατί: το πρόσθετο δεν έλεγε ποτέ στην εφαρμογή ελέγχου ποια ήταν η υψηλότερη ένταση του ήχου, οπότε κάθε εφαρμογή έπρεπε να μαντέψει. Μία από αυτές κατέληξε στο 69, πράγμα που σήμαινε ότι το 100% της έφτανε μόνο το 69% στο MusicBee, ενώ το 100% του MusicBee επέστρεφε ως 144% στο τηλέφωνο — και τα κουμπιά έντασης του τηλεφώνου δεν μπορούσαν ποτέ να φτάσουν στην κορυφή. Ο renderer δηλώνει τώρα το εύρος ξεκάθαρα, οπότε και τα δύο άκρα μιλούν για την ίδια κλίμακα.

Η μετάδοση ενός άλμπουμ διατηρεί τους τίτλους του και τον ρυθμιστή θέσης του

Τι: κάθε κομμάτι ενός άλμπουμ που αποστέλλεται από ένα τηλέφωνο εμφανίζει πλέον τον σωστό τίτλο του και μπορεί να μετακινηθεί, όχι μόνο το πρώτο.

Γιατί: μια εφαρμογή ελέγχου ανακοινώνει το επόμενο κομμάτι ένα κλάσμα του δευτερολέπτου μετά το τρέχον, και αυτή η ανακοίνωση ακύρωνε το αντίγραφο που ανακτούταν για το κομμάτι που επρόκειτο να παίξει — οπότε τα περισσότερα κομμάτια επέστρεφαν αθόρυβα στην αναπαραγωγή μέσω του δικτύου, κάτι που χάνει τόσο τον τίτλο όσο και τη δυνατότητα μετακίνησης. Τα αντίγραφα για πολλά κομμάτια διατηρούνται πλέον το ένα δίπλα στο άλλο, οπότε μια ανακοίνωση δεν μπορεί πλέον να ακυρώσει αυτό που χρησιμοποιείται.

2.0.4 - 2026-08-02

Η μουσική που αποστέλλεται στο MusicBee από ένα τηλέφωνο ή άλλο διακομιστή συμπεριφέρεται πλέον σαν ένα πραγματικό κομμάτι: μπορείτε να μετακινηθείτε μέσα σε αυτό και εμφανίζει τον σωστό τίτλο του αμέσως. Επιπλέον, μια διόρθωση για hi-fi streamers που παρουσιάζονται ως μία συνδυασμένη συσκευή.

Μετακινηθείτε σε ένα κομμάτι που στάλθηκε από αλλού

Τι: η μεταφορά του ρυθμιστικού θέσης λειτουργεί πλέον για ένα κομμάτι που στάλθηκε από το τηλέφωνό σας, ένα NAS ή έναν άλλο διακομιστή πολυμέσων. Για να γίνει αυτό δυνατό, το MusicBee κατεβάζει ένα αντίγραφο του κομματιού σε έναν προσωρινό φάκελο ενώ αρχίζει να παίζει και αναπαράγει αυτό το αντίγραφο. Χρειάζεται περίπου ένα δευτερόλεπτο σε ένα οικιακό δίκτυο, το αντίγραφο διαγράφεται μόλις στείλετε ένα άλλο κομμάτι και τυχόν υπολείμματα καθαρίζονται την επόμενη φορά που θα ξεκινήσει το MusicBee.

Γιατί: το MusicBee μπορεί να ξεκινήσει και να σταματήσει κάτι που ακούει μέσω του δικτύου, αλλά δεν μπορεί να μετακινηθεί μέσα σε αυτό — έτσι ο ρυθμιστής φαινόταν να πηδάει και μετά να γλιστράει κατευθείαν πίσω στην αρχική του θέση, χωρίς εξήγηση. Η αναπαραγωγή ενός συνηθισμένου αρχείου στον δικό σας δίσκο αφαιρεί εντελώς τον περιορισμό αντί να τον παρακάμπτει.

Σωστός τίτλος και διάρκεια από την πρώτη νότα

Τι: ένα κομμάτι που στάλθηκε από μια εφαρμογή που δεν δίνει στα αρχεία της μια συνηθισμένη επέκταση αρχείου εμφανίζει πλέον τον πραγματικό του τίτλο και τη διάρκεια μόλις ξεκινήσει, αντί να εμφανίζεται ως μια μεγάλη διεύθυνση ιστού.

Γιατί: το MusicBee αναγνωρίζει ένα κομμάτι — και βρίσκει τις ετικέτες του — από την επέκταση αρχείου, και ορισμένοι παίκτες δίνουν διευθύνσεις χωρίς καθόλου επέκταση. Το τοπικό αντίγραφο φέρει πάντα το σωστό, οπότε το κομμάτι αναγνωρίζεται ανεξάρτητα από το πώς το ονομάζει η αποστέλλουσα εφαρμογή.

Ένα άλμα που δεν μπορεί να γίνει τώρα το λέει

Τι: εάν ο renderer πραγματικά δεν μπορεί να μετακινηθεί στο ζητούμενο σημείο, η εφαρμογή ελέγχου ενημερώνεται και το αναφέρει.

Γιατί: προηγουμένως απαντούσε "έγινε" ανεξάρτητα, οπότε ο ρυθμιστής γλίστρησε πίσω ένα δευτερόλεπτο αργότερα χωρίς τίποτα να εξηγεί το γιατί. Μια ειλικρινής άρνηση είναι ευκολότερο να αντιμετωπιστεί από μια σιωπηλή.

Οι συνδυασμένοι hi-fi streamers διαβάζονται σωστά

Τι: όταν το MusicBee αναπαράγει σε μια συσκευή που παρουσιάζεται ως μία συνδυασμένη μονάδα — ένα Marantz ή Denon streamer, όπου ο player βρίσκεται μέσα σε ένα περίβλημα κατασκευαστή μαζί με έναν διακομιστή πολυμέσων — το plugin διαβάζει πλέον τις δικές του λεπτομέρειες του player αντί για αυτές του διακομιστή πολυμέσων.

Γιατί: προηγουμένως ρωτούσε το λάθος μισό της συσκευής ποιες μορφές ήχου μπορούσε να χειριστεί, χωρίς να λαμβάνει καμία χρήσιμη απάντηση, και συνέχιζε χωρίς ποτέ να ελέγχει — ακριβώς το υλικό όπου ο χειρισμός μορφών πρέπει να είναι σωστός. Η περιγραφή μοντέλου μιας συσκευής λαμβάνεται επίσης υπόψη κατά την αντιστοίχισή της με ένα προφίλ συσκευής. Διαβαζόταν από λάθος μέρος και απορριπτόταν.

2.0.3 - 2026-08-02

Ο ρόλος αναπαραγωγής εξελίσσεται: Το MusicBee μπορεί πλέον να λαμβάνει μουσική που δεν βρίσκεται ήδη στη βιβλιοθήκη του — ένα αρχείο στο τηλέφωνό σας, σε ένα NAS, σε άλλο διακομιστή — αντί μόνο για κομμάτια που ήδη διαθέτει.

Αναπαραγωγή μουσικής που αποστέλλεται από το τηλέφωνό σας, όχι μόνο από τη δική σας βιβλιοθήκη

Τι: όταν χρησιμοποιείτε μια εφαρμογή ελέγχου όπως το Symfonium ή το BubbleUPnP για να στείλετε μουσική στο MusicBee, το κομμάτι δεν χρειάζεται πλέον να προέρχεται από τη βιβλιοθήκη του MusicBee. Ένα αρχείο αποθηκευμένο στο ίδιο το τηλέφωνο, σε ένα NAS ή σε άλλο διακομιστή πολυμέσων αναπαράγεται τώρα. Ο τίτλος και η διάρκεια προέρχονται από την εφαρμογή που το έστειλε, οπότε το κομμάτι εμφανίζεται σωστά παρόλο που το MusicBee δεν έχει δει ποτέ το αρχείο.

Γιατί: ο ρόλος αναπαραγωγής δημιουργήθηκε για την περίπτωση όπου περιηγείστε στη βιβλιοθήκη αυτού του υπολογιστή από το τηλέφωνό σας και πατάτε ένα τραγούδι — το κομμάτι ήταν ήδη στον υπολογιστή, οπότε το MusicBee απλώς αναπαρήγαγε το δικό του αρχείο. Οτιδήποτε έφτανε από κάπου αλλού απορρίπτονταν αθόρυβα, γεγονός που καθιστούσε τη λειτουργία άχρηστη για την εξίσου φυσική περίπτωση της προώθησης μουσικής από το τηλέφωνο προς τα καλά ηχεία.

Ένα κομμάτι που δεν μπορεί να αναπαραχθεί το δηλώνει

Τι: εάν ο renderer δεν μπορεί πραγματικά να αναπαράγει αυτό που του στάλθηκε, το αναφέρει τώρα πίσω στην εφαρμογή που το έστειλε.

Γιατί: προηγουμένως απαντούσε "το έλαβα" σε οτιδήποτε, οπότε η εφαρμογή ελέγχου προχωρούσε και πατούσε αναπαραγωγή. Χωρίς να έχει φορτωθεί τίποτα, το MusicBee επανεκκινούσε όποιο κομμάτι είχε μείνει από πριν — και αν αυτό το αρχείο είχε χαθεί, παραπονιόταν ότι η πηγή του δεν μπορούσε να βρεθεί. Το σφάλμα ανέφερε ένα άσχετο κομμάτι και δεν έδειχνε πουθενά κοντά στο πραγματικό πρόβλημα.

Η αποστολή ενός νέου κομματιού ενώ είναι σε παύση αναπαράγει τώρα αυτό το κομμάτι

Τι: εάν το MusicBee είναι σε παύση και η εφαρμογή ελέγχου σας του στείλει κάτι νέο, το νέο κομμάτι ξεκινά.

Γιατί: η συνέχιση είχε προτεραιότητα έναντι της φόρτωσης, οπότε το κομμάτι σε παύση συνέχιζε από εκεί που είχε σταματήσει και το κομμάτι που μόλις είχατε επιλέξει απορρίπτονταν χωρίς λέξη.

2.0.2 - 2026-08-01

Το θέμα είναι η αναζήτηση: τώρα λειτουργεί ανά καλλιτέχνη, επιστρέφει τα σωστά αποτελέσματα και είναι γρήγορη σε μια μεγάλη βιβλιοθήκη. Επιπλέον, ένας νέος τρόπος για να στοχεύσετε την τυχαία αναπαραγωγή της εφαρμογής ελέγχου σας και μια διόρθωση για τρία κουμπιά που οδηγούσαν στο πουθενά.

Η αναζήτηση ανά καλλιτέχνη λειτουργεί πραγματικά

Τι: η αναζήτηση ενός καλλιτέχνη από την εφαρμογή ελέγχου σας επιστρέφει τώρα τη μουσική αυτού του καλλιτέχνη. Η αναζήτηση ταιριάζει τόσο με τον Καλλιτέχνη του κομματιού όσο και με τον Καλλιτέχνη Άλμπουμ του άλμπουμ, οπότε μια συλλογή βρίσκεται είτε πληκτρολογήσετε το όνομα του ερμηνευτή είτε το όνομα με το οποίο είναι αρχειοθετημένο το άλμπουμ.

Γιατί: μια αναζήτηση καλλιτέχνη παλαιότερα εκλαμβανόταν ως "δώσε μου τα πάντα αυτού του είδους" — ο καλλιτέχνης που πληκτρολογήσατε απορρίπτονταν και επέστρεφε ολόκληρη η βιβλιοθήκη, οπότε μια αναζήτηση που θα έπρεπε να είχε ταιριάξει με μερικές εκατοντάδες κομμάτια επέστρεφε δεκάδες χιλιάδες. Η αντιστοίχιση μόνο ενός από τα δύο πεδία καλλιτέχνη θα είχε χάσει αθόρυβα τα μισά αποτελέσματα, οπότε ελέγχονται και τα δύο.

Η σελίδα αποτελεσμάτων αναζήτησης εμφανίζεται σωστά

Τι: η κύλιση σε μια μεγάλη λίστα αποτελεσμάτων αναζήτησης τώρα κινείται μέσα σε αυτήν. Κάθε σελίδα στην οποία κάνετε κύλιση είναι η σελίδα που λαμβάνετε.

Γιατί: ο διακομιστής συνήθιζε να απαντά σε κάθε αίτημα με την πρώτη χούφτα αποτελεσμάτων, ενώ ανέφερε τον πλήρη αριθμό αντιστοιχίσεων, οπότε μια εφαρμογή που έκανε κύλιση για περισσότερα συνέχιζε να λαμβάνει τα ίδια στοιχεία και ποτέ δεν έφτανε στο τέλος.

Η αναζήτηση είναι πολύ πιο γρήγορη σε μια μεγάλη βιβλιοθήκη

Τι: μια αναζήτηση τώρα εκτελεί ένα μόνο ερώτημα για ολόκληρο το σύνολο αποτελεσμάτων και διαβάζει μόνο τις ετικέτες της σελίδας που βλέπετε.

Γιατί: κάθε σελίδα προηγουμένως επανεκτελούσε το ερώτημα έναντι της βιβλιοθήκης και στη συνέχεια φόρτωνε τις ετικέτες κάθε αντιστοίχισης — χιλιάδες από αυτές — για να εμφανίσει μια δωδεκάδα. Σε μια μεγάλη συλλογή αυτό έκανε κάθε κύλιση να παγώνει. Τα αποτελέσματα επίσης απορρίπτονται κάθε φορά που ανανεώνεται η βιβλιοθήκη, οπότε μια επεξεργασία δεν εμφανίζεται ποτέ παλιά.

Στοχεύστε την τυχαία αναπαραγωγή σας σε ένα φίλτρο

Τι: μια νέα ρύθμιση Τυχαίες αναπαραγωγές από στην καρτέλα Επιλογές Βιβλιοθήκης. Αφήστε την στο Όλη η Μουσική και οι φάκελοι Τυχαία Κομμάτια / Τυχαία Άλμπουμ της εφαρμογής ελέγχου σας συμπεριφέρονται όπως πριν. Επιλέξτε ένα από τα φίλτρα MusicBee και κάθε τυχαίο αίτημα αντλεί από αυτό το φίλτρο αντ' αυτού. Προσφέρονται και κρυφά φίλτρα.

Γιατί: ένας φάκελος τυχαίας αναπαραγωγής ζητά ένα κομμάτι "όλων", και είναι το μοναδικό αίτημα που δεν φέρει καμία ένδειξη για το τι εννοούσατε — οπότε πάντα αντλούσε από ολόκληρη τη βιβλιοθήκη, ομιλούμενο λόγο και όλα. Εδώ είναι που λέτε τι σημαίνει "όλα". Το άνοιγμα ενός φακέλου τυχαίας αναπαραγωγής από μέσα σε ένα φίλτρο στη συσκευή εξακολουθεί να αναπαράγει τυχαία αυτό το φίλτρο: μια επιλογή που κάνετε κατά την περιήγηση υπερισχύει της ρύθμισης.

Βοήθεια, GitHub και έλεγχος ενημερώσεων φτάνουν σε πραγματικές σελίδες

Τι: τα κουμπιά Βοήθεια και GitHub στο παράθυρο διαλόγου ρυθμίσεων, και ο αυτόματος έλεγχος για νέα έκδοση, ανοίγουν τώρα τις σελίδες που ονομάζουν.

Γιατί: και τα τρία δημιουργήθηκαν από μια συντομευμένη μορφή του ονόματος του πρόσθετου που δεν υπήρξε ποτέ σελίδα, οπότε το καθένα απέτυχε σιωπηλά — τα κουμπιά φαινόταν να μην κάνουν τίποτα και ο έλεγχος ενημερώσεων δεν ανέφερε ποτέ τίποτα, ανεξάρτητα από το πόσο καιρό είχε κυκλοφορήσει μια νέα έκδοση.

2.0.1 - 2026-07-26

Μια σειρά από διορθώσεις αναπαραγωγής και περιήγησης, με έμφαση στα podcast και στις εφαρμογές ελεγκτή (όπως το BubbleUPnP) που οδηγούν την αναπαραγωγή και την τυχαία σειρά.

Τα podcast αρχίζουν να παίζουν χωρίς παύση

Τι: ένα ληφθέν επεισόδιο podcast δηλώνει τώρα το πραγματικό του μήκος και το μέγεθος του αρχείου του εκ των προτέρων, μεταφερόμενο απευθείας από το αρχείο στο δίσκο στα μεταδεδομένα πολυμέσων.

Γιατί: χωρίς δηλωμένη διάρκεια, ένας ελεγκτής όπως το BubbleUPnP σαρώνει ξανά ολόκληρη τη ροή ήχου κάθε φορά που πατάτε αναπαραγωγή, απλώς για να υπολογίσει πόσο διαρκεί το επεισόδιο — έτσι η αναπαραγωγή ξεκινούσε μόνο μετά από μια αισθητή παύση. Με το μήκος να διαφημίζεται τώρα, ξεκινάει ομαλά.

Τα podcast εμφανίζονται όταν περιηγείστε ανά καλλιτέχνη

Τι: το όνομα της εκπομπής ενός podcast καταχωρείται τώρα ως ο καλλιτέχνης του — αντικατοπτρίζεται στα πεδία Καλλιτέχνης και Καλλιτέχνης Άλμπουμ (και τις παραλλαγές ταξινόμησής τους), ακριβώς όπως ήδη συμπληρώνει το πεδίο Άλμπουμ.

Γιατί: μια διαδρομή περιήγησης που ομαδοποιείται ανά πεδίο καλλιτέχνη συνήθιζε να βρίσκει τον καλλιτέχνη κάθε podcast κενό και να καταλήγει σε ένα άδειο επίπεδο. Η αντιμετώπιση της ίδιας της εκπομπής ως καλλιτέχνη — συνεπής με την αντιμετώπισή της ως άλμπουμ — σημαίνει ότι αυτές οι διαδρομές φτάνουν τώρα στα επεισόδια αντί για το τίποτα.

Οι λίστες "Πρόσφατα Αναπαραγωγμένα" και η μετάδοση λειτουργούν σωστά μετά από επανεκκίνηση

Τι: η αναπαραγωγή ενός podcast, ηχητικού βιβλίου, εισερχομένων ή ραδιοφωνικού κομματιού απευθείας — χωρίς να περιηγηθείτε πρώτα σε αυτό, όπως κάνουν η λίστα "Πρόσφατα Αναπαραγωγμένα" του BubbleUPnP και οι στόχοι μετάδοσης — δεν αποτυγχάνει πλέον. Το πρόσθετο φορτώνει τώρα το κομμάτι κατ' απαίτηση όταν ζητείται με αναγνωριστικό.

Γιατί: αυτές οι λίστες ζητούν ένα κομμάτι αμέσως μετά την επανεκκίνηση του MusicBee, πριν περιηγηθεί σε οτιδήποτε, οπότε το πρόσθετο δεν είχε δει ποτέ το αναγνωριστικό και απαντούσε "Κακό αναγνωριστικό". Τώρα φορτώνει αναγκαστικά τις σχετικές πηγές σε αυτό το πρώτο άμεσο αίτημα και βρίσκει το κομμάτι.

Οι λίστες "Τυχαία Κομμάτια" και "Τυχαία Άλμπουμ" επιστρέφουν αποτελέσματα

Τι: οι φάκελοι τυχαίας αναπαραγωγής "Τυχαία Κομμάτια" και "Τυχαία Άλμπουμ" του BubbleUPnP, οι οποίοι ζητούν ένα τυχαίο τμήμα ολόκληρης της βιβλιοθήκης, επιστρέφουν τώρα γεμάτοι.

Γιατί: αυτές είναι αναζητήσεις χωρίς τίτλο για αντιστοίχιση, και το πρόσθετο προηγουμένως τις απαντούσε από μια κενή εσωτερική λίστα, οπότε πάντα έδειχναν τίποτα. Τώρα εξυπηρετούνται — σωστά σελιδωμένες — από την ίδια διαδρομή ερωτήματος κατ' απαίτηση που χρησιμοποιεί η υπόλοιπη περιήγηση.

Τα άλμπουμ με κενή ετικέτα παραθέτουν τα κομμάτια τους

Τι: το άνοιγμα ενός άλμπουμ που ομαδοποιήθηκε σε μια κενή τιμή — για παράδειγμα κομμάτια εισερχομένων που δεν φέρουν έτος — εμφανίζει τώρα τα κομμάτια του.

Γιατί: η αντιστοίχιση που συλλέγει τα κομμάτια ενός άλμπουμ αντιμετώπιζε το "αυτή η ετικέτα είναι κενή" ως "καμία αντιστοίχιση", οπότε οποιοδήποτε άλμπουμ σχηματίστηκε από ένα κενό πεδίο δεν οδηγούσε σε τίποτα. Μια κενή τιμή ομάδας τώρα αντιστοιχεί σωστά στα κομμάτια που την μοιράζονται.


2.0.0 - 2026-07-22

Αυτή είναι η πρώτη δημόσια έκδοση του open-source yaiol fork του MusicBee UPnP plugin. Παρουσιάζεται σε δύο μέρη: όλα όσα είναι νέα σε αυτό το fork, και στη συνέχεια οι διορθώσεις και βελτιώσεις που έγιναν στο αρχικό plugin. Κάθε στοιχείο διατηρεί τη μορφή Τι / Γιατί του εσωτερικού καταλόγου χαρακτηριστικών του έργου, έτσι ώστε η λογική πίσω από κάθε αλλαγή να είναι στην σελίδα, όχι μόνο η αλλαγή.

Νέα σε αυτό το fork

MediaRenderer - αναπαραγωγή στο MusicBee

N01 - MusicBee ως renderer αναπαραγωγής

Τι: κανονικά αυτό το plugin λειτουργεί μονόδρομα: ένα τηλέφωνο ή άλλη συσκευή περιηγείται στη βιβλιοθήκη του MusicBee και αναπαράγει τη μουσική στον εαυτό της. Αυτή η λειτουργία προσθέτει την αντίθετη κατεύθυνση - επιτρέπει στο MusicBee να είναι ο αναπαραγωγέας. Από μια εφαρμογή ελεγκτή στο τηλέφωνό σας (όπως το BubbleUPnP) μπορείτε να επιλέξετε το MusicBee της επιφάνειας εργασίας σας ως αυτό που αναπαράγει, και στη συνέχεια να το ελέγχετε από το χέρι σας: αναπαραγωγή, παύση, διακοπή, παράλειψη εμπρός ή πίσω, μετάβαση σε ένα σημείο του κομματιού, και αλλαγή της έντασης ή σίγαση.

Γιατί: μετατρέπει το τηλέφωνό σας σε τηλεχειριστήριο για τη μουσική που βρίσκεται ήδη στον υπολογιστή σας. Καθίστε στον καναπέ, περιηγηθείτε στη βιβλιοθήκη σας στο τηλέφωνο, πατήστε ένα κομμάτι, και αυτό βγαίνει από τα ηχεία που είναι συνδεδεμένα στον υπολογιστή σας - με πλήρη έλεγχο από εκεί που κάθεστε. Το αρχικό plugin δεν το διέθεσε ποτέ ως λειτουργικό χαρακτηριστικό.

Ενεργοποίηση: είναι απενεργοποιημένο από προεπιλογή, επειδή η ενεργοποίησή του επιτρέπει σε οτιδήποτε στο οικιακό σας δίκτυο να ξεκινήσει την αναπαραγωγή στον υπολογιστή σας. Το ενεργοποιείτε με ένα πλαίσιο επιλογής στην καρτέλα Γενικά του διαλόγου ρυθμίσεων. Οι τρεις ρόλοι του plugin έχουν ο καθένας το δικό του πλαίσιο επιλογής εκεί - κοινή χρήση της βιβλιοθήκης μου (Server), άσε τους άλλους να παίξουν σε μένα (Renderer), και αναπαραγωγή σε άλλες συσκευές (Control Point) - και ο διάλογος εμφανίζει μόνο τις καρτέλες ρυθμίσεων που χρειάζονται πραγματικά οι ρόλοι που ενεργοποιήσατε, οπότε δεν αντιμετωπίζετε ποτέ επιλογές που δεν ισχύουν για εσάς.

Διαχωρισμός των μηχανών σας: μπορείτε να δώσετε στον renderer οποιοδήποτε όνομα θέλετε (ξεκινά ως "MusicBee (yaiol)"). Αυτό το όνομα είναι αυτό που εμφανίζεται στη λίστα των στόχων αναπαραγωγής του τηλεφώνου σας, οπότε όταν περισσότεροι από ένας υπολογιστές τρέχουν MusicBee μπορείτε να ξεχωρίσετε ποιος είναι ποιος. Μια αλλαγή ονόματος τίθεται σε ισχύ αμέσως, χωρίς επανεκκίνηση.

Καλύτερος δυνατός ήχος όταν παίζει στον εαυτό του: όταν περιηγείστε στην ίδια τη βιβλιοθήκη του MusicBee από το τηλέφωνό σας και στέλνετε ένα κομμάτι πίσω στο ίδιο MusicBee, το plugin αναγνωρίζει ότι του ζητείται να αναπαράγει ένα από τα δικά του αρχεία και απλώς το αναπαράγει απευθείας από τον δίσκο σας. Το αποτέλεσμα είναι ακριβές και άμεσο - bit-perfect, με τον δικό του ισοσταθμιστή και την εξισορρόπηση έντασης του MusicBee - αντί να ωθεί άσκοπα τον ήχο στο δίκτυο και κατευθείαν πίσω στον εαυτό του.

Λειτουργία ιδιωτικά: οι τρεις ρόλοι λειτουργούν ανεξάρτητα, οπότε μπορείτε να ενεργοποιήσετε τον renderer ενώ αφήνετε απενεργοποιημένη την κοινή χρήση βιβλιοθήκης. Σε αυτή τη ρύθμιση "μόνο renderer" η βιβλιοθήκη σας παραμένει εντελώς κρυμμένη από το δίκτυο - ανακοινώνεται μόνο ο στόχος αναπαραγωγής - και το MusicBee δεν θα προσφερθεί ποτέ να παίξει στον εαυτό του.


Συμπεριφορά αναπαραγωγής

N02 - Το 5.1 FLAC δεν γίνεται αυτόματη υπομίξη

Τι: ο περιορισμός του αριθμού καναλιών στο MediaServerDevice.GetEncodedFile ήταν If StereoOnly OrElse Not isPcmData Then channelCount = 2. Η ρήτρα Not isPcmData έκανε σιωπηλά υπομίξη κάθε μη-PCM μετακωδικοποίηση (FLAC, MP3, AAC, Ogg) σε στερεοφωνικό, ανεξάρτητα από τον αριθμό καναλιών της πηγής, νικώντας τους 5.1-ικανούς renderers όταν η πηγή ήταν 5.1 FLAC. Τώρα η δεύτερη ρήτρα εξαιρεί το FLAC: Not isPcmData AndAlso encoder.Codec <> FileCodec.Flac. Το FLAC 5.1 περνάει· τα MP3/AAC/Ogg εξακολουθούν να είναι αναγκαστικά στερεοφωνικά επειδή οι κωδικοποιητές γραμμής εντολών του MusicBee για αυτές τις μορφές αναμένουν είσοδο 2 καναλιών.

Γιατί: ολόκληρο το νόημα της μετακωδικοποίησης μιας πηγής 5.1 FLAC σε έξοδο FLAC είναι η διατήρηση της πολυκάναλης μίξης. Η σιωπηλή υπομίξη καθιστούσε την επιλογή μετακωδικοποίησης FLAC άχρηστη για ακρόαση surround. Με το N02 κάνει το σωστό.


Αρχιτεκτονική

Η δομική αλλαγή που καθιστά το fork βιώσιμο σε μια μεγάλη βιβλιοθήκη - απουσιάζει από το αρχικό plugin.

N03 - Δέντρο περιήγησης Lazy (κατά παραγγελία)

Τι: το αρχικό plugin δημιούργησε ολόκληρο το δέντρο περιήγησης κατά την εκκίνηση του MusicBee - απαρίθμηση κάθε κομματιού, πλήρες Library_GetFileTags ανά αρχείο, συναρμολόγηση ολόκληρης της ιεραρχίας κοντέινερ - πριν ανοίξει τη θύρα HTTP. Σε μια πραγματική βιβλιοθήκη (50k+ κομμάτια, 5400 επεισόδια podcast, εκατοντάδες σταθμοί) αυτό είναι λεπτά ψυχρής εκκίνησης, και το δέντρο παραμένει στη RAM για πάντα, συμπεριλαμβανομένων κλάδων που κανένας πελάτης δεν ανοίγει ποτέ. Αυτό το fork δεν χτίζει τίποτα εκ των προτέρων: η ρίζα εκθέτει έναν placeholder με πρόθεμα L: ανά τελικό σημείο (L:music, L:podcast, L:filter:…)· κάθε επίπεδο υπολογίζεται μόνο όταν ένας πελάτης περιηγείται σε αυτό (LazyBrowseEnsureLazyEndpointInMemory → κρυφές μνήμες ανά επίπεδο), και οι ειδοποιήσεις αλλαγής βιβλιοθήκης καθαρίζουν τις κρυφές μνήμες (SetLibraryDirty).

Γιατί: η ψυχρή εκκίνηση είναι ουσιαστικά άμεση - η θύρα HTTP είναι ανοιχτή μέχρι να ολοκληρώσει το MusicBee την αρχικοποίηση του plugin - και η μνήμη παραμένει ανάλογη με ό,τι έχει περιηγηθεί, όχι με το μέγεθος της βιβλιοθήκης. Αντιστάθμιση: η πρώτη περιήγηση σε ένα τελικό σημείο πληρώνει το κόστος φόρτωσης· η επανείσοδος αποθηκεύεται στην κρυφή μνήμη μέχρι την επόμενη αλλαγή βιβλιοθήκης. Αυτό είναι το θεμέλιο από το οποίο εξαρτώνται όλα τα άλλα. Πλήρεις σημειώσεις: FIXES.md.


Δικτύωση & ανθεκτικότητα

Ενίσχυση της διαδρομής σύνδεσης του HTTP server. Το αρχικό plugin πεθαίνει σιωπηλά όταν η θύρα του είναι μη διαθέσιμη.

N04 - Αυτο-επιδιόρθωση σύνδεσης θύρας HTTP

Τι: ο HTTP server του plugin δεν πεθαίνει πλέον όταν η ρυθμισμένη θύρα του είναι μη διαθέσιμη. Τρεις συνδεδεμένες αλλαγές:

  1. Αυτόματη επαναφορά σε περίπτωση αποτυχίας σύνδεσης. Το HttpServer.Start δοκιμάζει τη ρυθμισμένη θύρα, και σε SocketException σαρώνει προς τα πάνω έως και 20 θύρες για την πρώτη ελεύθερη. Η πραγματική συνδεδεμένη θύρα καταγράφεται σε ένα νέο Plugin.boundServerPort, και ό,τι διαφημίζει τον server - SSDP LOCATION URLs (NOTIFY + M-SEARCH response), το URL της συσκευής (PrimaryHostUrl), η προώθηση θύρας του router, και οι αυτο-φίλτρα SSDP/control-point - διαβάζει τώρα το boundServerPort αντί για το Settings.ServerPort. Οι UPnP clients ανακαλύπτουν την πραγματική θύρα μέσω SSDP, οπότε μια μετακινημένη θύρα είναι διαφανής για τους renderers.
  2. Ειδοποίηση χρήστη. Όταν συμβαίνει μια επαναφορά (η αποθηκευμένη θύρα δεν είναι αυτή που χρησιμοποιείται), ένα τοπικοποιημένο MessageBox (WarnPortInUse) ενημερώνει τον χρήστη ποια θύρα εξυπηρετεί πραγματικά και ότι οι συσκευές θα την βρουν ακόμα - επειδή το plugin λειτουργεί χωρίς γραφικό περιβάλλον και ένα μήνυμα εντός διαλόγου θα το έβλεπε μόνο κάποιος που ήδη υποψιαζόταν ένα πρόβλημα.
  3. Ανάκτηση επανεκκίνησης. Το RestartServer (η διαδρομή επανεκκίνησης αποθήκευσης ρυθμίσεων) συνήθιζε να αποαναφοροποιεί τα Plugin.controller / Plugin.server τυφλά. Εάν η αρχική Initialise έριχνε εξαίρεση πριν τα δημιουργήσει (ακριβώς αυτό που προκαλούσε μια αποτυχημένη σύνδεση), η επόμενη αποθήκευση ρυθμίσεων χτυπούσε ένα NullReferenceException - αφήνοντας ένα μισο-νεκρό plugin. Τώρα τα αναδημιουργεί και τα ξεκινά όταν είναι Nothing, οπότε η αποθήκευση μιας λειτουργικής θύρας αναβιώνει το plugin χωρίς πλήρη επανεκκίνηση του MusicBee.

Γιατί: η αιτία ήταν ένα πραγματικό περιστατικό χρήστη. Η παλιά προεπιλεγμένη θύρα 49382 βρίσκεται στο δυναμικό εύρος των Windows (49152-65535), όπου το Hyper-V/WSL2/Docker/WinNAT δεσμεύουν μεγάλα μπλοκ που μετατοπίζονται σε κάθε εκκίνηση - οπότε η σύνδεση απέτυχε με WSAEACCES ("απαγορευμένη πρόσβαση") σε μια μηχανή όπου λειτουργούσε για μήνες. Η αλλαγή της προεπιλογής σε μια ελεύθερη θύρα συγκρούστηκε στη συνέχεια με το Serviio (ένας ξεχωριστός DLNA server που βρισκόταν ήδη στη νέα θύρα), αποτυγχάνοντας με WSAEADDRINUSE. Κάθε αποτυχία καταπινόταν στο Initialise, αφήνοντας το plugin σιωπηλά νεκρό και στη συνέχεια NRE-ing στην επόμενη αποθήκευση ρυθμίσεων. Μετά το N04 μια σύγκρουση θύρας αυτο-επιδιορθώνεται - ο server συνεχίζει να λειτουργεί στην επόμενη ελεύθερη θύρα, ο χρήστης ενημερώνεται, και οι πελάτες τον ανακαλύπτουν ξανά - αντί να καταρρίπτει ολόκληρο το plugin.

Υλοποίηση:

  • Η προεπιλεγμένη θύρα μετακινήθηκε 493829779 (κάτω από το δυναμικό εύρος, οπότε τα Windows δεν την δεσμεύουν ποτέ αυτόματα· δεν είναι γνωστή προεπιλογή media-server) σε όλες τις τρεις δηλώσεις ServerPort + την επαναφορά αποτυχίας ανάλυσης ρυθμίσεων.
  • Το Plugin.boundServerPort (νέο κοινό πεδίο) κρατά την ενεργή θύρα ακρόασης· το activeServerPort παραμένει το ρυθμισμένο στιγμιότυπο, οπότε η λογική της ετικέτας "Απαιτείται Επανεκκίνηση" δεν ενεργοποιείται ψευδώς σε περίπτωση επαναφοράς.
  • HttpServer.PortScanRange = 20· η σάρωση σταματά στην πρώτη επιτυχημένη TcpListener.Start() και ρίχνει την τελευταία εξαίρεση μόνο αν όλες οι προσπάθειες αποτύχουν.
  • Νέο κλειδί πόρου EN WarnPortInUse (οι μεταφράσεις ακολουθούν την τοπική ρύθμιση κατά τη δημοσίευση).

N05 - Ανακοινώσεις SSDP μέσω της ομάδας multicast (VPN / σημείο-προς-σημείο)

Τι: οι ανακοινώσεις SSDP αποστέλλονται στην ομάδα multicast UPnP (239.255.255.250) αντί για μια διεύθυνση IP broadcast. Το αβλαβές σφάλμα "cannot access a disposed object" που καταγράφεται όταν μια απάντηση αναζήτησης SSDP ανταγωνίζεται μια επανεκκίνηση server καταστέλλεται επίσης.

Γιατί: σε προσαρμογείς δικτύου σημείο-προς-σημείο / VPN, η IP broadcast δεν ισχύει - η παλιά αποστολή broadcast απέτυχε με "invalid argument" και οι ανακοινώσεις χάθηκαν, οπότε το plugin ήταν αόρατο για τους πελάτες σε αυτές τις συνδέσεις. Η ανακοίνωση στην κατάλληλη ομάδα multicast διορθώνει την ανακάλυψη ακριβώς σε αυτούς τους προσαρμογείς.

Πλοήγηση βιβλιοθήκης

Αυτά κυκλοφόρησαν σε αυτό το fork και δεν υπάρχουν στο αρχικό plugin. Προέκυψαν από την πραγματική περιήγηση στην έξοδο του plugin από πραγματικούς UPnP clients.

N06 - Έκθεση βιβλιοθήκης βάσει φίλτρων

Τι: οι καρτέλες φίλτρων του MusicBee (αρχεία .xautopf στον φάκελο MusicBee του χρήστη) γίνονται ριζικά κοντέινερ UPnP στη βιβλιοθήκη του plugin. Τα κομμάτια κάθε φίλτρου είναι στη συνέχεια περιηγήσιμα σε μια ιεραρχία AlbumArtistSort → Album → Tracks.

Γιατί: οι χρήστες με επιμελημένα φίλτρα MusicBee (π.χ. "5-star tracks", "Recently added", "Classical → Baroque") αναμένουν να τα βρουν όταν περιηγούνται στο plugin από έναν UPnP client. Το αρχικό plugin εξέθετε μόνο το ακατέργαστο δέντρο της βιβλιοθήκης.


N07 - Καλωδίωση πεδίου SortAlbumArtist

Τι: το plugin διαβάζει τώρα το MetaDataType 165 του MusicBee (Sort Album Artist) και το χρησιμοποιεί για ομαδοποίηση/ταξινόμηση καλλιτεχνών σε προβολές περιήγησης.

Γιατί: οι hi-fi browsers και οι audiophiles χρησιμοποιούν ονόματα καλλιτεχνών ταξινόμησης ("Beethoven, Ludwig van" αντί για "Ludwig van Beethoven") για να οργανώσουν τις βιβλιοθήκες. Τυπική προσδοκία για σοβαρούς ακροατές. Λείπει και από τα δύο upstream.


N08 - Χειρισμός πολλαπλών τιμών AlbumArtist

Τι: όταν το πεδίο AlbumArtist ενός άλμπουμ περιέχει πολλούς καλλιτέχνες διαχωρισμένους με "; " (π.χ. "yaiol; Ars Ricercata"), το κομμάτι εμφανίζεται τώρα κάτω από κάθε καλλιτέχνη στις προβολές περιήγησης, όχι κάτω από έναν ενιαίο καλλιτέχνη Frankenstein που συνδυάζει τα ονόματα.

Γιατί: τα συνεργατικά άλμπουμ και οι συλλογές πρέπει να εμφανίζονται κάτω από κάθε συνεργάτη. Χωρίς αυτό, οι μισές διαδρομές αναζήτησης για να βρεθεί το άλμπουμ είναι σπασμένες.


N09 - Εξώφυλλο κοντέινερ άλμπουμ (upnp:albumArtURI)

Τι: οι κόμβοι κοντέινερ άλμπουμ στις απαντήσεις DIDL Browse περιλαμβάνουν τώρα ένα στοιχείο upnp:albumArtURI που δείχνει το εξώφυλλο του άλμπουμ.

Γιατί: χωρίς αυτό, κάθε άλμπουμ σε μια προβολή περιήγησης ενός UPnP client εμφανίζει ένα γενικό εικονίδιο αντί για το εξώφυλλο του άλμπουμ. Οπτική ένδειξη για την πλοήγηση· αναμενόμενο από κάθε σύγχρονο hi-fi browser.


N10 - Σειρά κομματιών μέσα σε άλμπουμ φίλτρων

Τι: τα κομμάτια μέσα σε ένα άλμπουμ που εκτίθεται από φίλτρο ταξινομούνται τώρα κατά Αριθμό Δίσκου, και στη συνέχεια κατά Αριθμό Κομματιού.

Γιατί: τυπική σειρά άλμπουμ. Χωρίς ρητή ταξινόμηση, τα κομμάτια επέστρεφαν με όποια σειρά τα επέστρεφε το φίλτρο - συνήθως τυχαία.


N11 - Διόρθωση δέντρου φακέλων λίστας αναπαραγωγής

Τι: η συνάρτηση LoadLibraryPlaylists (αρχικά από τον Steven Mayall, ~2014) απέτυχε να εισέλθει σε νεοδημιουργημένους φακέλους λίστας αναπαραγωγής. Η πρώτη λίστα αναπαραγωγής σε κάθε φάκελο, συν τυχόν υποφακέλους, κατέληγε ορφανή στο ριζικό επίπεδο.

Γιατί: υπήρχε στο αρχικό plugin για έντεκα χρόνια. Ορατό μέσα σε 30 δευτερόλεπτα από το άνοιγμα του BubbleUPnP και το κλικ στις Λίστες Αναπαραγωγής. Διορθώθηκε στο yaiol με σωστή αναδρομή σε νεοδημιουργημένους φακέλους κατά τη δημιουργία του δέντρου.


N12 - Καθαρισμός χαρακτήρων ελέγχου που είναι παράνομοι για XML

Τι: οποιοδήποτε κομμάτι με ετικέτα που περιέχει χαρακτήρα ελέγχου C0 (π.χ. 0x19 από μια κακή κωδικοποίηση - UTF-8 → Latin-1 → πίσω περικοπή 0x99 σε 0x19) προκαλούσε την αποτυχία ολόκληρης της απάντησης Browse με Action Failed μόλις το κακό κομμάτι εισερχόταν σε μια σελιδοποιημένη παρτίδα.

Γιατί: το XML 1.0 απαγορεύει τους περισσότερους χαρακτήρες ελέγχου C0, και ο XmlWriter ρίχνει εξαίρεση όταν του ζητηθεί να γράψει οποιονδήποτε. Υπήρχε στο αρχικό plugin. Διορθώθηκε με την αφαίρεση μη έγκυρων χαρακτήρων σε κάθε σημείο εξόδου Library_GetFileTags μέσω του XmlConvert.IsXmlChar.


N13 - Κατάλογος ραδιοφώνου ντετερμινιστικός σε σελιδοποιημένη περιήγηση

Τι: η περιήγηση για το κοντέινερ Ραδιοφώνου έπεφτε στον γενικό κλάδο λίστας αρχείων, ο οποίος καλούσε το files.Sort(AlbumFileComparer) σε κάθε κλήση. Οι καταχωρήσεις ραδιοφώνου έχουν κενές ετικέτες Άλμπουμ/Δίσκου/Κομματιού, οπότε κάθε σύγκριση επέστρεφε 0 - το List(Of T).Sort είναι ασταθές, παράγοντας μια διαφορετική σειρά σε κάθε κλήση. Τα σημεία ελέγχου UPnP σελιδοποιούν (το BubbleUPnP ανακτά 0..15 και μετά 16..τέλος)· μεταξύ των δύο κλήσεων η λίστα ανακατατάσσονταν, οπότε κάποιοι σταθμοί εμφανίζονταν και στις δύο σελίδες (διπλότυπα) και κάποιοι σε καμία (λείπουν) - φαινόταν τυχαίο σε κάθε ανανέωση.

Γιατί: υπήρχε στο αρχικό plugin (ο συγγραφέας του δεν περιηγείται ποτέ στο ραδιόφωνο μέσω UPnP). Διορθώθηκε εδώ με έναν ειδικό κλάδο ContainerCategory.Radio στο Browse, χωρίς ταξινόμηση ανά κλήση· το radioFiles ταξινομείται μία φορά κατά τη φόρτωση κατά Τίτλο (σταθερό). Η σελιδοποιημένη περιήγηση βλέπει τώρα μια ντετερμινιστική σειρά· η σελίδα 1 και η σελίδα 2 είναι ασύνδετες.


N14 - Η αναζήτηση UPnP κλάσης άλμπουμ επιστρέφει κοντέινερ άλμπουμ

Τι: η αναζήτηση UPnP για ερωτήματα κλάσης άλμπουμ (upnp:class = "object.container.album.musicAlbum", π.χ. "Random Albums" του BubbleUPnP) επέστρεφε την πλήρη λίστα κομματιών αντί για κοντέινερ άλμπουμ, οπότε ο πελάτης εμφάνιζε μηδέν άλμπουμ. Ο αρχικός χειριστής ανέλυε μόνο κριτήρια σε παρένθεση, και στη συνέχεια απέρριπτε όλα τα κομμάτια ανεξάρτητα από την αιτούμενη κλάση.

Γιατί: διορθώθηκε εδώ - τα ερωτήματα κλάσης άλμπουμ απαριθμούν τώρα διακριτά άλμπουμ (ομαδοποιημένα κατά AlbumArtist+Album) και εκπέμπουν το καθένα ως ένα σωστό κοντέινερ musicAlbum με εξώφυλλο, προσβάσιμο μέσω του εικονικού χώρου αναγνωριστικών Salb<idx> ώστε ο πελάτης να μπορεί να εμβαθύνει σε ένα αποτέλεσμα και να το αναπαράγει.


N15 - Λειτουργική, ευαίσθητη στο πεδίο αναζήτηση UPnP με κλικ-μέσω

Τι: το αρχικό δεν διαφήμιζε δυνατότητες αναζήτησης (GetSearchCapabilities επέστρεφε κενό), οπότε οι πελάτες αρνούνταν ακόμη και να στείλουν μια αναζήτηση· και το παλιό backend διάβαζε από το musicFiles, μόνιμα κενό στην εποχή του lazy-tree. Αυτό το fork διαφημίζει τις πραγματικές αναζητήσιμες ιδιότητες, υλοποιεί κομμάτια ανά τίτλο και άλμπουμ ανά τίτλο έναντι της lazy βιβλιοθήκης (HandleLazySearch), περιορίζει το ερώτημα στον τρέχοντα κλάδο του πελάτη όταν αποστέλλεται ένα πραγματικό αναγνωριστικό κοντέινερ (αλλιώς αντικαθιστά το L:music ώστε οι αναζητήσεις στην επάνω γραμμή να μην παρασύρουν θόρυβο podcast/ραδιοφώνου/audiobook), και καθιστά τα αποτελέσματα άλμπουμ κλικαριστά μέσω συνθετικών αναγνωριστικών Ssrch_alb_* που ένας πρώιμος κλάδος Browse αντιστοιχίζει πίσω στα κομμάτια του άλμπουμ. (Το κομμάτι των αποτελεσμάτων κλάσης άλμπουμ ως κοντέινερ είναι το N14.)

Γιατί: η αναζήτηση στο BubbleUPnP πήγε από "Η βιβλιοθήκη δεν υποστηρίζει αναζήτηση" στην επιστροφή χρήσιμων, περιορισμένων, αναπαραγώγιμων αποτελεσμάτων. Πλήρης σχεδιασμός + απορριφθείσες προσεγγίσεις: SEARCH.md.


N16 - Ακύρωση κρυφής μνήμης UPnP (SystemUpdateID)

Τι: το αρχικό επέστρεφε ένα σταθερό SystemUpdateID=0 - τη σύμβαση ακύρωσης κρυφής μνήμης UPnP ContentDirectory - οπότε οι πελάτες που συμμορφώνονταν με τις προδιαγραφές (BubbleUPnP) αντιμετώπιζαν τη βιβλιοθήκη ως αμετάβλητη: παλιά αποτελέσματα περιήγησης, 404 μικρογραφίες μετά από αλλαγή σχήματος URL, και ο χορός "επανεκκίνηση του MusicBee δύο φορές για να δείτε αλλαγές". Αυτό το fork αρχικοποιεί το SystemUpdateID από δευτερόλεπτα εποχής κατά τη φόρτωση (οπότε κάθε επανεκκίνηση είναι αυστηρά μπροστά από την τελευταία) και το αυξάνει σε κάθε μεταβολή βιβλιοθήκης και αλλαγή ρυθμίσεων (SetLibraryDirty / ResetCacheBumpSystemUpdateId).

Γιατί: οι πελάτες ανακτούν αξιόπιστα τις επεξεργασίες, τα νέα αρχεία και τις αλλαγές ρυθμίσεων στην επόμενη περιήγησή τους. Γνωστό όριο: οι εγγεγραμμένοι πελάτες δεν επαναπροωθούνται ενεργά με τη νέα τιμή μέσω GENA (παρκαρισμένο ως μελλοντική εργασία)· εξακολουθούν να τη βλέπουν στην επόμενη περιήγησή τους.


N17 - Εξώφυλλο συνδρομής Podcast

Τι: οι πλακίδια podcast δεν εμφάνιζαν εικόνες - κάθε αίτημα /PodcastThumbnail/ επέστρεφε 404. Δύο αλληλεπικαλυπτόμενα σφάλματα: η αλυσίδα ανάλυσης δεν έλεγχε ποτέ την πραγματική κρυφή μνήμη εξώφυλλων του MusicBee (%LocalAppData%\MusicBee\InternalCache\Subscriptions\<name>.jpg, από όπου φορτώνει το UI της επιφάνειας εργασίας), και το unescape+lowercase του HTTP layer παραμόρφωνε το κλειδί διαδρομής URL τροφοδοσίας μέχρι το τελευταίο τμήμα της διαδρομής του. Αυτό το fork αναλύει το εξώφυλλο από το InternalCache του MB και δρομολογεί τις αναζητήσεις μέσω ενός URL-safe slug που επιβιώνει ανέπαφο στο HTTP layer (PodcastSlug / podcastSubIdBySlug).

Γιατί: το εξώφυλλο συνδρομής εμφανίζεται τώρα στις προβολές περιήγησης (όλα τα 22 αιτήματα που προηγουμένως επέστρεφαν 404 επιλύονται).


N18 - Ιεραρχική (οριοθετημένη) περιήγηση ετικετών

Τι: οποιοδήποτε πεδίο μπορεί να επισημανθεί ως ιεραρχικό στην καρτέλα Επιλογές Βιβλιοθήκης και να του δοθεί ένας χαρακτήρας οριοθέτησης (ένας επιλογέας πεδίου + πλαίσιο οριοθέτησης με προσθήκη/αφαίρεση, που διατηρείται στις ρυθμίσεις του plugin). Ορίστε το Grouping σε / και μια τιμή όπως Jazz/Cool Jazz τότε περιηγείται ως Jazz › Cool Jazz αντί για μια επίπεδη καταχώρηση. Τα κομμάτια που έχουν ετικέτα ακριβώς σε έναν κλάδο (μόνο Jazz) αποκτούν τον δικό τους κόμβο [Jazz] ώστε τίποτα να μην κρύβεται, ένας κλάδος με ένα μόνο παιδί συμπτύσσεται από μόνος του, και το ; απορρίπτεται ως οριοθέτης επειδή είναι ο δικός του διαχωριστής πολλαπλών τιμών του MusicBee.

Γιατί: οι βαθιές ταξινομίες ετικετών που ένας χρήστης έχει ήδη κωδικοποιήσει σε ένα μόνο πεδίο (δέντρα ειδών, ιεραρχίες διάθεσης, "Classical/Baroque/Concerto") επιτέλους περιηγούνται ως το δέντρο που περιγράφει η ετικέτα, αντί για έναν επίπεδο τοίχο από slash-separated strings που ο χρήστης πρέπει να διαβάσει από άκρη σε άκρη.


N19 - Ενιαία ριζική διαδρομή με ετικέτα από το πεδίο ομαδοποίησης

Τι: μια ενιαία διαδρομή περιήγησης στη ρίζα επισημαίνεται από το πεδίο ομαδοποίησής της (π.χ. "Είδος") αντί για την πλήρη σύντομη διαδρομή της, ταιριάζοντας με τον τρόπο που ονομάζονται οι συγχωνευμένες ομάδες πρώτου πεδίου.

Γιατί: το δέντρο περιήγησης διαβάζεται με συνέπεια - ένας κανόνας ονομασίας είτε μια ριζική καταχώρηση στέκεται μόνη της είτε συγχωνεύτηκε με αδέλφια (N20) - αντί για μια μοναχική ριζική καταχώρηση που εμφανίζει μια λεπτομερή εσωτερική διαδρομή ενώ οι συγχωνευμένοι γείτονές της εμφανίζουν ένα καθαρό όνομα πεδίου.


N20 - Συγχώνευση διαδρομών περιήγησης που μοιράζονται ένα πρώτο πεδίο

Τι: δύο διαδρομές περιήγησης που μοιράζονται το ίδιο πρώτο πεδίο - "Είδος / Ταξινόμηση Καλλιτέχνη Άλμπουμ" και "Είδος / Άτομα Podcast" - συμπτύσσονται σε έναν ενιαίο ριζικό φάκελο Είδος που παραθέτει πρώτα τις τιμές του είδους και στη συνέχεια χωρίζεται στις δύο προβολές, αντί για δύο σχεδόν διπλότυπες καταχωρήσεις "Είδος / …" δίπλα-δίπλα στη ρίζα.

Γιατί: ένας χρήστης με πολλές σχετικές προβολές ενσωματωμένες κάτω από ένα κοινό πεδίο έβλεπε τη ρίζα γεμάτη με σχεδόν πανομοιότυπες καταχωρήσεις ανώτερου επιπέδου. Η συγχώνευσή τους διατηρεί τη ρίζα ευανάγνωστη και ομαδοποιεί τις σχετικές προβολές εκεί που ανήκουν - κάτω από το κοινό τους πεδίο.


N21 - Διαδρομές περιήγησης με τύπο κατηγορίας (Standard / Radio / Podcast)

Τι: κάθε διαδρομή περιήγησης είναι τύπου κατηγορίας - Standard, Radio ή Podcast. Η λίστα προτύπων ομαδοποιείται σε αυτές τις τρεις ενότητες, ο επιλογέας πεδίων κάθε προτύπου προσφέρει μόνο τα πεδία που μπορούν πραγματικά να παραδώσουν τα δεδομένα αυτής της κατηγορίας, και ένα πρότυπο μπορεί να εφαρμοστεί μόνο σε αντίστοιχους κόμβους στο δέντρο View (οι ασύμβατοι κόμβοι γκριζάρουν και δεν μπορούν να επιλεγούν). Τα δεσμευμένα πρότυπα Radio και Podcasts δεν μπορούν να διαγραφούν, οπότε η ενότητα κατηγορίας τους δεν εξαφανίζεται ποτέ.

Γιατί: χωρίς την τυποποίηση ένας χρήστης θα μπορούσε να δημιουργήσει μια διάταξη που να εμφανίζεται σιωπηλά κενή - ένας ραδιοφωνικός σταθμός δεν έχει "άλμπουμ", ένα επεισόδιο podcast δεν έχει "καλλιτέχνη άλμπουμ" - και να το ανακαλύψει μόνο περιηγούμενος σε έναν νεκρό φάκελο από έναν UPnP client. Ο περιορισμός του μενού πεδίων και των στόχων εφαρμογής στα πραγματικά δεδομένα της κατηγορίας καθιστά τις κενές διατάξεις μη κατασκευάσιμες.


N22 - Ομαδοποίηση podcast ανά έτος δημοσίευσης

Τι: η ημερομηνία δημοσίευσης κάθε επεισοδίου podcast διαβάζεται, οπότε μια διαδρομή περιήγησης podcast με επίπεδο Έτους ομαδοποιεί τα επεισόδια ανά έτος αντί να τα συμπτύσσει κάτω από ένα ενιαίο "Άγνωστο".

Γιατί: οι μεγάλες συνδρομές podcast γίνονται πλοηγήσιμες ανά έτος όπως και η υπόλοιπη βιβλιοθήκη, αντί να καταλήγει κάθε επεισόδιο σε μια αχρονολόγητη στοίβα επειδή το plugin δεν κοίταξε ποτέ την ημερομηνία δημοσίευσης ανά επεισόδιο.


N23 - Σύμπτυξη επιπέδων ομαδοποίησης με ένα αποτέλεσμα

Τι: ένα επίπεδο ομαδοποίησης που επιλύεται σε μία μόνο τιμή - ένα επίπεδο Τύπου Εγγραφής που εμφανίζει μόνο "LP" για έναν καλλιτέχνη που έφτιαξε μόνο LPs, ή ένα επίπεδο γραμμάτων με ένα μόνο γράμμα - παραλείπεται αυτόματα, οδηγώντας τον χρήστη απευθείας στο περιεχόμενό του.

Γιατί: η περιήγηση σε έναν φάκελο που περιέχει ακριβώς έναν φάκελο είναι καθαρή τριβή. Η σύμπτυξη του επιπέδου μονής επιλογής αφαιρεί το νεκρό κλικ χωρίς να αλλάζει αυτό που μπορεί να φτάσει ο χρήστης.


N24 - Ομαδοποίηση/αναζήτηση έτους έναντι του πεδίου ημερομηνίας του MusicBee

Τι: η συνθήκη έτους δεν αναζητά πλέον το πεδίο "Έτος" πλήρους ημερομηνίας του MusicBee με μια απλή τετραψήφια τιμή, και η σκληρά κωδικοποιημένη ψευδωνυμία πεδίου έτους έχει φύγει, οπότε κάθε πεδίο ομαδοποίησης επιλύεται πλέον γενικά από τον ορισμό της διαδρομής.

Γιατί: για βιβλιοθήκες των οποίων η ετικέτα Έτους περιέχει μια πλήρη ημερομηνία, η ομαδοποίηση ή η αναζήτηση ανά έτος προηγουμένως δεν επέστρεφε τίποτα - το τετραψήφιο ερώτημα δεν ταίριαζε ποτέ με το πεδίο πλήρους ημερομηνίας. Η αναζήτηση του σωστού πεδίου κάνει την ομαδοποίηση και την αναζήτηση έτους να βρίσκουν ξανά τα κομμάτια.


N25 - Ξεχωριστά πεδία ομαδοποίησης "Έτος" και "Έτος (yyyy)"

Τι: οι διαδρομές ομαδοποίησης και περιήγησης άλμπουμ εκθέτουν τώρα και τα δύο πεδία έτους του MusicBee - Έτος (η ετικέτα πλήρους ημερομηνίας) και Έτος (yyyy) (μόνο το τετραψήφιο έτος) - ώστε ο χρήστης να μπορεί να επιλέξει οποιοδήποτε κατά τον ορισμό μιας ομαδοποίησης άλμπουμ ή μιας διαδρομής περιήγησης.

Γιατί: τα δύο πεδία σημαίνουν διαφορετικά πράγματα στο MusicBee, και η σύμπτυξή τους έχανε αυτή τη διάκριση. Η εμφάνιση και των δύο επιτρέπει στον χρήστη να συγκεντρώσει κάθε κυκλοφορία ενός έτους μαζί (yyyy) ή να διατηρήσει την ακριβή σειρά ημερομηνίας (πλήρης ετικέτα Έτους), όπως επιθυμεί.


N32 - Καρφιτσωμένα φίλτρα και λίστες αναπαραγωγής ομαδοποιημένα κατά είδος στη ρίζα

Τι: ένα καρφιτσωμένο φίλτρο εμφανίζεται τώρα ακριβώς κάτω από τον φάκελο Φίλτρα στη ρίζα περιήγησης, και μια καρφιτσωμένη λίστα αναπαραγωγής ακριβώς κάτω από τον φάκελο Λίστες Αναπαραγωγής, αντί να συγκεντρώνονται όλες οι καρφίτσες σε ένα σωρό στο τέλος της ρίζας. Κάθε καρφιτσωμένη συντόμευση βρίσκεται με το δικό της είδος.

Γιατί: καθώς ένας χρήστης καρφιτσώνει περισσότερες συντομεύσεις, ένας ενιαίος σωρός από μικτά φίλτρα και λίστες αναπαραγωγής γίνεται πιο δύσκολο να σαρωθεί και διαχωρίζει κάθε συντόμευση από τον φάκελο στον οποίο ανήκει. Η ομαδοποίηση των καρφιτσωμένων στοιχείων κάτω από τη δική τους κατηγορία διατηρεί τη ρίζα ευανάγνωστη και κρατά κάθε συντόμευση δίπλα στα πράγματα στα οποία ανήκει.

Διάλογος ρυθμίσεων & συσκευασία

N26 - Διάλογος ρυθμίσεων με ενότητες

Τι: η σελίδα Προτιμήσεις απέκτησε μια διάταξη αριστερής πλοήγησης με ενότητες: Γενικά / Αναπαραγωγή / Βιβλιοθήκη / Προφίλ Συσκευών / Διαγνωστικά.

Γιατί: το αρχικό ήταν μια ενιαία ψηλή επίπεδη λίστα κάθε ρύθμισης - μια χαρά για τον προγραμματιστή που το έφτιαξε, μπερδευτικό για όλους τους άλλους. Η διαμόρφωση σε ενότητες ομαδοποιεί σχετικές επιλογές και κάνει τον διάλογο να μοιάζει περισσότερο με τις ρυθμίσεις σύγχρονων εφαρμογών.


Μετονομασία Assembly + plugin (χωρίς F-id - σημείωση συσκευασίας)

Τι: το μεταγλωττισμένο DLL ονομάζεται mb_UPnP_yaiol.dll και το plugin αναφέρει τον εαυτό του ως "MusicBee UPnP (yaiol)". Διαφορετικό από το αρχικό mb_Upnp.dll.

Γιατί: οι χρήστες μπορούν να εγκαταστήσουν το yaiol παράλληλα με το αρχικό plugin και να συγκρίνουν τη συμπεριφορά δίπλα-δίπλα.


Σύστημα ετικετών - εμφάνιση κατάστασης εκτέλεσης (μηχανισμός πίσω από το F40)

Τι: ένα γενικό μοτίβο UI για την εμφάνιση σημαντικών συνθηκών εκτέλεσης ως ορατές χρωματιστές ετικέτες στον διάλογο Ρυθμίσεων. Τρέχουσες περιπτώσεις:

  • ⚠ Μέγ. Συνδ. (N04) - ενεργοποιείται όταν το όριο μέγιστων συνδέσεων χτυπήθηκε τουλάχιστον μία φορά από την εκκίνηση του MusicBee. Κολλώδης σημαία συνεδρίας Plugin.MaxConnectionsHit. Ορίζεται μέσα στο WaitOnSendBarrier όταν δεν υπάρχει ελεύθερη θέση.
  • ⚠ Απαιτείται Επανεκκίνηση - ενεργοποιείται όταν μια αποθηκευμένη ρύθμιση χρειάζεται επανεκκίνηση του MusicBee για να τεθεί σε ισχύ. Κολλώδης σημαία συνεδρίας Plugin.RestartRequired. Ορίζεται στον χειριστή Αποθήκευσης του διαλόγου όταν η νέα αποθηκευμένη τιμή διαφέρει από το στιγμιότυπο εκτέλεσης (Plugin.activeMaxConnections, Plugin.activeServerPort, Plugin.activeIpAddress). Οι ρυθμίσεις που απαιτούν επανεκκίνηση περιορίζονται σε αυτές που πραγματικά δεν μπορούν να φορτωθούν εν θερμώ - παράμετροι σύνδεσης HTTP server και το SemaphoreSlim που δημιουργείται μία φορά κατά την αρχικοποίηση.

Γιατί: το αρχείο καταγραφής του plugin είναι μια χαρά για τεχνικούς χρήστες που κάνουν debugging, αλλά ένας μη τεχνικός χρήστης που κοιτάζει "η συσκευή ακούγεται λάθος" ή "η αναπαραγωγή είναι αργή" δεν θα ανοίξει ποτέ το Διαγνωστικά → Προβολή καταγραφής. Οι ετικέτες καταγράφουν τις περιπτώσεις όπου ο χρήστης πρέπει να γνωρίζει ότι κάτι συνέβη και το εμφανίζουν την επόμενη φορά που ανοίγει το plugin - ανακαλύψιμο χωρίς να διαβάσει τίποτα.

Επαναχρησιμοποιήσιμο για το μέλλον:

  • Εντοπίστηκε αναντιστοιχία προφίλ (ο user-agent της συσκευής δεν ταίριαξε ποτέ με κανένα προφίλ, επέστρεψε στο Generic).
  • Ενεργοποιήθηκε η αναστολή NextURI (F13 - απενεργοποιήθηκε η χωρίς κενά αναπαραγωγή για τη συνεδρία σε μια ασταθή συσκευή).
  • Η σάρωση βιβλιοθήκης απέτυχε / ήταν μερική.
  • Η σύνδεση του renderer χάθηκε εν μέσω συνεδρίας.
  • Οποιαδήποτε άλλη συνθήκη όπου "συνέβη μία φορά, ο χρήστης πρέπει να γνωρίζει" είναι καλύτερη από "καταγράφηκε σιωπηλά μεταξύ 1000 άλλων γραμμών".

Συμβάσεις υλοποίησης:

  • Οι ετικέτες των ετικετών βρίσκονται στο επίπεδο του διαλόγου (όχι μέσα σε κανένα πάνελ) ώστε να είναι ορατές ανεξάρτητα από το ποια ενότητα βρίσκεται ο χρήστης.
  • Τοποθετημένες στην κάτω σειρά κοντά στο Αποθήκευση/Ακύρωση (τρέχουσα: y=410 οριζόντια στοίβαξη).
  • Κάθε ετικέτα έχει μια αντίστοιχη κολλώδη σημαία συνεδρίας στο Plugin που γίνεται True όταν συμβαίνει η συνθήκη και επαναφέρεται μόνο με επανεκκίνηση του MusicBee.
  • Πόροι: <Condition>Badge (κείμενο ετικέτας, πρόθεμα με ⚠) + <Condition>BadgeTip (συμβουλή εργαλείου που εξηγεί την αιτία + τη λύση).
  • Για τις ετικέτες "αποθηκευμένη ρύθμιση χρειάζεται επανεκκίνηση", λάβετε ένα στιγμιότυπο εκτέλεσης στο Plugin.Initialise() και συγκρίνετε με το Settings.* μετά το Settings.SaveSettings() στον χειριστή Αποθήκευσης του διαλόγου.

N27 - Η ακύρωση απορρίπτει τις επεξεργασίες διαδρομής/προτύπου

Τι: οι επεξεργασίες που έγιναν σε διαδρομές και πρότυπα μέσα στον διάλογο ρυθμίσεων απορρίπτονται τώρα όταν ο χρήστης κάνει κλικ στο Ακύρωση, αντί να παραμένουν σιωπηλά εφαρμοσμένες, και οποιοδήποτε δεσμευμένο πρότυπο αφαιρέθηκε κατά τη διάρκεια της συνεδρίας αναδημιουργείται. (Τα πρότυπα διαφορετικά αποθηκεύονται ζωντανά καθώς επεξεργάζονται - δεν υπάρχει ξεχωριστό κουμπί Αποθήκευσης στην καρτέλα Διαδρομές.)

Γιατί: το Ακύρωση πρέπει να σημαίνει ακύρωση. Προηγουμένως ένας χρήστης που πειραματίστηκε με αλλαγές διαδρομής/προτύπου και υποχώρησε διαπίστωσε ότι οι αλλαγές είχαν ήδη δεσμευτεί, χωρίς τρόπο να τις αναιρέσει εκτός από το να τις ξανακάνει μία προς μία.


N28 - Κυριολεκτικές εμπορικές αμπέρ στο μενού επιλογής πεδίου

Τι: ένα πεδίο του οποίου το όνομα περιέχει "&" - π.χ. "Διάθεση & Πλαίσιο" - αποδίδει την εμπορική αμπέρ κυριολεκτικά στο μενού επιλογής πεδίου αντί να την καταπίνει ως πρόθεμα Alt-mnemonic.

Γιατί: τα ονόματα πεδίων με εμπορική αμπέρ εμφανίζονταν λανθασμένα (ο χαρακτήρας εξαφανιζόταν και το επόμενο γράμμα γινόταν επιταχυντής), καθιστώντας την καταχώρηση του μενού δύσκολο να αναγνωριστεί.


N29 - Σταθερός, αμετάφραστος τίτλος παραθύρου ρυθμίσεων

Τι: ο τίτλος του παραθύρου ρυθμίσεων είναι σταθερός στην επωνυμία "MusicBee UPnP Plugin" και δεν ποικίλλει πλέον με τη γλώσσα της διεπαφής· η συμβολοσειρά DialogTitle ανά γλώσσα αφαιρέθηκε από κάθε πακέτο τοπικής προσαρμογής.

Γιατί: ένας τίτλος παραθύρου που άλλαζε διατύπωση ανά γλώσσα ήταν μια μεταφράσιμη επιφάνεια χωρίς όφελος - ο τίτλος είναι ένα σήμα κατατεθέν. Η σταθεροποίησή του τον διατηρεί σταθερό και συνεπή παντού.

Τοπικοποίηση

Το αρχικό plugin είναι μόνο στα Αγγλικά. Αυτό το fork είναι πλήρως τοπικοποιήσιμο - κάθε συμβολοσειρά που βλέπει ο χρήστης περνάει μέσα από ένα πακέτο πόρων, και το plugin ανιχνεύει αυτόματα τη γλώσσα UI του MusicBee.

N30 - Διεπαφή χρήστη πολλαπλών γλωσσών (αναμένονται μεταφράσεις)

Τι: ο μηχανισμός τοπικοποίησης είναι πλήρης και διαθέσιμος. Το Localisation.vb διαβάζει την επιλεγμένη γλώσσα του MusicBee από το MusicBee3Settings.ini (ενδώνυμο <SystemLanguage>) και εφαρμόζει την αντίστοιχη κουλτούρα .NET στο νήμα, οπότε το My.Resources.Resources.* επιστρέφει την τοπικοποιημένη συμβολοσειρά. Κάθε ετικέτα/κουμπί/μήνυμα που βλέπει ο χρήστης είναι συνδεδεμένο με ένα κλειδί πόρου (στοιχεία ελέγχου σχεδιαστή μέσω ApplyDesignerExtras + sync-en-locale.js· συμβολοσειρές χρόνου εκτέλεσης όπως WarnPortInUse προστίθενται χειροκίνητα). Αυτό που δεν έχει γίνει ακόμα είναι η πραγματική μετάφραση: υπάρχει μόνο το αγγλικό πακέτο πηγής (Resources.resx) - τα δορυφορικά πακέτα για τις άλλες γλώσσες παράγονται σε μια ενιαία παρτίδα όταν το plugin είναι πλήρες σε χαρακτηριστικά (η τμηματική μετάφραση ενώ οι συμβολοσειρές εξακολουθούν να αλλάζουν σπαταλάει προσπάθεια).

Γλώσσες στόχοι (το σύνολο που προσφέρει το ίδιο το MusicBee, αντιστοιχισμένο 1:1 από το endonymToCulture ώστε το plugin να ακολουθεί αυτόματα τη γλώσσα του MusicBee):

Αραβικά (ar) Τσέχικα (cs) Γερμανικά (de) Ελληνικά (el)
Ισπανικά (es) Γαλλικά (fr) Ουγγρικά (hu) Ιταλικά (it)
Κορεάτικα (ko) Ολλανδικά (nl) Νορβηγικά (nb) Πολωνικά (pl)
Πορτογαλικά ΒΡ (pt-BR) Πορτογαλικά ΠΤ (pt-PT) Σουηδικά (sv) Τουρκικά (tr)
Ουκρανικά (uk) Ρωσικά (ru) Ιαπωνικά (ja) Απλοποιημένα Κινεζικά (zh-CN)
Παραδοσιακά Κινεζικά (zh-TW) Αγγλικά (en, πηγή)

Πολιτική παραλλαγών (σύμφωνα με τον κανόνα τοπικής ρύθμισης του χώρου εργασίας): τα PT και ZH χωρίζονται σε διακριτά πακέτα επειδή το λεξιλόγιο/σενάριο αποκλίνει πραγματικά (pt-BR/pt-PT, zh-CN/zh-TW). Το EN είναι ένα ενιαίο πακέτο - το "English(US)" του MusicBee (en-US) επιστρέφει στο en μέσω της αλυσίδας κουλτούρας του .NET, οπότε δεν παράγεται ξεχωριστό πακέτο US. Τα ES και FR είναι ομοίως μονής τοπικής ρύθμισης.

Γιατί: οι ρυθμίσεις ενός UPnP plugin ("μη χρησιμοποιείτε ακατέργαστο PCM", "επιβάλλετε little-endian PCM", προειδοποιήσεις επαναφοράς θύρας) είναι αρκετά κρυπτικές στη μητρική γλώσσα κάποιου. Η παρακολούθηση της γλώσσας UI του ίδιου του MusicBee - αντί της επιβολής των Αγγλικών - είναι η διαφορά μεταξύ ενός εργαλείου που ένας μη-Αγγλόφωνος χρήστης μπορεί να διαμορφώσει και ενός που δεν μπορεί. Κανένα upstream δεν το επιχείρησε αυτό.


N31 - Ο σύνδεσμος βοήθειας ανοίγει στην πλήρη γλώσσα διεπαφής

Τι: το άνοιγμα του συνδέσμου Βοήθειας από το plugin σέβεται την πλήρη γλώσσα διεπαφής του χρήστη (π.χ. pt-BR, zh-CN) αντί να συμπτύσσεται στην βασική γλώσσα, και στέλνει ένα σαφέστερο αναγνωριστικό ελέγχου ενημέρωσης.

Γιατί: ένας χρήστης που χρησιμοποιούσε το MusicBee σε μια περιφερειακή παραλλαγή (Πορτογαλικά Βραζιλίας, Απλοποιημένα Κινεζικά) οδηγούνταν στη σελίδα βοήθειας της βασικής γλώσσας. Η μεταφορά της πλήρους κουλτούρας τους οδηγεί στη σελίδα βοήθειας στην ακριβή γλώσσα που χρησιμοποιούν.

Διορθώσεις και βελτιώσεις στο αρχικό plugin

Βασικό πρωτόκολλο & αναπαραγωγή

F01 - Ενημερωμένα προεπιλεγμένα προφίλ συσκευών DLNA

Τι: παρέχει νέα προεπιλεγμένα προφίλ για PlayStation 4, Xbox 360/One, και σύγχρονο BubbleUPnP, με σημαίες δυνατοτήτων (ρυθμοί δειγματοληψίας, βάθη bit, κωδικοποιητές) που αντικατοπτρίζουν τι υποστηρίζουν πραγματικά αυτές οι συσκευές σήμερα.

Γιατί: οι προεπιλογές του αρχικού plugin ήταν παγωμένες περίπου το 2014. Τα PS4/Xbox/BubbleUPnP έχουν έκτοτε αποκτήσει υποστήριξη ήχου υψηλής ανάλυσης. Εκτός συσκευασίας, μια νέα εγκατάσταση παίζει καλύτερα στην κατηγορία σε αυτές τις συσκευές χωρίς ο χρήστης να αγγίξει τις ρυθμίσεις προφίλ συσκευής.


F02 - Συσκευές ελέγχου που διαφημίζουν MediaRenderer:3

Τι: το plugin ερευνά την περιγραφή υπηρεσίας UPnP ενός renderer για να αποφασίσει αν το MusicBee μπορεί να το οδηγήσει. Το αρχικό ταίριαζε μόνο με το urn:schemas-upnp-org:device:MediaRenderer:1. Οι σύγχρονες συσκευές διαφημίζουν :2 ή :3. Το F02 διευρύνει την αντιστοίχιση.

Γιατί: χωρίς αυτό, οι πρόσφατες μονάδες Sonos / WiiM / Eversolo απλά δεν εμφανίζονται ως στόχοι στη λίστα συσκευών "Αναπαραγωγή σε" του MusicBee - παρόλο που μιλούν το ίδιο πρωτόκολλο. Μια απλή διόρθωση αντιστοίχισης προθέματος συμβολοσειράς ξεκλειδώνει ολόκληρη τη σύγχρονη γενιά συσκευών.


F03 - Επιλογή "Επιβολή εγγενούς ροής" ανά προφίλ (προεπιλογή ON)

Τι: όταν επιλεγεί, το plugin στέλνει τα αρχικά bytes του αρχείου στη συσκευή χωρίς μετακωδικοποίηση, χωρίς DSP, χωρίς επεξεργασία ReplayGain. Απλώς το αρχικό αρχείο που επέλεξε ο χρήστης, byte-προς-byte (εκτός από το HTTP framing).

Γιατί: σύμφωνα με μαρτυρίες σε φόρουμ, αυτό είναι το μεγαλύτερο κέρδος στην ποιότητα αναπαραγωγής. Οι χρήστες hi-fi που αγοράζουν ακριβούς renderers θέλουν ρητά bit-perfect έξοδο· οποιαδήποτε παρέμβαση DSP ακυρώνει το νόημα. Προεπιλογή ON επειδή οι περισσότερες σύγχρονες συσκευές χειρίζονται όποιον κωδικοποιητή τους έριξε ο χρήστης, και το ReplayGain/EQ πρέπει να είναι opt-in. Είναι ανά προφίλ, οπότε μπορείτε να διατηρήσετε τη μετακωδικοποίηση για ένα παλιό Xbox ενώ στέλνετε εγγενή ροή σε έναν hi-fi DAC.


F04 - "Επιβολή μετακωδικοποίησης" ανά προφίλ

Τι: παράκαμψη ανά προφίλ που αναγκάζει κάθε ροή σε αυτή τη συσκευή να περάσει από τον μετακωδικοποιητή, ανεξάρτητα από την υποστήριξη εγγενούς κωδικοποιητή. Το αντίστροφο του F03 (ForceNativeStream). Αμοιβαία αποκλειόμενο με το F03 - το UI απενεργοποιεί αυτόματα το άλλο όταν ενεργοποιηθεί ένα από τα δύο.

Γιατί: ένας ενιαίος καθολικός διακόπτης θα ήταν αντιφατικός με το ForceNativeStream ανά προφίλ (F03). Πραγματική περίπτωση: η συσκευή Α είναι ένας hi-fi DAC που θέλει bit-perfect εγγενείς ροές· η συσκευή Β είναι ένας παλιός AV receiver που πνίγεται στο FLAC. Με έναν καθολικό διακόπτη ο χρήστης πρέπει να επιλέξει - με κόστος την άλλη συσκευή. Με ανά προφίλ κάθε συσκευή παίρνει τη σωστή απάντηση.

Υλοποίηση:

  • StreamingProfile.ForceTranscoding As Boolean = False.
  • Το σχήμα επιμονής αυξήθηκε στην έκδοση 9. Τα αρχεία προ-v9 φορτώνουν την παλιά καθολική τιμή μία φορά και την αντιγράφουν σε όλα τα προφίλ, διατηρώντας την παλιά συμπεριφορά μέσω της αναβάθμισης.
  • UI: αφαιρέθηκε από το πάνελ Διαγνωστικά, προστέθηκε στην ενότητα Προφίλ Συσκευών δίπλα στο ForceNativeStream. Χειριστές αμοιβαίου αποκλεισμού δύο κατευθύνσεων (CheckedChanged σε κάθε ένα καταργεί την εγγραφή του άλλου πριν την αναστροφή, για να αποφευχθεί ένας άπειρος βρόχος).
  • Σημείο απόφασης: Settings.ForceTranscodingstreamingProfile.ForceTranscoding στο WriteAudioFileDIDL.

F05 - "Επιβολή little-endian PCM" ανά προφίλ

Τι: οι ροές PCM (τύποι mime L16/L24) είναι big-endian σύμφωνα με τις προδιαγραφές. Ορισμένες συσκευές λανθασμένα αναμένουν little-endian και αναπαράγουν λευκό θόρυβο όταν τους δίνονται σωστά big-endian δεδομένα. Το F05 αλλάζει τη σειρά byte ανά προφίλ.

Γιατί: χωρίς αυτό, ορισμένες συσκευές παράγουν έναν τοίχο στατικού θορύβου. Το σύμπτωμα είναι δραματικό και η αιτία αόρατη χωρίς γνώση της κωδικοποίησης PCM - ο διακόπτης δίνει στους χρήστες μια λύση δοκιμής και σφάλματος.


F06 - "Μη χρήση Raw PCM" ανά προφίλ

Τι: όταν η συσκευή ισχυρίζεται ότι υποστηρίζει raw PCM, το plugin το χρησιμοποιεί. Ορισμένες συσκευές ψεύδονται - δέχονται το SOAP handshake αλλά παραμορφώνουν τα πραγματικά raw PCM δεδομένα, ενώ χειρίζονται σωστά το PCM τυλιγμένο σε ένα κοντέινερ WAVE. Το F06 επιβάλλει PCM-over-Wave ανεξάρτητα από το τι διαφημίζει η συσκευή.

Γιατί: συγκεκριμένα μοντέλα Marantz - διαφημίζουν raw PCM αλλά μόνο το WAVE λειτουργεί. Χωρίς αυτό, οι raw PCM ροές βγαίνουν παραμορφωμένες, χωρίς μήνυμα σφάλματος για να το υποδείξει.


F07 - "Μήκος περιεχομένου" ανά προφίλ

Τι: ποια τιμή να στείλετε στην κεφαλίδα HTTP Content-Length. Τέσσερις επιλογές:

  • Προεπιλογή - πραγματικός αριθμός byte όταν είναι γνωστός, παράλειψη όταν είναι άγνωστος.
  • Κανένα - ποτέ μην στέλνετε την κεφαλίδα (μόνο κωδικοποίηση με κομμάτια).
  • Μόνο PCM - στέλνετε μόνο για raw PCM· παραλείψτε για όλα τα άλλα.
  • Σταθερό - στέλνετε UInt32.MaxValue - 8192 (ένας φρουρός για "τεράστιο άγνωστο μήκος").

Γιατί: οι συσκευές UPnP/DLNA διαφέρουν πολύ στον τρόπο που αντιδρούν στο Content-Length. Κάποιες χρειάζονται έναν ακριβή αριθμό, κάποιες το μισούν στις ροές, κάποιες χρειάζονται έναν φρουρό "πραγματικά μεγάλη" τιμή για να συνεχίσουν την προσωρινή αποθήκευση. Αυτό αργότερα διευρύνθηκε από μόνο PCM σε όλες τις μορφές εξόδου επειδή τα ίδια προβλήματα εμφανίστηκαν σε μετακωδικοποιημένες ροές MP3/AAC.


F08 - "Μη διαγραφή NextURI" ανά προφίλ

Τι: κανονικά το plugin καθαρίζει το NextURI της συσκευής όταν η ουρά αδειάζει (στέλνοντας SetNextAVTransportURI με κενό URL). Ορισμένες συσκευές (ιδίως η Denon) ερμηνεύουν ένα κενό NextURI ως "σταμάτα τα πάντα" και διακόπτουν αμέσως την αναπαραγωγή. Το F08 εμποδίζει το plugin να το καθαρίσει ποτέ.

Γιατί: χωρίς αυτό, οι κάτοχοι Denon βιώνουν τη συσκευή να διακόπτει εν μέσω κομματιού όταν η ουρά αδειάζει. Με το F08 επιλεγμένο, η συσκευή διατηρεί το παλιό NextURI στη μνήμη (αβλαβές - απλώς αντικαθίσταται την επόμενη φορά που κάτι μπαίνει στην ουρά).


F09 - FLAC ως μορφή εξόδου μετακωδικοποίησης

Τι: το αναπτυσσόμενο μενού μορφής μετακωδικοποίησης στα Προφίλ Συσκευών προσφέρει τώρα FLAC μαζί με PCM 16/24, MP3, AAC, Ogg. Η επιλογή του δρομολογεί τον κωδικοποιητή BASS μέσω της τυπικής γραμμής εντολών μετατροπής FLAC του MusicBee (ο ίδιος μηχανισμός που χρησιμοποιούν ήδη τα MP3/AAC/Ogg).

Γιατί: για συσκευές που χειρίζονται καλά το FLAC αλλά δεν μπορούν να αποκωδικοποιήσουν τον κωδικοποιητή πηγής (π.χ. ένα Eversolo που λαμβάνει τη βιβλιοθήκη WMA του MusicBee μετατρεμμένη σε FLAC), αυτό διατηρεί την ποιότητα χωρίς απώλειες όπου τα MP3/AAC θα απέρριπταν δεδομένα ήχου. Ξεκλειδώνει το N02 (έλεγχος υπομίξης 5.1), το οποίο δεν μπορούσε να αντιμετωπιστεί χωρίς μια επιλογή μετακωδικοποίησης χωρίς απώλειες.

Υλοποίηση: προσθήκη μιας γραμμής στο μπλοκ Select Case Codec του Encoder.StartEncode - το FLAC ενώνεται με τα MP3/AAC/Ogg στον κλάδο που οδηγείται από τη γραμμή εντολών. Το αναπτυσσόμενο μενού UI αποκτά το "FLAC" ως 6η επιλογή. Η αντιστοίχιση φόρτωσης/αποθήκευσης στο SettingsDialog επεκτείνεται για να αναγνωρίζει FileCodec.FlacSelectedIndex = 5. Ο τύπος Mime, ο τύπος DLNA και η λειτουργία κωδικοποίησης είχαν ήδη καλωδιωθεί στα ItemManager.GetMimes / GetDlnaType / GetEncodeFeature από προηγούμενη εργασία (F21, F26).


Χωρίς κενά (SetNextAVTransportURI)

F10 - SetNextAVTransportURI / NextURI core

Τι: πραγματική αναπαραγωγή χωρίς κενά. Όταν η συσκευή διαφημίζει υποστήριξη για SetNextAVTransportURI στην περιγραφή υπηρεσίας UPnP της, το plugin προ-εντάσσει το επόμενο κομμάτι στη συσκευή πριν τελειώσει το τρέχον. Η συσκευή μεταβαίνει εσωτερικά χωρίς ακουστικό κενό μεταξύ των κομματιών - αυτό που ακούτε σε ένα CD player. Αυτό δεν είναι το hack "συνεχής ροή" (το οποίο συνενώνει τα πάντα σε μια μακρά ροή και χάνει τα μεταδεδομένα ανά κομμάτι).

Γιατί: το κορυφαίο χαρακτηριστικό Tier-2. Τα άλμπουμ που ηχογραφούνται ως συνεχής ζωντανή παράσταση (ζωντανές ηχογραφήσεις, κλασικές κινήσεις, DJ sets) ακούγονται λάθος όταν υπάρχει μισό δευτερόλεπτο σιωπής μεταξύ των κομματιών. Η σωστή επίλυση αυτού είναι ένα κορυφαίο χαρακτηριστικό, τώρα σε αυτό το fork.

Σημειώσεις: ο ήχος που βρίσκεται στην ουρά εξυπηρετείται μέσω του HTTP server του plugin χρησιμοποιώντας streamHandle=0 (λειτουργία ανάκτησης βιβλιοθήκης), πράγμα που σημαίνει ότι ο μηχανισμός ήχου του MusicBee δεν συμμετέχει στο κομμάτι που βρίσκεται στην ουρά. Αντιστάθμιση: τα εφέ ReplayGain/DSP/EQ δεν εφαρμόζονται στο επόμενο κομμάτι. Αποδεκτό όταν είναι ενεργοποιημένη η "επιβολή εγγενούς ροής" (η προεπιλογή).


F11 - "Απενεργοποίηση υποστήριξης NextURI" ανά προφίλ

Τι: ακόμα κι αν μια συσκευή διαφημίζει SetNextAVTransportURI, αυτό το πλαίσιο ελέγχου αναγκάζει το plugin να αγνοήσει αυτή τη διαφήμιση και να επιστρέψει στην αναπαραγωγή ενός κομματιού κάθε φορά.

Γιατί: ορισμένες συσκευές διαφημίζουν NextURI αλλά έχουν μια προβληματική υλοποίηση (κρασάρισμα, μισές μεταβάσεις, κολλήματα). Αντί να κάνουμε reverse-engineer κάθε χαλασμένη συσκευή, ο χρήστης παίρνει έναν διακόπτη "απλά απενεργοποίησέ το εδώ".


F12 - Κύκλος ζωής NextURI στη λίστα αναπαραγωγής

Τι: όταν το MusicBee ενεργοποιεί το NowPlayingListChanged, το plugin επανεκτιμά τι πρέπει να μπει στην ουρά για μετάβαση χωρίς κενά. Ζητά από το MusicBee το νέο "επόμενο" κομμάτι μέσω NowPlayingList_GetNextIndex(1) + NowPlayingList_GetListFileUrl, συγκρίνει με αυτό που βρίσκεται αυτή τη στιγμή στην ουρά της συσκευής (παρακολουθείται μέσω του νέου πεδίου nextPlaySourceUrl), και το ξαναβάζει στην ουρά αν άλλαξε (ή καθαρίζει την ουρά αν το MusicBee λέει ότι δεν υπάρχει επόμενο κομμάτι).

Γιατί: χωρίς το F12, η συσκευή συνέχιζε να παίζει ένα παλιό NextURI όταν ο χρήστης αφαιρούσε/αναδιάτασσε το κομμάτι στην ουρά. Αυτό ιστορικά χρειάστηκε αρκετές επαναλήψεις επειδή κάθε μετάλλαξη λίστας χρειάζεται διαφορετικό χειρισμό - εμείς απλοποιήσαμε εμπιστευόμενοι το NowPlayingList_GetNextIndex (το οποίο ήδη σέβεται την αναπαραγωγή τυχαίας σειράς και την επανάληψη όλων), οπότε όλες οι παραλλαγές περνούν από την ίδια σύγκριση.

Υλοποίηση:

  • Το νέο πεδίο nextPlaySourceUrl αποθηκεύει το URL της βιβλιοθήκης MusicBee του κομματιού που βρίσκεται στην ουρά (το URL ροής με επίθημα χειρισμού δεν είναι συγκρίσιμο με μια διαδρομή βιβλιοθήκης).
  • Νέα Public Sub RefreshQueuedNextUri() στο MediaRendererDevice. Τρία αποτελέσματα: κανένα NextURI στην ουρά → no-op· το NextURI στην ουρά ταιριάζει με το νέο "επόμενο" → no-op· το NextURI στην ουρά διαφέρει → καλέστε το QueueNext με το νέο URL (ή QueueNext("") για εκκαθάριση - το οποίο σέβεται το F08 DoNotClearNextUri).
  • Καλωδιωμένο στο Plugin.ReceiveNotification κάτω από το NotificationType.NowPlayingListChanged.

F13 - Αναστολή αποτυχίας NextURI

Τι: μετά από 4 διαδοχικές αποτυχίες SetNextAVTransportURI στην ίδια συσκευή, το plugin απενεργοποιεί την αναπαραγωγή χωρίς κενά για αυτή τη συσκευή μέχρι να επανεκκινηθεί το MusicBee.

Γιατί: αν μια συσκευή είναι πραγματικά χαλασμένη για το NextURI (διαλείποντα σφάλματα SOAP, δυσλειτουργίες δικτύου), το plugin θα συνέχιζε να προσπαθεί σε κάθε κομμάτι. Το F13 σταματά τον θόρυβο και επιστρέφει σιωπηλά στην αναπαραγωγή ενός κομματιού κάθε φορά.


F14 - Ενσωμάτωση λειτουργίας επανάληψης + NextURI

Τι: το F14 χωρίζεται σε δύο περιπτώσεις που χειρίζονται στον ανιχνευτή μετάβασης F15 στο OnAvTransportStatusCheck:

  • Επανάληψη Όλων: Το MusicBee περνάει το σωστό URL "wrap" (κομμάτι 1 στο τέλος της λίστας) στο Plugin.QueueNext από μόνο του. Δεν χρειάζεται ειδική λογική plugin - η συσκευή μεταβαίνει σε αυτό και ο ανιχνευτής F15 καλεί το Player_PlayNextTrack ως συνήθως, το οποίο επαναφέρει τον δείκτη NPL του MusicBee στο 0.
  • Επανάληψη Ενός: Το MusicBee περνάει το ΙΔΙΟ URL κομματιού στο Plugin.QueueNext. Η συσκευή μεταβαίνει σε αυτό (νέος χειριστής ροής, ίδια πηγή). Ο ανιχνευτής F15 τώρα ερωτά το Player_GetRepeat() - αν είναι RepeatMode.One, παραλείπει την κλήση Player_PlayNextTrack ώστε το MusicBee να μην προωθήσει τον δείκτη NPL μακριά από το κομμάτι που επαναλαμβάνεται.

Γιατί: χωρίς την παράλειψη Επανάληψης Ενός, η κλήση του Player_PlayNextTrack κατά τη μετάβαση χωρίς κενά θα προωθούσε το MusicBee στο επόμενο κομμάτι της λίστας (η Επανάληψη Ενός επηρεάζει μόνο την αυτόματη προώθηση στο τέλος του κομματιού στο UI του player - το Επόμενο Κομμάτι κινείται πάντα προς τα εμπρός), αντιφάσκοντας με το τι σημαίνει Επανάληψη Ενός.

Προσοχή στον αριθμό αναπαραγωγών: στην Επανάληψη Ενός, η αύξηση του αριθμού αναπαραγωγών εξαρτάται από το MusicBee 3.7.9563+ που παρατηρεί την επαναλαμβανόμενη αναπαραγωγή. Οι παλαιότερες εκδόσεις του MusicBee αναπαράγουν σωστά την επανάληψη χωρίς κενά αλλά χάνουν την αύξηση του αριθμού αναπαραγωγών. Τεκμηριωμένο· δεν είναι εμπόδιο.


F15 - Μηχανή κατάστασης ανίχνευσης μετάβασης κομματιού

Τι: όταν η συσκευή μεταβαίνει εσωτερικά από το τρέχον κομμάτι στο NextURI, το plugin πρέπει να το παρατηρήσει και να πει στο MusicBee να προωθήσει τον δείκτη αναπαραγωγής του. Διαφορετικά, το MusicBee νομίζει ότι βρίσκεται ακόμα στο προηγούμενο κομμάτι και οι μετρήσεις αναπαραγωγής / UI / scrobbling αποκλίνουν.

Υλοποίηση: ελέγχει το GetPositionInfo.TrackURI σε κάθε χτύπο του χρονομέτρου κατάστασης. Όταν το αναφερόμενο URI ταιριάζει με αυτό που βάλαμε στην ουρά μέσω NextURI, καλούμε το Player_PlayNextTrack στο MusicBee και ορίζουμε το suppressNextSoapCall ώστε το προκύπτον PlayToDevice να μην ξαναστείλει το SetAVTransportURI (το οποίο θα διέκοπτε την αναπαραγωγή χωρίς κενά).

Γιατί: χωρίς το F15 η συσκευή παίζει το επόμενο κομμάτι αλλά το UI του MusicBee λέει ότι βρίσκεται ακόμα στο προηγούμενο. Μπερδευτικό, χαλάει το scrobbling, χαλάει την παρακολούθηση του αριθμού αναπαραγωγών. Η ανίχνευση μετάβασης κομματιού χρειάζεται μακρά, ανά renderer επανάληψη επειδή κάθε μάρκα renderer έχει τις δικές της ιδιορρυθμίες στο πότε αναφέρει την αλλαγή URI (κάποια αναφέρουν πρώτα TRANSITIONING, κάποια πηδούν κατευθείαν στο PLAYING με νέο URI, κάποια έχουν ένα σύντομο STOPPED ενδιάμεσα).

Σημειώσεις: η πρώτη μας έκδοση λειτουργεί στον renderer BubbleUPnP. Οι περιπτώσεις άκρων ανά συσκευή παραμένουν στο B6.


F16 - Διόρθωση Pop-on-gapless-transition

Τι: το pop συμβαίνει όταν η μορφή πηγής (ρυθμός δειγματοληψίας / κανάλια / κωδικοποιητής) του κομματιού που βρίσκεται στην ουρά διαφέρει από το κομμάτι που αναπαράγεται αυτή τη στιγμή, αναγκάζοντας το DAC της συσκευής να κλειδώσει ξανά στη μετάβαση. Το F16 προσθέτει ένα διαγνωστικό NextUri:FormatChange που ενεργοποιείται κατά τη στιγμή της ουράς κάθε φορά που οι μορφές διαφέρουν, ονομάζοντας και τις δύο πλευρές - έτσι οι χρήστες που ακούν pops μπορούν να συσχετίσουν.

Το διαγνωστικό υποδεικνύει επίσης την αντιμετώπιση: επιλέξτε ForceTranscoding στο προφίλ της συσκευής. Αυτό ομογενοποιεί κάθε κομμάτι σε έναν ενιαίο κωδικοποιητή/ρυθμό δειγματοληψίας/βάθος bit μετακωδικοποίησης, εξαλείφοντας εντελώς τη διαφορά μορφής πηγής.

Γιατί αναβλήθηκε για την πραγματική διόρθωση μετακωδικοποίησης-για-αντιστοίχιση: η δομική διόρθωση (μετακωδικοποίηση του κομματιού που βρίσκεται στην ουρά για να ταιριάζει με τη μορφή του κομματιού που αναπαράγεται) απαιτεί αλλαγές στο σχήμα URL του HTTP server του plugin - επί του παρόντος το /encode/{id}0.{ext} εξυπηρετεί το κομμάτι που βρίσκεται στην ουρά εγγενώς. Μια μελλοντική v2 του F16 θα πρόσθετε διαδρομές /encode/{id}0_{rate}_{depth}.{ext} ανά μορφή και θα τις συνέδεε μέσω του κωδικοποιητή. Αυτή είναι μια μεγαλύτερη αρχιτεκτονική αλλαγή που αξίζει να γίνει αν μια πραγματική συσκευή εμφανίζει το pop αφού το ForceTranscoding δεν επαρκεί.

Υλοποίηση σήμερα:

  • Το πεδίο lastSourceUrl παρακολουθεί το URL της πηγής που αναπαράγεται αυτή τη στιγμή.
  • Το QueueNext διαβάζει το FilePropertyType.SampleRate/Channels/Kind τόσο για το τρέχον όσο και για τα κομμάτια που βρίσκονται στην ουρά και καταγράφει το NextUri:FormatChange σε περίπτωση αναντιστοιχίας.

F17 - Επανασυγχρονισμός γραμμής προόδου μετά από αναζήτηση

Τι: η συνάρτηση Seek() καλούσε ήδη το GetPlayPositionInformation() μετά από ένα επιτυχημένο Seek SOAP, το οποίο διορθώνει την περίπτωση "καθόλου επανασυγχρονισμός". Το F17 κλείνει την υπόλοιπη απόκλιση έως 1 δευτερόλεπτο που προκαλείται από την κβαντοποίηση RelTime του UPnP σε 1 δευτερόλεπτο: όταν η αναφερόμενη θέση της συσκευής στρογγυλοποιείται εντός 1 δευτερολέπτου από τον αιτούμενο στόχο του χρήστη, το plugin εμπιστεύεται τώρα την υπο-δευτερολεπτο-ακριβή τιμή του χρήστη αντί για την περικοπή της συσκευής. Μόνο όταν η συσκευή αναφέρει κάτι δραματικά διαφορετικό (>1 δευτερόλεπτο απόκλιση) χρησιμοποιούμε την τιμή της (η αναζήτηση προσγειώθηκε κάπου αλλού από ό,τι ζητήθηκε, π.χ. snap-to-keyframe σε ορισμένους κωδικοποιητές).

Γιατί: χωρίς αυτό, η αναζήτηση στο 2:30.500 αγκυροβολημένη στην αναφορά "2:30" της συσκευής θα έκανε τη γραμμή προόδου να εμφανίζει ~500ms πίσω από την πραγματικότητα. Μετά το F17 η γραμμή ταιριάζει με την πρόθεση του χρήστη για την κοινή περίπτωση σάρωσης εντός κομματιού, και εξακολουθεί να σέβεται την αναφορά της συσκευής για την εξαίρεση snap-to-keyframe.


F18 - Συνεχής ροή / αλληλοσύνδεση NextURI

Τι: δύο αλληλοσυνδέσεις είναι τώρα σε ισχύ:

  1. Χρόνος εκτέλεσης: Το QueueNext επιστρέφει νωρίς False όταν το Settings.ContinuousOutput είναι ενεργοποιημένο. Η συνεχής ροή είναι ο δικός της μηχανισμός χωρίς κενά (μία μακρά συνενωμένη ροή)· η αποστολή SetNextAVTransportURI πάνω από αυτήν μπερδεύει τη συσκευή σχετικά με το αν κάθε κομμάτι είναι ένα διακριτό URI ή μέρος της συνεχούς ροής.
  2. UI: όταν ο χρήστης επιλέγει το καθολικό πλαίσιο ελέγχου συνεχούς ροής, το forceNativeStream του προφίλ που εμφανίζεται αυτή τη στιγμή απενεργοποιείται αυτόματα. Η συνεχής ροή μετακωδικοποιεί πάντα, οπότε η επιβολή εγγενούς ροής είναι χωρίς νόημα σε συνδυασμό.

Γιατί: αποτρέπει τον χρήστη από το να ενεργοποιήσει δύο αντικρουόμενους μηχανισμούς χωρίς κενά ταυτόχρονα. Χωρίς το F18, η συσκευή θα λάμβανε τόσο ένα URI συνεχούς ροής όσο και ένα NextURI για κάθε επόμενο κομμάτι, με απροσδιόριστη συμπεριφορά ανάλογα με τον renderer.


F19 - Αγνοούνται τα σφάλματα κενών NextURI

Τι: όταν καλείται το SetNextAVTransportURI με κενό URL (π.χ. τελευταίο κομμάτι στη λίστα), ορισμένες συσκευές επιστρέφουν ένα σφάλμα SOAP. Το F19 τα καταπίνει σιωπηλά - καταγράφονται αλλά δεν διαδίδονται ως σφάλματα.

Γιατί: η συνθήκη "δεν υπάρχει επόμενο κομμάτι" είναι φυσιολογική, όχι σφάλμα. Η αντιμετώπισή της ως μοιραίας μολύνει το αρχείο καταγραφής και (σε ορισμένες ροές) ενεργοποιεί καταιγίδες επανάληψης.


Τύποι Mime & μεταδεδομένα DLNA

F20 - MP3 mime → audio/mpeg

Τι: ο συμβατός με τα πρότυπα τύπος mime MP3 είναι audio/mpeg, όχι audio/mp3. Ο τελευταίος είναι μια κοινή λανθασμένη ονομασία που οι περισσότερες συσκευές ανέχονται, αλλά οι αυστηρότεροι renderers τον απορρίπτουν.

Γιατί: διορθώνει σιωπηλά την αναπαραγωγή σε αυστηρότερες συσκευές που ακολουθούν το πρότυπο. Η βάση κώδικα yaiol το είχε ήδη σωστό· δεν χρειάστηκε αλλαγή.


F21 - Σειρά τύπων Mime: πρώτα η μη-x- παραλλαγή

Τι: όταν μια συσκευή διαφημίζει τόσο audio/flac όσο και audio/x-flac, το plugin επιστρέφει πρώτα την μη-x- παραλλαγή. Το ίδιο ισχύει για οποιονδήποτε κωδικοποιητή με τυπικούς και πειραματικούς τύπους mime.

Γιατί: το πρόθεμα x- σηματοδοτεί πειραματικούς/ανεπίσημους τύπους mime. Ορισμένοι renderers συμπεριφέρονται καλύτερα με την τυπική μορφή. Μικρή αναδιάταξη, πραγματικός αντίκτυπος.


F22 - Υποστήριξη τύπου mime Opus

Τι: αναγνωρίζει το Opus ως κωδικοποιητή ήχου με δυνατότητα ροής· στέλνει τύπο mime audio/opus κατά την εξυπηρέτηση κομματιών Opus.

Γιατί: το Opus είναι πλέον κοινό (σύγχρονος κωδικοποιητής συμβιβασμού ομιλίας/μουσικής). Χωρίς το F22 το plugin θα αρνούνταν να μεταδώσει αρχεία Opus ακόμη και σε συσκευές που τα χειρίζονται.


F23 - Υποστήριξη αρχείων πηγής Monkey Audio (APE)

Τι: αναγνωρίζει τα αρχεία .ape ως έγκυρο κωδικοποιητή πηγής για ροή/μετακωδικοποίηση.

Γιατί: το APE είναι μια μορφή χωρίς απώλειες με μια εξειδικευμένη αλλά πιστή βάση χρηστών. Η προσθήκη του κοστίζει λίγο και ξεκλειδώνει τη βιβλιοθήκη για αυτούς τους χρήστες.


F24 - Επαναφορά mime AAC / ALAC

Τι: αν μια συσκευή υποστηρίζει AAC ή ALAC αλλά δεν τα διαφημίζει ρητά στην περιγραφή υπηρεσίας UPnP της, το plugin τα προσφέρει ούτως ή άλλως ως επαναφορά.

Γιατί: αρκετές συσκευές που χειρίζονται καλά το AAC ξέχασαν να το αναφέρουν στο XML δυνατοτήτων τους. Χωρίς το F24 το plugin δεν θα προσπαθούσε καν, αναγκάζοντας τη μετακωδικοποίηση. Με το F24 το plugin προσπαθεί και αφήνει τη συσκευή να το χειριστεί εγγενώς αν μπορεί.


F25 - Σημαία τύπου DLNA για εγγενείς + κωδικοποιημένες ροές WAV

Τι: η σημαία τύπου DLNA (ένα αναγνωριστικό προφίλ όπως LPCM, WAVE, MP3) πρέπει να ταιριάζει με αυτό που λαμβάνει η συσκευή. Το F25 διασφαλίζει ότι οι εγγενείς ροές και οι κωδικοποιημένες ροές WAV επισημαίνονται σωστά.

Γιατί: ο μη ταιριαστός τύπος DLNA προκαλεί σε ορισμένες συσκευές να αρνηθούν εντελώς την αναπαραγωγή ή να εφαρμόσουν τον λάθος αποκωδικοποιητή.


F26 - Κεφαλίδα DLNA για αρχεία FLAC

Τι: οι ροές FLAC λαμβάνουν το σωστό αναγνωριστικό προφίλ DLNA στις κεφαλίδες τους.

Γιατί: χωρίς αυτό, ορισμένες συσκευές που υποστηρίζουν FLAC δεν αναγνωρίζουν τη ροή ως τέτοια.


F27 - Διόρθωση υπολογισμού bitrate στα μεταδεδομένα

Τι: το res@bitrate της συνεχούς ροής υπολογιζόταν ως (sampleRate * channels * bitsPerSample) / 1000 - kbps, με απόκλιση κατά έναν παράγοντα ~125 από την προδιαγραφή UPnP DIDL που ορίζει το χαρακτηριστικό ως bytes ανά δευτερόλεπτο. Τώρα διαιρείται με το 8 αντί για το 1000.

Γιατί: λανθασμένη εμφάνιση bitrate στη συσκευή - κοσμητική στους περισσότερους renderers, αλλά κάποιοι διαθέτουν buffer ροής από την τιμή και κολλάνε σε ροές που φαίνονται ~125 φορές μικρότερες από ό,τι είναι. Η διαδρομή αρχείου πηγής χωρίς συνεχή ροή το είχε ήδη σωστό ((bitrate_kbps * 1000) \ 8 = bytes/sec)· μόνο η διαδρομή συνεχούς ροής ήταν λάθος.


F28 - Διόρθωση μορφής ώρας μεταδεδομένων (Marantz)

Τι: το res@duration στο DIDL ήταν μορφοποιημένο ως H:MM:SS (π.χ. 0:03:42). Η προδιαγραφή UPnP DIDL ορίζει τη μορφή ως H+:MM:SS[.F+] - αυστηρά με κλασματικά δευτερόλεπτα προαιρετικά αλλά συνιστώμενα· ορισμένες συσκευές Marantz αντιμετωπίζουν την απλή μορφή ως μη έγκυρη και αφήνουν την εμφάνιση διάρκειας κενή. Τώρα μορφοποιείται ως H:MM:SS.fff (π.χ. 0:03:42.000).

Γιατί: πρόβλημα εμφάνισης ειδικό για μια μάρκα· η συμβατή μορφή τύπου ISO με κλασματικά δευτερόλεπτα το διορθώνει χωρίς να επηρεάζει καμία άλλη συσκευή. Εφαρμόζεται και στα δύο σημεία εκπομπής DIDL (διαδρομή αρχείου πηγής + διαδρομή κωδικοποιημένης ροής στο WriteAudioFileDIDL).

Επιπλέον διόρθωση στην ίδια διέλευση: τα pv:addedTime και pv:lastPlayedTime χρησιμοποιούσαν hh (ρολόι 12 ωρών) στις συμβολοσειρές μορφής DateTime αντί για HH (24 ωρών). Οποιοδήποτε κομμάτι προστέθηκε ή αναπαράχθηκε μεταξύ 13:00 και 23:59 θα εμφανιζόταν με λάθος ώρα (π.χ. 17:42 → "05:42") σε συσκευές που εμφανίζουν το πεδίο. Τώρα χρησιμοποιεί HH.


F29 - Υποστήριξη αναζήτησης κωδικοποιημένου MP3 (CBR)

Τι: οι μετακωδικοποιημένες ροές MP3 διαφημίζουν τώρα DLNA.ORG_OP=11 (αναζήτηση κατά byte και κατά ώρα) αντί για DLNA.ORG_OP=10 (μόνο κατά byte). Οι συσκευές που προηγουμένως αρνούνταν την αναζήτηση κατά ώρα σε μετακωδικοποιημένο MP3 μπορούν τώρα να οδηγήσουν τη γραμμή προόδου/UI αναζήτησης κανονικά.

Γιατί: ο μετακωδικοποιητής του MusicBee παράγει MP3 σταθερού bitrate στο preset HighQuality, οπότε η αντιστοίχιση byte ↔ ώρα είναι γραμμική - η συσκευή μπορεί να μετατρέψει ένα αίτημα αναζήτησης κατά ώρα σε αναζήτηση κατά byte HTTP Range από μόνη της χωρίς καμία υποστήριξη από την πλευρά του κωδικοποιητή. Η διαφήμιση OP=11 ξεκλειδώνει αυτό το UI στη συσκευή. Χωρίς το F29, οι χρήστες που αναζητούσαν μέσα σε ένα μετακωδικοποιημένο MP3 είτε αγνοούσαν σιωπηλά την αναζήτηση είτε επέστρεφαν στην αρχή του κομματιού.

Υλοποίηση: αναδιαρθρώθηκε το GetEncodeFeature στο ItemManager.vb για να σπάσει το inline If σε μια αναγνώσιμη αλυσίδα If/ElseIf/Else. Το MP3 αποκτά ρητά OP=11· άλλοι μη-PCM κωδικοποιητές διατηρούν OP=10. Καμία αλλαγή για AAC/FLAC/κ.λπ. - αυτά θα χρειάζονταν επαλήθευση CBR-ness ειδικά για τον κωδικοποιητή, την οποία το MusicBee δεν εγγυάται.


F30 - Χειρισμός επέκτασης αρχείου .mpeg

Τι: αρχεία με επέκταση .mpeg (και το ακόμα σπανιότερο .mpe) αναγνωρίζονται τώρα ως FileCodec.Mp3 στο GetCodec. Πριν το F30 επέστρεφαν FileCodec.Unknown και απορρίπτονταν σιωπηλά από τη βιβλιοθήκη / δεν μπορούσαν να είναι πηγές μετακωδικοποίησης.

Γιατί: παλιά αρχεία MPEG-1 Layer 3 χρησιμοποιούσαν μερικές φορές .mpeg αντί για .mp3 (η προδιαγραφή επιτρέπει και τα δύο). Μια χούφτα αρχείων σε μια βιβλιοθήκη 300k είναι αρκετή για να νιώθει κανείς "το MusicBee τα δείχνει αλλά το plugin όχι" - μπερδευτικό για τον χρήστη.


Συμπεριφορά αναπαραγωγής

F31 - Οι ροές ραδιοφώνου χρησιμοποιούν αυτόματα τη συνεχή λειτουργία

Τι: το WriteAudioFileDIDL ερευνά τώρα την ιδιότητα Kind του URL πηγής μέσω του Library_GetFileProperty και αντιμετωπίζει οποιοδήποτε αρχείο του οποίου το Kind τελειώνει σε "Stream" (το MusicBee αναφέρει "MP3 Stream", "Internet Stream", κ.λπ. για το ραδιόφωνο) ως συνεχές ανεξάρτητα από τον καθολικό διακόπτη Settings.ContinuousOutput. Χρησιμοποιείται ο κλάδος DIDL συνεχούς ροής (Τίτλος: "Continuous Stream", id="continuousstream", σταθερή έξοδος PCM/Wave)· η συσκευή βλέπει μια ενιαία ροή άπειρου τύπου.

Γιατί: οι ροές ραδιοφώνου δεν έχουν όρια κομματιών, σταθερό μήκος, αναζήτηση. Η αντιμετώπισή τους ως διακριτών αρχείων στο DIDL προκάλεσε το plugin να διαφημίζει εύρη byte και διάρκειες που δεν υπάρχουν. Η αυτόματη εναλλαγή όταν το MusicBee μας είπε ήδη "αυτό είναι μια ροή" αφαιρεί ένα πρόβλημα που ο χρήστης δεν θα έπρεπε να σκέφτεται.

Πεδίο εφαρμογής: εφαρμόζεται μόνο όταν το MusicBee οδηγεί την αναπαραγωγή (musicBeePlayToMode). Η διαδρομή ανάκτησης βιβλιοθήκης (περιήγηση UPnP client) παραμένει αμετάβλητη - τα URL ραδιοφώνου εκεί είναι σπάνια και η συμπεριφορά που βλέπει ο χρήστης δεν πρέπει να αλλάξει χωρίς ρητή δοκιμή.


F32 - Επαναφορά διαφήμισης κωδικοποιητή

Τι: αν μια συσκευή δεν διαφημίζει ορισμένους κωδικοποιητές (ή το plugin δεν μπορεί να αναλύσει το XML δυνατοτήτων της συσκευής), το plugin δεν απορρίπτει αμέσως τη ροή. Αντίθετα, προσπαθεί να την εξυπηρετήσει και αφήνει τη συσκευή να αποφασίσει.

Γιατί: πολλές συσκευές έχουν ελλιπές ή μη αναγνώσιμο XML δυνατοτήτων αλλά στην πραγματικότητα χειρίζονται τον κωδικοποιητή μια χαρά. Το F32 ανταλλάσσει μια μικρή "καλύτερη εικασία και δοκιμή" με μια πλήρη άρνηση.


F33 - Βελτίωση συγχρονισμού γραμμής προόδου

Τι: η θέση μεταξύ των ελέγχων είναι ήδη εκτιμώμενη με βάση το ρολόι από μια ενιαία άγκυρα (currentPlayStartTicks), οπότε η γραμμή προόδου ενημερώνεται ομαλά σε υπο-δευτερολεπτο ρυθμό. Η υπόλοιπη πηγή τρεμοπαίγματος ήταν η αρχική άγκυρα για ένα κομμάτι που μόλις ξεκίνησε: ο προηγούμενος κώδικας υπέθετε position=0 τη στιγμή που ο χρονοδιακόπτης κατάστασης παρατήρησε για πρώτη φορά ότι η κατάσταση έγινε Playing, αλλά μέχρι τότε η συσκευή μπορεί να έπαιζε για 100-500ms (ένα διάστημα ελέγχου). Η γραμμή προόδου του MusicBee θα ξεκινούσε από το 0, και στη συνέχεια θα πηδούσε μπροστά όταν η πραγματικότητα την προλάβαινε.

Διόρθωση F33: κατά τη μετάβαση σε Playing για πρώτη φορά σε ένα νέο κομμάτι (currentPlayStartTimeEstimated=True), καλέστε το GetPlayPositionInformation() για να λάβετε την πραγματική τρέχουσα θέση της συσκευής, και στη συνέχεια αγκυροβολήστε σε αυτήν. Το UPnP αναφέρει μόνο ανάλυση 1 δευτερολέπτου, οπότε η άγκυρα είναι ακόμα κβαντισμένη, αλλά είναι πολύ πιο κοντά στην αλήθεια από το να υποθέσουμε 0.

Γιατί: ομαλότερη + ακριβέστερη εμφάνιση προόδου, ειδικά αμέσως μετά την αλλαγή κομματιού. Δεν υπάρχει τρόπος να παρακαμφθεί η ανάλυση αναφοράς UPnP 1 δευτερολέπτου - αυτό είναι προδιαγραφή.


F34 - Τρεμόπαιγμα γραμμής προόδου μετά την αλλαγή κομματιού

Τι: όταν καλείται το PlayToDevice για ένα νέο κομμάτι, το plugin συνήθιζε να αφήνει τα currentPlayPositionMs και currentPlayStartTicks στις τιμές του προηγούμενου κομματιού για το παράθυρο ~100ms μεταξύ SOAP-Play και του πρώτου ελέγχου του χρονοδιακόπτη κατάστασης που ανιχνεύει τη νέα κατάσταση Playing. Η γραμμή προόδου του MusicBee θα έδειχνε για λίγο το τέλος του προηγούμενου κομματιού, στη συνέχεια θα επέστρεφε στο 0, και στη συνέχεια θα ανέβαινε. Το F34 μηδενίζει και τα δύο στην είσοδο PlayToDevice - τη στιγμή που γνωρίζουμε ότι συμβαίνει μια αλλαγή κομματιού, πριν από οποιαδήποτε εργασία SOAP.

Γιατί: οπτικό σφάλμα σε περιπτώσεις γρήγορης παράλειψης (χειροκίνητη επόμενη ή μετάβαση χωρίς κενά). Τώρα η πρώτη ερώτηση PlayPositionMs του MusicBee μετά το Play επιστρέφει καθαρά 0, και στη συνέχεια το GetPlayPositionInformation του F33 την βελτιώνει στην πραγματική θέση της συσκευής στον πρώτο χτύπο αλλαγής κατάστασης.

Υλοποίηση: τέσσερις γραμμές στην κορυφή του PlayToDevice, σε συνδυασμό με την ακριβή αγκυροβόληση του F33 κατά τη μετάβαση.


F35 - Σφάλμα "Επιβολή μετακωδικοποίησης"

Τι: η επιβολή μετακωδικοποίησης μπορούσε ακόμα να παρακάμψει τη μετακωδικοποίηση σε ορισμένους συνδυασμούς. Μετά την αναδιάρθρωση ανά προφίλ του F04, δύο συγκεκριμένα κενά σφραγίστηκαν:

  1. Προτεραιότητα με το ForceNativeStream. Όταν και τα δύο ήταν True (κάτι που μπορεί να συμβεί σε μια μετανάστευση σχήματος ή ένα μερικό αρχείο ρυθμίσεων), το ForceTranscoding κερδίζει τώρα απόλυτα (If streamingProfile.ForceTranscoding Then forceEncode = True ElseIf streamingProfile.ForceNativeStream Then forceEncode = False). Ο αμοιβαίος αποκλεισμός UI εμποδίζει τον χρήστη να επιλέξει και τα δύο, αλλά η προστασία χρόνου εκτέλεσης χειρίζεται οποιαδήποτε κατάσταση που φορτώθηκε ασυνεπής από το δίσκο.
  2. Λογική bypassTranscodeDecision. Προηγουμένως: streamingProfile.ForceNativeStream AndAlso Not Settings.ForceTranscoding. Τώρα: streamingProfile.ForceNativeStream AndAlso Not streamingProfile.ForceTranscoding - ο ίδιος κανόνας προτεραιότητας αλλά στο ίδιο πεδίο ανά προφίλ.

Γιατί: "επιβολή" πρέπει να σημαίνει επιβολή. Αν ο χρήστης ενεργοποίησε ρητά το ForceTranscoding για μια συσκευή, το plugin δεν πρέπει ποτέ να επιστρέψει σιωπηλά στην εγγενή ροή, ανεξάρτητα από το πώς συνδυάζονται άλλες σημαίες.


F36 - Εξαίρεση κλεισίματος Renderer

Τι: περιτύλιξε το Plugin.ReceiveNotification σε ένα Try/Catch ανώτερου επιπέδου που καταγράφει οποιαδήποτε ανεπεξέργαστη εξαίρεση αντί να την αφήνει να διαδοθεί πίσω στην αντλία ειδοποιήσεων του MusicBee.

Γιατί: οι ειδοποιήσεις από το MusicBee (PlayStateChanged, VolumeMuteChanged, κ.λπ.) αποστέλλονται στο ControlPointManager το οποίο επικοινωνεί με τον renderer μέσω SOAP. Οι μεμονωμένες τοποθεσίες κλήσης είχαν ήδη Try/Catch γύρω από τις κλήσεις SOAP τους, αλλά μια αρκετά περίεργη περίπτωση χρονισμού (π.χ. ο renderer να πεθαίνει μεταξύ δύο κλήσεων SOAP στον ίδιο χειριστή ειδοποιήσεων) μπορούσε ακόμα να διαφύγει. Ο περιτύλιγμα ανώτερου επιπέδου είναι το τελικό δίχτυ ασφαλείας ώστε ο χρήστης να μην βλέπει ποτέ ένα γενικό αναδυόμενο παράθυρο "TargetInvocationException" από το MusicBee.

Υλοποίηση: μετονομάστηκε το υπάρχον σώμα σε ReceiveNotificationInternal και προστέθηκε ένα λεπτό περιτύλιγμα ReceiveNotification που κάνει Try { ReceiveNotificationInternal(...) } Catch { LogError(...) }. Η προϋπάρχουσα υποδομή Try/Catch ανά μέθοδο μέσα στο ControlPointManager (γύρω από κάθε κλήση PostSoapRequest) παραμένει - το F36 είναι ζώνη + τιράντες.


F37 - Η αναζήτηση μακράς διαδρομής ενεργοποιεί ψευδή μετάβαση

Τι: η αναζήτηση μέσα σε ένα μακρύ κομμάτι μπορεί να προκαλέσει έναν σύντομο κύκλο Stopped→Playing σε ορισμένους renderers. Χωρίς διάκριση, το ProcessNewPlayState.Stopped το αντιμετωπίζει ως φυσικό τέλος κομματιού και καλεί το Player_PlayNextTrack, προωθώντας το MusicBee όταν ο χρήστης ήθελε απλώς να κάνει scrub. Το F37 σφραγίζει το lastUserInitiatedSeek στο Seek() και προσθέτει μια προστασία 5 δευτερολέπτων στον χειριστή Stopped (αντικατοπτρίζοντας το υπάρχον παράθυρο lastUserInitiatedStop).

Γιατί: η σιωπηλή παράλειψη στο επόμενο κομμάτι κατά τη διάρκεια μιας αναζήτησης είναι ένα από αυτά τα σφάλματα που κανείς δεν μπορεί να μαντέψει την αιτία - ο χρήστης σκέφτεται "περίεργο, προσπάθησα να κάνω scrub προς τα εμπρός και τώρα παίζει το επόμενο τραγούδι". Η διόρθωση είναι μηχανική: το ίδιο μοτίβο με τη διάκριση διακοπής χρήστη που υπάρχει ήδη.


F38 - Βελτιωμένος χειρισμός αναζήτησης για κωδικοποιητές επιρρεπείς σε κρασάρισμα

Τι: το κρασάρισμα του BubbleUPnP στην αναζήτηση MP3 ήταν το κανονικό σύμπτωμα. Μετά από έλεγχο, ο τρέχων κώδικας αναζήτησης yaiol κάνει ήδη τα σωστά πράγματα - η εγγενής διαδρομή χειρίζεται σωστά το HTTP Range (206, Content-Range, AcceptRanges), η κωδικοποιημένη διαδρομή διαφημίζει X-AvailableSeekRange και αναλύει τις εισερχόμενες κεφαλίδες timeSeekRange.dlna.org / npt, οι σημαίες DLNA.ORG_OP αντικατοπτρίζουν τις πραγματικές δυνατότητες ροής (με DisablePcmTimeSeek opt-out για προβληματικές συσκευές Platinum). Δοκιμασμένο από χρήστες στην τρέχουσα έκδοση BubbleUPnP 4.6.4: δεν παρατηρήθηκαν κρασαρίσματα.

Γιατί: το κρασάρισμα αναζήτησης MP3 του BubbleUPnP αναφέρθηκε περίπου το 2024 και η εφαρμογή έχει λάβει ~16 μήνες διορθώσεων από τότε. Το F29 (κωδικοποιημένο MP3 OP=11) ήταν η νέα μεταβλητή που θα μπορούσε να το είχε εκθέσει ξανά· δεν το κάνει, στις δοκιμασμένες εκδόσεις.

Αν επιστρέψει ένα κρασάρισμα: η μορφή διόρθωσης θα ήταν ένας διακόπτης "περιορισμένη αναζήτηση" ανά προφίλ που επιβάλλει DLNA.ORG_OP=10 (μόνο κατά byte) σε επισημασμένους κωδικοποιητές - αντικατοπτρίζοντας τον τρόπο λειτουργίας του DisablePcmTimeSeek για το PCM. Προσθέστε το τότε, όχι προληπτικά.


UI & καταγραφή

F39 - Το κουμπί "Προσθήκη" επιλέγει το νέο προφίλ

Τι: το κλικ στο "Προσθήκη" στη λίστα προφίλ συσκευών δημιουργεί ένα νέο προφίλ ΚΑΙ το επιλέγει αυτόματα ώστε ο χρήστης να μπορεί να επεξεργαστεί αμέσως τα πεδία. Η αναδιάρθρωση του διαλόγου μας με ενότητες το κάνει ήδη αυτό - τόσο η διαδρομή άμεσης προσθήκης όσο και η διαδρομή από πρότυπο καταλήγουν με Me.activeStreamingProfiles.SelectedIndex = Me.activeStreamingProfiles.Items.Count - 1. Ένας έλεγχος επιβεβαίωσε ότι το fork μας το χειρίζεται ήδη - τίποτα να αλλάξει.

Γιατί: μικρό UX papercut που αποδείχθηκε ότι δεν ήταν ήδη papercut εδώ.


F40 - Μεγαλύτερες μέγιστες συνδέσεις + προειδοποιητικό αρχείο καταγραφής

Τι: το όριο ταυτόχρονων ροών του plugin (SemaphoreSlim γύρω από Sockets_Stream_File / Sockets_Encoder_Start) ήταν σκληρά κωδικοποιημένο στο 4. Το F40 το καθιστά διαμορφώσιμο από τον χρήστη στη σελίδα γενικών ρυθμίσεων (προεπιλογή 16, εύρος 1-256), προσθέτει μια γραμμή καταγραφής MaxConnections όταν ένα αίτημα πρέπει να περιμένει για μια θέση, ΚΑΙ εμφανίζει ένα κόκκινο ⚠ Max Conn badge κάτω αριστερά στον διάλογο ρυθμίσεων αν το όριο χτυπήθηκε τουλάχιστον μία φορά από την εκκίνηση του MusicBee.

Γιατί: όταν μια συσκευή εκτελεί παράλληλα αιτήματα (κάποια Marantz/Linn κατά τη σάρωση εξώφυλλων, οι ανιχνεύσεις μεταδεδομένων του BubbleUPnP παράλληλα με την ενεργή αναπαραγωγή), πρόσθετα αιτήματα μπλοκάρονταν σιωπηλά πίσω από το semaphore - ο χρήστης έβλεπε "η συσκευή αργή" χωρίς ορατή αιτία. Η γραμμή καταγραφής είναι καλή για τεχνικό debugging αλλά οι μη τεχνικοί χρήστες δεν διαβάζουν ποτέ αρχεία καταγραφής. Η ορατή ετικέτα στον διάλογο ρυθμίσεων καθιστά την κατάσταση υπέρβασης ορίου ανακαλύψιμη σε όποιον ανοίξει τις προτιμήσεις του plugin.

Υλοποίηση:

  • Κεντροποίησε την αναμονή στο WaitOnSendBarrier(logTag) στο MusicBeeUpnp.vb· και οι δύο τοποθεσίες κλήσης (MediaServerDevice.GetFile, Encoder.StartEncode) το χρησιμοποιούν.
  • Το Settings.MaxConnections διατηρείται στην v8 του σχήματος ρυθμίσεων.
  • Το Plugin.MaxConnectionsHit είναι μια κολλώδης σημαία συνεδρίας που ορίζεται μέσα στο WaitOnSendBarrier· επαναφέρεται μόνο με επανεκκίνηση του MusicBee.
  • Το SettingsDialog.maxConnectionsBadge είναι μια κόκκινη έντονη ετικέτα στο (16, 410) που εμφανίζεται μόνο όταν το Plugin.MaxConnectionsHit είναι True. Έχει μια συμβουλή εργαλείου που εξηγεί την αιτία και τη λύση.
  • Το Semaphore αρχικοποιείται μία φορά κατά τη φόρτωση τύπου, οπότε η αλλαγή της ρύθμισης απαιτεί επανεκκίνηση του MusicBee (σημειώνεται στην ετικέτα πεδίου).

F41 - Καταγραφή "κωδικοποίηση λόγω ReplayGain/DSP"

Τι: αντί για ξεχωριστές γραμμές καταγραφής "κωδικοποίηση για RG" / "κωδικοποίηση για DSP", η ενιαία γραμμή StreamDecision από το F42 περιλαμβάνει MB-DSP/EQ, MB-ReplayGain, Profile-DSP/EQ, Profile-ReplayGain ως συσσωρευμένους λόγους. Ίδια διαγνωστική αξία, λιγότερος θόρυβος.

Γιατί: οι χρήστες βλέπουν όλους τους λόγους για τους οποίους γίνεται μετακωδικοποίηση για ένα δεδομένο κομμάτι σε μία γραμμή καταγραφής, όχι διάσπαρτα. Δείτε το F42 για πλήρεις λεπτομέρειες.


F42 - Καταγραφή "ο renderer δεν υποστηρίζει τον κωδικοποιητή πηγής"

Τι: προστέθηκε μια γραμμή καταγραφής StreamDecision ανά κομμάτι αναπαραγωγής-σε-συσκευή που λέει είτε "εγγενής CODEC" είτε "μετακωδικοποίηση CODEC→CODEC λόγος=…". Το πεδίο λόγου συσσωρεύει κάθε συνθήκη που ενεργοποίησε τη μετακωδικοποίηση: MB-DSP/EQ, MB-ReplayGain, Profile-DSP/EQ, Profile-ReplayGain, WebFile, VirtualFile, ForceTranscoding(global), SampleRate<min/SampleRate>max, DownmixToStereo, DeviceLacksCodec(X), BandwidthConstrained.

Γιατί: οι χρήστες μπερδεύονταν από απροσδόκητες αιχμές CPU σε αρχεία που περίμεναν να μεταδοθούν εγγενώς. Μια γραμμή καταγραφής ανά κομμάτι τους λέει ακριβώς ποια συνθήκη προκάλεσε τη μετακωδικοποίηση - και αν το πεδίο δείχνει DeviceLacksCodec(Flac) γνωρίζουν αμέσως ότι οι πληροφορίες πρωτοκόλλου της συσκευής ήταν ελλιπείς και μπορεί να θέλουν να ενεργοποιηθεί η επαναφορά του F32.

Υλοποίηση: ενιαία συμβολοσειρά συσσωρευτή που δημιουργείται σταδιακά μέσω της αλυσίδας αποφάσεων· καταγράφεται μία φορά στο τέλος. Περιορίζεται στο Settings.LogDebugInfo για να αποφευχθεί ο θόρυβος καταγραφής στην παραγωγή.


F43 - Το αρχείο καταγραφής SetNextAVTransport εμφανίζει το URL πηγής

Τι: οι καταχωρήσεις καταγραφής QueueNext περιλαμβάνουν τώρα source=<διαδρομή βιβλιοθήκης MusicBee> μαζί με stream=<URL ροής HTTP>. Η ίδια αλλαγή εφαρμόστηκε στη διαδρομή επιτυχίας και στη διαδρομή αποτυχίας (QueueNext:Failed).

Γιατί: κατά τον εντοπισμό σφαλμάτων ενός προβλήματος κομματιού στην ουρά, το URL ροής (/encode/aabbccdd0.flac) είναι αδιαφανές από μόνο του - το ίδιο για κάθε κομμάτι. Το URL πηγής είναι η αναγνώσιμη από τον άνθρωπο διαδρομή βιβλιοθήκης που σας λέει ακριβώς ποιο αρχείο προσπάθησε να βάλει στην ουρά το MusicBee.


F44 - Καλύτερη καταγραφή σφαλμάτων τύπου mime

Τι: δύο νέες καταχωρήσεις καταγραφής κατά την Activate:

  • Activate:MimeUnverified - ενεργοποιείται ανά λανθασμένη καταχώρηση στην απάντηση GetProtocolInfo της συσκευής, ονομάζοντας ποια καταχώρηση δεν μπορούσε να αναλυθεί (ώστε ο χρήστης να μπορεί να δει π.χ. "το Marantz επέστρεψε http-get:*::* για κάποιον κωδικοποιητή - η δυνατότητα είναι ανεπιβεβαίωτη, η επαναφορά του F32 θα μαντέψει").
  • Activate:NoSinkInfo - ενεργοποιείται μία φορά αν η συσκευή δεν επέστρεψε καθόλου στοιχείο <Sink>. Σημαίνει ότι το SupportedMimeTypes παραμένει Nothing και το IsCodecSupported υποβαθμίζεται σε "υποθέτουμε ότι όλα λειτουργούν" - χρήσιμο πλαίσιο όταν αργότερα εμφανίζονται σφάλματα "η συσκευή αρνήθηκε τη ροή".

Γιατί: πριν το F44 αυτές οι σιωπηλές παραλείψεις δυνατοτήτων άφηναν τους χρήστες να μαντεύουν γιατί τα κομμάτια τους είτε μετακωδικοποιούνταν ενάντια στις προσδοκίες είτε απορρίπτονταν από τη συσκευή. Τώρα μια απλή αναζήτηση για Activate: δείχνει αν οι πληροφορίες δυνατοτήτων της συσκευής ήταν χρησιμοποιήσιμες.


F45 - Καλύτερη καταγραφή σφαλμάτων μεταδεδομένων

Τι: το αρχείο καταγραφής εξαιρέσεων Browse στο ContentDirectoryService.vb είχε ήδη εμπλουτιστεί σε προηγούμενη εργασία yaiol (η συνεδρία σφαλμάτων Alia Vox) με ObjectID και ίχνος στοίβας. Το F45 το επεκτείνει περαιτέρω με BrowseFlag (μεταδεδομένα έναντι παιδιών), Filter (ποια χαρακτηριστικά ζήτησε ο πελάτης), sortCriteria, και partialResultLength (πόσα bytes DIDL παρήχθησαν πριν την αποτυχία - δείχνει πόσο μακριά στην παρτίδα βρίσκεται το κακό κομμάτι).

Γιατί: όταν κάτι πάει στραβά εν μέσω DIDL, η τιμή partial-length σας λέει αν η αποτυχία ήταν στο πρώτο κομμάτι της παρτίδας (partial=0) ή ενδιάμεσα (partial=N) - σε συνδυασμό με το startingIndex της παρτίδας, μπορείτε να αναγνωρίσετε τον δείκτη του κομματιού που προκάλεσε το πρόβλημα. Το Filter και το BrowseFlag εξηγούν τι είδους περιήγηση ήθελε ο πελάτης· μερικές φορές μια περιήγηση μόνο μεταδεδομένων αποτυγχάνει όπου μια περιήγηση παιδιών για το ίδιο ID επιτυγχάνει.


Δικτύωση

F46 - Η αυτόματη λειτουργία διαφημίζει μόνο σε προσαρμογείς πραγματικού δικτύου

Τι: σε λειτουργία διεπαφής Αυτόματη το plugin συνήθιζε να ανακοινώνει τον εαυτό του (SSDP) σε κάθε λειτουργικό προσαρμογέα IPv4. Σε μια μηχανή που εκτελεί επίσης ένα τούνελ VPN (NordLynx) ή έναν εικονικό διακόπτη (Hyper-V / WSL / Docker), η ίδια βιβλιοθήκη ανακοινωνόταν και σε κάθε έναν από αυτούς τους προσαρμογείς, οπότε το σημείο ελέγχου από το οποίο κάνατε cast ανακάλυπτε τον διακομιστή δύο ή τρεις φορές και εμφάνιζε τη βιβλιοθήκη ως διπλότυπα αντίγραφα. Η αυτόματη λειτουργία διατηρεί τώρα μόνο τους προσαρμογείς που έχουν μια πραγματική προεπιλεγμένη πύλη IPv4 (HasIPv4Gateway) - την οποία δεν έχουν οι προσαρμογείς τούνελ και εικονικού διακόπτη - οπότε αυτοί αφαιρούνται από τη λίστα ανακοίνωσης. Μια διεύθυνση που έχει καρφιτσωθεί από τον χρήστη εξακολουθεί να κερδίζει απόλυτα (ανακοίνωση μόνο σε αυτή τη διεπαφή), και αν κανένας προσαρμογέας δεν αναφέρει πύλη, ο επιλογέας επιστρέφει σε κάθε προσαρμογέα, οπότε η λίστα διαφημιζόμενων διευθύνσεων δεν είναι ποτέ κενή και το plugin δεν μπορεί να γίνει αόρατο.

Γιατί: το διπλότυπο δεν προκαλείται από το "να είσαι σε VPN" - προκαλείται από την ανακοίνωση στον προσαρμογέα LAN και στον προσαρμογέα τούνελ/εικονικού ταυτόχρονα, οπότε ένα σημείο ελέγχου βλέπει τον ίδιο διακομιστή σε δύο διευθύνσεις. Ένα καταναλωτικό VPN (NordVPN/NordLynx) διοχετεύει μόνο την κίνηση που προορίζεται για το διαδίκτυο· ο renderer DLNA βρίσκεται στο LAN και η κίνηση τοπικού υποδικτύου παρακάμπτει το τούνελ, οπότε ο προσαρμογέας τούνελ δεν φτάνει ποτέ σε έναν renderer ούτως ή άλλως - η αφαίρεσή του αφαιρεί ένα φάντασμα αντίγραφο, ποτέ μια λειτουργική διαδρομή. Ο έλεγχος πύλης είναι το φθηνό, αξιόπιστο σήμα που διαχωρίζει έναν πραγματικό προσαρμογέα LAN/Wi-Fi από ένα τούνελ ή έναν εικονικό διακόπτη. Συμπληρώνει το N05 (το οποίο διόρθωσε πώς αποστέλλονται οι ανακοινώσεις σε τέτοιες συνδέσεις - multicast αντί για broadcast)· το F46 καθορίζει ποιους προσαρμογείς θα ανακοινώσει καθόλου.

Γνωστό όριο: ένα VPN πλέγματος / απομακρυσμένης πρόσβασης (Tailscale, ZeroTier, WireGuard-to-home) του οποίου οι renderers βρίσκονται πραγματικά μέσω του τούνελ συνήθως παρουσιάζει έναν προσαρμογέα χωρίς προεπιλεγμένη πύλη, οπότε η αυτόματη λειτουργία τον απορρίπτει επίσης. Αυτοί οι χρήστες καρφιτσώνουν τη διεύθυνση VPN αντ' αυτού, η οποία υπερισχύει του φίλτρου πύλης.

Περιεχόμενα