MusicPod ist ein lokaler Musik-, Radio-, Fernseh- und Podcast-Player für Linux Desktop, MacOS und Windows. (Android ist geplant, aber es gibt noch keine ETA, wann es passieren wird.)
Betriebssystem | Anleitung zur Installation |
---|---|
Linux | oder |
Windows | Release-Seite |
MacOS | Release-Seite |
Android | In Bearbeitung |
Merkmale | Dunkles Linux | Leichtes Linux | Dunkles MacOS | Leichtes MacOS |
---|---|---|---|---|
Spielen Sie lokales Audio ab | ||||
Finden Sie lokale Audios, sortiert nach Metadaten | ||||
Spielen Sie Radiosender mit nachgeschlagenen Icytags und Kunstwerken! | ||||
Podcasts abspielen und herunterladen, Fortschritte sichern, Episoden sortieren und mehr! | ||||
Video-Podcast-Unterstützung! | ||||
Entdecken Sie Podcasts, gefiltert nach Ihren Wünschen | ||||
Entdecken Sie Radiosender, gefiltert nach Ihren Wünschen | ||||
Verschiedene Ansichtsmodi |
Das App-Symbol wurde von Stuart Jaggers erstellt, vielen Dank, Stuart!
Vielen Dank an TheShadowOfHassen für die Verpackung von MusicPod als Flatpak!
Vielen Dank an alle MPV-Mitwirkenden!
Vielen Dank @amugofjava für die Erstellung der sehr benutzerfreundlichen und zuverlässigen Podcast_Suche!
Vielen Dank an @alexmercerind für die superleistungsfähige Mediakit-Bibliothek und die mpris_service-Dart-Implementierung!
Vielen Dank an @KRTirtho für das sehr einfach zu verwendende Paket smtc_windows und Flutter Discord RPC
Vielen Dank @tomassasovsky für die Dart-Implementierung von radiobrowser-api!
Vielen Dank @ClementBeal für den superschnellen, reinen Dart Audio Metadata Reader!
Vielen Dank @escamoteur für die Erstellung von get_it und watch_it, die meine Anwendung schneller und den Quellcode sauberer gemacht haben!
Beiträge sind herzlich willkommen. Vor allem Übersetzungen. Bitte verzweigen Sie MusicPod in Ihren GitHub-Namespace, klonen Sie es auf Ihren Computer, erstellen Sie einen von Ihnen benannten Zweig, übernehmen Sie Ihre Änderungen in Ihren lokalen Zweig, übertragen Sie sie in Ihren Zweig und stellen Sie dann eine Pull-Anfrage von Ihrem Zweig in dieses Repository. Ich empfehle die vscode-Erweiterung GitHub Pull Requests insbesondere für Git- und GitHub-Neulinge.
Für Übersetzungen in Ihre Sprache ändern Sie die entsprechende Datei app_xx.arb
wobei xx
der Sprachcode Ihrer Sprache in Kleinbuchstaben ist. Wenn die Datei noch nicht existiert, erstellen Sie sie bitte, kopieren Sie den whole
Inhalt von app_en.arb hinein und ändern Sie nur die Werte in Ihrer Übersetzung, lassen Sie die Schlüssel jedoch unberührt. Der Arb-Editor der vscode-Erweiterung von Google wird dringend empfohlen, um Arb-Syntaxfehler zu vermeiden. Empfehlenswert ist auch die Google Translate-Erweiterung.
Wenn Sie einen Fehler finden, können Sie ihn gerne als Problem melden und ihn so gut wie möglich beschreiben. Wenn Sie Code beisteuern möchten, erstellen Sie bitte zuerst ein Problem.
Testmocks werden mit Mockito generiert. Sie müssen den Befehl build_runner
ausführen, um Mocks neu zu generieren, falls Sie die Signaturen von Dienstmethoden geändert haben.
dart run build_runner build
MusicPod ist im Grunde ein schickes Frontend für MPV! Ohne würde es immer noch gut aussehen, aber es würde keine Medien abspielen :D!
MusicPod verwendet das MVVM-Architekturmuster, das den Anforderungen dieser reaktiven App am besten entspricht, und hält alle Ebenen getrennt, sodass wir bei Bedarf die Implementierung einer Ebene austauschen können. MVVM wird auch von Flutter selbst empfohlen.
Die App, der Player, die Suche und jede Hauptseite verfügen über ihre eigenen Widgets, ein oder mehrere Ansichtsmodelle, die von einem oder mehreren Diensten abhängen.
Alle Dienste und ViewModels werden träge über get_it registriert, was bedeutet, dass sie erst dann instanziiert werden, wenn sie zum ersten Mal über di
oder di
gefunden werden.
Flussdiagramm LR
classDef view fill:#0e84207d
classDef viewmodel fill:#e9542080
classDef-Modellfüllung:#77216f80
Ansicht["`
**Sicht**
(Widgets)
`"]:::view--watchProperty-->ViewModel["`
**ViewModel**
(ChangeNotifier)
`"]:::viewmodel--listen/get Properties-->Model["`
**(Domänen-)Modell**
(Service)
`"]:::Modell
ViewModel--notify-->Ansicht
Modell--changedProperties.add(true)-->ViewModel
Die ViewModels haben Abhängigkeiten zu Diensten, die über ihren Konstruktor angegeben werden, wo sie über den Dienst-Locator get_it gefunden werden. Dies erleichtert das Testen, da Sie die Dienste durch simulierte Dienste ersetzen können.
Die ViewModels sind ChangeNotifier. Sie können die notifyListener
-Methode verwenden, die Listener (konkret: UI-Klassen) dazu bringt, zu reagieren (dh neu zu erstellen).
Die ViewModels enthalten (eine) StreamSubscription(s) für den/die Dienst(e), von denen sie abhängig sind. Wenn Eigenschaften nur nicht persistente UI-Zustände sind, werden sie im ViewModel gespeichert. Wenn sie mehr als das sind, sind sie lediglich Geber von Service-Eigenschaften. Wenn sich also eine Eigenschaft eines Dienstes ändert, werden die ViewModels über den PropertiesChanged-Stream benachrichtigt, und wenn wir möchten, dass die Benutzeroberfläche dies bemerkt, benachrichtigen wir innerhalb des listen
-Rückrufs die Benutzeroberfläche (Listener).
Was die Pakete zur Implementierung dieser Architektur angeht, habe ich einen langen Weg vom Anbieter bis zum Riverpod hinter mir.
Meine persönliche Lieblingslösung habe ich mit get_it plus seiner watch_it-Erweiterung gefunden, weil diese den Anforderungen dieser Anwendung und der MVVM-Architektur am besten entspricht, ohne zu stark in die API des Flatter-Widget-Baums einzugreifen.
Auf diese Weise sind alle Ebenen klar getrennt, leicht neu zu implementieren und leicht zu befolgen, auch wenn dies ein wenig Boilerplate-Code mit sich bringt.
Wenn die Widgets neu erstellt werden sollen, sobald sich die Eigenschaften von ViewModels ändern, verwenden wir die Methode watchPropertyValue
des Pakets watch_it:
final audio = watchPropertyValue (( PlayerModel m) => m.audio);
Dies macht es einfacher, obwohl wir auch einfach in ListenableBuilder erstellte Flatterfunktionen verwenden könnten.
Sowohl lokale Cover als auch Remote-Cover werden nach dem Laden/Abrufen in einem CoverStore
und einem UrlStore
zwischengespeichert.
Das Lesen der lokalen Abdeckungen und das Abrufen entfernter Abdeckungen für Funkdaten erfolgt in zusätzlichen zweiten Dart-Isolaten.
Präferenzen werden mit shared_preferences gespeichert.