MusicPod 是一款适用于 Linux 桌面、MacOS 和 Windows 的本地音乐、广播、电视和播客播放器。 (Android 已计划,但尚未确定何时推出。)
操作系统 | 如何安装 |
---|---|
Linux | 或者 |
视窗 | 发布页面 |
苹果系统 | 发布页面 |
安卓 | 在制品 |
特征 | 黑暗Linux | 轻型Linux | 黑暗的MacOS | 轻型MacOS |
---|---|---|---|---|
播放本地音频 | ||||
查找按元数据排序的本地音频 | ||||
播放广播电台,查找冰标签和艺术品! | ||||
播放和下载播客、安全进度、排序剧集等等! | ||||
视频播客支持! | ||||
发现播客,根据您的喜好进行过滤 | ||||
发现广播电台,根据您的喜好进行筛选 | ||||
不同的视图模式 |
该应用程序图标是由 Stuart Jaggers 制作的,非常感谢 Stuart!
感谢 TheShadowOfHassen 将 MusicPod 打包为 Flatpak!
感谢所有 MPV 贡献者!
感谢 @amugofjava 创建了非常易于使用且可靠的 podcast_search!
感谢 @alexmercerind 提供的超高性能 Mediakit 库和 mpris_service dart 实现!
感谢 @KRTirtho 提供了非常易于使用的 smtc_windows 包和 Flutter Discord RPC
感谢@tomassasovsky 的 radiobrowser-api 的 dart 实现!
感谢 @ClementBeal 提供的超快、纯 dart 音频元数据阅读器!
感谢 @escamoteur 创建 get_it 和 watch_it,这使我的应用程序更快,源代码更干净!
非常欢迎您的贡献。尤其是翻译。请将 MusicPod 分叉到您的 GitHub 命名空间,将其克隆到您的计算机,创建您自己命名的分支,将更改提交到本地分支,将它们推送到您的分支,然后从您的分支向此存储库发出拉取请求。我推荐 vscode 扩展 GitHub Pull Requests,特别是对于 Git 和 GitHub 的新手。
要翻译成您的语言,请更改相应的app_xx.arb
文件,其中xx
是您的语言的小写语言代码。如果该文件尚不存在,请创建它并将 app_en.arb 的whole
内容复制到其中,然后仅更改您翻译的值,但保持键不变。强烈推荐使用 Google 的 vscode 扩展 arb 编辑器以避免 arb 语法错误。还推荐谷歌翻译扩展。
如果您发现任何错误,请随时将其报告为问题并尽可能详细地描述它。如果您想贡献代码,请先创建问题。
测试模拟是用 Mockito 生成的。如果您更改了服务方法的签名,您需要运行build_runner
命令才能重新生成模拟。
dart run build_runner build
MusicPod 基本上是 MPV 的一个奇特前端!如果没有它,它看起来仍然不错,但它不会播放任何媒体:D!
MusicPod 使用 MVVM 架构模式,最适合这种反应式应用程序的需求,并将所有层分开,以便我们可以在需要时交换某一层的实现。 MVVM也是Flutter自己推荐的。
应用程序、播放器、搜索和每个主页都有自己的一组小部件、一个或多个视图模型,它们依赖于一个或多个服务。
所有服务和 ViewModel 都是通过 get_it 延迟注册的,这意味着它们只有在第一次通过di
或di
定位时才会被实例化。
流程图LR
classDef 视图填充:#0e84207d
classDef 视图模型填充:#e9542080
classDef模型填充:#77216f80
查看["`
**看法**
(小工具)
`"]:::view--watchProperty-->ViewModel["`
**视图模型**
(变更通知程序)
`"]:::viewmodel--监听/获取属性-->模型["`
**(域)模型**
(服务)
`"]:::模型
ViewModel--通知-->视图
模型--changedProperties.add(true)-->ViewModel
ViewModel 依赖于通过其构造函数给出的服务,它们通过服务定位器 get_it 定位。这使得它们易于测试,因为您可以用模拟服务替换服务。
ViewModel 是 ChangeNotifier。他们可以使用notifyListener
方法来使侦听器(具体:UI 类)做出反应(即重建)。
ViewModel 持有它们所依赖的服务的 StreamSubscription。如果属性只是非持久 UI 状态,则它们保存在 ViewModel 中。如果它们不止于此,那么它们只是服务属性的获取者。因此,如果服务的属性发生更改,ViewModel 将通过propertiesChanged 流收到通知,如果我们希望 UI 注意到,在listen
回调中我们将通知 UI(侦听器)。
关于实现此架构的包,我从提供者到 Riverpod 经历了相当长的一段旅程。
我发现我个人最喜欢的解决方案是 get_it 加上它的 watch_it 扩展,因为这最适合这个应用程序和 MVVM 架构的需求,而且不会过多侵入 flutter widget 树的 API。
这样,所有层都清晰分离,易于重新实现且易于遵循,即使这会带来一点样板代码。
如果 ViewModel 的属性发生更改后希望重新构建 Widget,我们可以使用 watch_it 包的watchPropertyValue
方法:
final audio = watchPropertyValue (( PlayerModel m) => m.audio);
这使得它变得更容易,即使我们也可以只使用 ListenableBuilder 中内置的 flutters。
本地封面和远程封面在加载/获取后都缓存在CoverStore
和UrlStore
中。
读取本地覆盖物和获取远程覆盖物的无线电数据发生在额外的第二个省隔离内。
首选项通过shared_preferences 存储。