{"id":13604259,"url":"https://github.com/ubuntu-flutter-community/musicpod","last_synced_at":"2025-12-30T14:04:38.452Z","repository":{"id":103767686,"uuid":"606369386","full_name":"ubuntu-flutter-community/musicpod","owner":"ubuntu-flutter-community","description":"Music, radio, television and podcast player for Ubuntu, Windows, MacOs and maybe soon Android","archived":false,"fork":false,"pushed_at":"2025-04-09T20:35:45.000Z","size":64102,"stargazers_count":514,"open_issues_count":34,"forks_count":60,"subscribers_count":8,"default_branch":"main","last_synced_at":"2025-04-09T21:24:54.098Z","etag":null,"topics":["android","flutter","internet-radio","linux","macos","music","music-player","podcasts","radio","radio-station","radiobrowser","radiobrowser-api","tv","ubuntu","windows"],"latest_commit_sha":null,"homepage":"","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ubuntu-flutter-community.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-02-25T09:25:24.000Z","updated_at":"2025-04-09T20:13:48.000Z","dependencies_parsed_at":"2023-07-10T05:45:31.674Z","dependency_job_id":"694e2a77-cebb-4f34-92a5-da5d8028611e","html_url":"https://github.com/ubuntu-flutter-community/musicpod","commit_stats":null,"previous_names":[],"tags_count":53,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubuntu-flutter-community%2Fmusicpod","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubuntu-flutter-community%2Fmusicpod/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubuntu-flutter-community%2Fmusicpod/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubuntu-flutter-community%2Fmusicpod/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ubuntu-flutter-community","download_url":"https://codeload.github.com/ubuntu-flutter-community/musicpod/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248495108,"owners_count":21113572,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","flutter","internet-radio","linux","macos","music","music-player","podcasts","radio","radio-station","radiobrowser","radiobrowser-api","tv","ubuntu","windows"],"created_at":"2024-08-01T19:00:42.422Z","updated_at":"2025-12-30T14:04:38.446Z","avatar_url":"https://github.com/ubuntu-flutter-community.png","language":"Dart","funding_links":[],"categories":["Multimedia","Dart"],"sub_categories":["Media Servers"],"readme":"# MusicPod\n\n\u003ca href=\"https://hosted.weblate.org/engage/musicpod/\"\u003e\n\u003cimg src=\"https://hosted.weblate.org/widget/musicpod/app/svg-badge.svg\" alt=\"Translation status\" /\u003e\n\u003c/a\u003e\n\n[![Dart](https://img.shields.io/badge/-Dart-555?style=flat\u0026logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAKaAAACmgFJLYRWAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAArhJREFUSImdk89rE1EQx78zmzaprUmbH03wB4gFsckmm/64FKqCeFX8gelBPHhpT4LVHjx48B+wejUK1YIIPRV6kB6EFvFm8VAiYtFbwbRKY4U2abo7HpImm2Szmzqw8N7Me9/PzLxZQot2fllOkgsPSTAGIC/Ak+VReup0j1oSZkwxYRyAxxwT4NnSKE3+F8BO+DCQBkCrwq1CagG3Xpzo06Kvsl/WzgLEIGImIoAUYiIQEYEYDCKDFDARIMztLvEE/O/WH1+8UQ9wmTe8T1PeuJbIFYzsVuarSs5PVK5AgM2t65xKTxtz4/fNMaWyuvY6QC59NqLFdc+x46dgGN93Nzb9AEBk/VXbUN4QjVD0sk8yC4uVpCsLd+EBgC6BMBEQGkz2BTQ1SzZFWEKYJjmVnq6t4OZzHyn8BoAnoql5nbgDALoi4S4A2zvZDXdJkEB1xKaVxK50S2Zh0VV23IWgu9xRKh0uWVCLeyGy+3s101EVLUVFpAIpL820ezz20lBwe7aTRX8LoBMAIppa0Ik95jyPRMJtpPD+zs8s4zAm+ghjLz8BIFTDtrCAGnP1DiYNc7C+XVbGBLpTAzWkaZb+WD+HhpL1zbAHAAjXeGyGXwD0RPspOKjpQPUNbAEEmanx2FRwYIFYVAkNJAqO6gDY8MkjEZmvZllqrFNufjXmDmqJbcBigkw+RnqiKD5JHUBEpNIiJ0hQU73+hJqtnm+8UWpHGUJE81LYM8wZ2UEEQCiZCAfi0R9mcfP9ar/TE0X9qJ7azeVW6w9Jk69SyUDydE//mc9WSTRMTGxO2uHNzyiCC6xQLwFtNkUcJKIbIr/WP3xczX1bqyRNEOs/ZeiTtPkKmBPBVTtxC9j7pXN0yeyzHMmVYSr+cSMlhHmreIMwmr9V05lfGabiXweInbAjoB5i98h29g+dUABUDBEaEwAAAABJRU5ErkJggg==)](https://dart.dev/)\n[![Flutter](https://img.shields.io/badge/-Flutter-555?style=flat\u0026logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAAYCAYAAAAYl8YPAAAACXBIWXMAAAAkAAAAJAGHsLAiAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAoNJREFUOI2NlU9IVFEUxr9z79NZmAUubFG0ChPLeQMFQS4i0laFC7N/REGZlRWEKZKVTC3SCFMjMhNy1FaOg9XSN2a0aiHRDJgjUhSBBpZaU1A4c08LR3059zlzdu98h9/53ne57xHSrPJRzpyNcYDA+zUyM3DBSBc0F2O/EwiES0G3bJepQNtHOEMQ+wEu1ekE1FmmbAWAVZ2V97Gcy1A9DGhBzLhqeeTdxWexKmiL6gVwxGHkWtAjm+wNLay8j+VsnuoGcFSLYTRYpry9sp2UmZdZTMSVjwjHdRwCbloeeUun/Q9jJiOkHhHhlNYR0GyZst5BA9lBJWH1EMA53SAzWoIeWe0EAhYzY6bisHrgBALQlgq04IyZSkLqPggXHax3DrrFWRBxKphRElYtTiAQOgYLxXkQccJ9PcB79CjZbjDwiXQao6vILaqshKPisKoBcMIe89JOwhPLTQERNGUrGFdW6N1FpqjwEikAKA7FawFU6HfCZ7nlHSBxAJZH3mOgNrHHPz+zDCrwvbf+Rn/fACvNC6ieIVM2Lqdiq32h2MF143LAf4jiAFDYE3mWvTG3FABkphF1ZWdN2Sz1BU3RYD8YbVwAsK030r92Q26ZvSddxk/XmqyvBBWwBozr8C64XxWW7xurzNm0vkOn/Zicfjf6PG8H/Avu7aW96JGT+Z2/pr4Pr+xPj3/G2MBrj1CdHQAnGdF/gog4fGzz3ujkt1eLrZkPX/Dx5QgABoDToiwZ6JgZAICZCp9Ghuf/xHZPDL4Bq6RL0KYClZfTgyWAxuGuRhWP1TlMtKhAZXV6sESJssdNAPRAombVf6Ym5Q9lyeDYiyHa+jYHwE6NvIsKDoh/P0T0VGjgES8AAAAASUVORK5CYII=)](https://flutter.dev/)\n\nMusicPod is a local music, radio, television and podcast player for Linux Desktop, MacOS and Windows (currently the metadata loading for local audio takes ages, so the Windows version is not considered stable if you are looking for the local audio feature. See [#264](https://github.com/ubuntu-flutter-community/musicpod/issues/264) ). (Android is planed but no ETA yet when it will happen.)\n\n| OS      | How to install                                                                                                                                                                                                                                     |\n| ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Linux   | [![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-black.svg)](https://snapcraft.io/musicpod) \u003cbr/\u003e or \u003cbr/\u003e [![](https://flathub.org/api/badge?locale=en)](https://flathub.org/apps/org.feichtmeier.Musicpod) |\n| Windows | [Release Page](https://github.com/ubuntu-flutter-community/musicpod/releases)                                                                                                                                                                      |\n| MacOS   | [Release Page](https://github.com/ubuntu-flutter-community/musicpod/releases)                                                                                                                                                                      |\n| Android | WIP                                                                                                                                                                                                                                                |\n\n\n## Features\n\n| Features                                                                                     | Dark Linux                                    | Light Linux                                    | Dark MacOS                                    | Light MacOS                                    |\n| -------------------------------------------------------------------------------------------- | --------------------------------------------- | ---------------------------------------------- | --------------------------------------------- | ---------------------------------------------- |\n| Play local audio                                                                             | ![](.github/images/album_dark_linux.png)      | ![](.github/images/album_light_linux.png)      | ![](.github/images/album_dark_macos.png)      | ![](.github/images/album_light_macos.png)      |\n| Find local audios sorted by [Metadata](https://github.com/ClementBeal/audio_metadata_reader) | ![](.github/images/albums_dark_linux.png)     | ![](.github/images/albums_light_linux.png)     | ![](.github/images/albums_dark_macos.png)     | ![](.github/images/albums_light_macos.png)     |\n| Play radio stations, with icytags and artwork looked up!                                     | ![](.github/images/station_dark_linux.png)    | ![](.github/images/station_light_linux.png)    | ![](.github/images/station_dark_macos.png)    | ![](.github/images/station_light_macos.png)    |\n| Play and download podcasts, safe progress, sort episodes and more!                           | ![](.github/images/podcast_dark_linux.png)    | ![](.github/images/podcast_light_linux.png)    | ![](.github/images/podcast_dark_macos.png)    | ![](.github/images/podcast_light_macos.png)    |\n| Video podcast support!                                                                       | ![](.github/images/video_dark_linux.png)      | ![](.github/images/video_light_linux.png)      | ![](.github/images/video_dark_macos.png)      | ![](.github/images/video_light_macos.png)      |\n| Discover podcasts, filtered as you like                                                      | ![](.github/images/podcasts_dark_linux.png)   | ![](.github/images/podcasts_light_linux.png)   | ![](.github/images/podcasts_dark_macos.png)   | ![](.github/images/podcasts_light_macos.png)   |\n| Discover radio stations, filtered as you like                                                | ![](.github/images/radio_dark_linux.png)      | ![](.github/images/radio_light_linux.png)      | ![](.github/images/radio_dark_macos.png)      | ![](.github/images/radio_light_macos.png)      |\n| Different view modes                                                                         | ![](.github/images/fullheight_dark_linux.png) | ![](.github/images/fullheight_light_linux.png) | ![](.github/images/fullheight_dark_macos.png) | ![](.github/images/fullheight_light_macos.png) |\n\n\n## Credits\n\n### AppIcon\n\nThe app icon has been made by [Stuart Jaggers](https://github.com/ubuntujaggers), thank you very much Stuart!\n\n### Flatpak\n\nThanks [TheShadowOfHassen](https://github.com/TheShadowOfHassen) for packaging MusicPod as a  [Flatpak](https://flathub.org/apps/org.feichtmeier.Musicpod)!\n\n### Libraries used\n\nThanks to all the [MPV](https://github.com/mpv-player/mpv) contributors!\n\nThank you [@amugofjava](https://github.com/amugofjava) for creating the very easy to use and reliable [podcast_search](https://github.com/amugofjava/podcast_search)!\n\nThanks [@alexmercerind](https://github.com/alexmercerind) for the super performant [Mediakit library](https://github.com/alexmercerind/media_kit) and [mpris_service](https://github.com/alexmercerind/mpris_service) dart implementation!\n\nThank you [@KRTirtho](https://github.com/KRTirtho) for the very easy to use [smtc_windows](https://github.com/KRTirtho/frb_plugins) package and [Flutter Discord RPC](https://github.com/KRTirtho/frb_plugins)\n\nThank you [@tomassasovsky](https://github.com/tomassasovsky) for the [dart implementation of radiobrowser-api](https://github.com/tomassasovsky/radio-browser-api.dart)!\n\nThank you [@ClementBeal](https://github.com/ClementBeal) for the super fast, pure dart [Audio Metadata Reader](https://github.com/ClementBeal/audio_metadata_reader)!\n\nThank you [@escamoteur](https://github.com/escamoteur) for creating [get_it](https://pub.dev/packages/get_it) and [watch_it](https://pub.dev/packages/watch_it), which made my application faster and the source code cleaner!\n\n## Contributing\n\nContributions are highly welcome. Especially translations.\nPlease [fork](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) MusicPod to your GitHub namespace, [clone](https://docs.github.com/de/repositories/creating-and-managing-repositories/cloning-a-repository) it to your computer, create a branch named by yourself, commit your changes to your local branch, push them to your fork and then make a pull request from your fork to this repository.\nI recommend the vscode extension [GitHub Pull Requests](https://marketplace.visualstudio.com/items?itemName=GitHub.vscode-pull-request-github) especially for people new to [Git](https://git-scm.com/doc) and [GitHub](https://docs.github.com/en/get-started/start-your-journey).\n\n## Translations\n\nThe help of translators is highly appreciated!\nFor translations MusiPod is now on Weblate thanks to [@keunes](https://github.com/keunes):\n\nhttps://hosted.weblate.org/projects/musicpod/app\n\n\u003ca href=\"https://hosted.weblate.org/engage/musicpod/\"\u003e\n\u003cimg src=\"https://hosted.weblate.org/widget/musicpod/app/multi-auto.svg\" alt=\"Translation status\" /\u003e\n\u003c/a\u003e\n\n## Code contributions\n\nIf you find any error please feel free to report it as an issue and describe it as good as you can.\nIf you want to contribute code, please create an issue first.\n\n## Build\n\n- for Linux desktop builds: `sudo apt install libmpv-dev mpv`\n- [install rust](https://www.rust-lang.org/tools/install) (for some dependencies)\n- [install flutter](https://docs.flutter.dev/get-started/install)\n  - I suggest to install the flutter *sdk* with [FVM](https://fvm.app/) (this does not replace the native dependencies ofc!)\n- required for android builds: [install android-studio](https://developer.android.com/studio)\n- required for macos builds: [install xcode](https://developer.apple.com/xcode/)\n- as a good IDE for all builds: [install vcode](https://code.visualstudio.com/)\n\n## Release\n\n[The release please bot](https://github.com/googleapis/release-please) automatically creates a pull request when new changes after the last release are made with [sconventional commits](https://www.conventionalcommits.org/en/v1.0.0/).\nIt force pushes those to its branch and updates the version string in pubspec.yaml and the changelog file.\nWhen the release please pull request is merged the version and changelog will be updated in main.\n\n### Linux\n\nThe linux snap packages are always build when a new commit lands in main.\nWhen a new release is made go to https://snapcraft.io/musicpod/releases and promote the latest snap from edge to stable.\n\n### MacOs\n\n- fvm flutter build macos --release\n- open the macos directory in xcode\n  - in xcode go to \"Product\" -\u003e \"Archive\"\n  - create archive\n  - validate\n  - distribute\n  - notarize\n  - export app\n- install [create-dmg](https://github.com/create-dmg/create-dmg)\n- open the location you exported the app to\n- create-dmg --idenfity=XXXXXXXX musicpod.app (XXXXXXXX is your apple dev ID which needs to be with your certificate in your mac...)\n\n### Windows\n\nCurrently inno setup is needed. This hopefully changes some day when https://github.com/ubuntu-flutter-community/musicpod/issues/964 is merged.\n\n- fvm flutter build windows --release\n- copy the following files from C:\\Program Files (x86)\\Microsoft Visual Studio\\2022\\Community\\VC\\\nRedist\\MSVC\\14.34.31931\\x64\\Microsoft.VC143.CRT\\ into your windows build\n\n```\nmsvcp140.dll\nmsvcp140_1.dll\nmsvcp140_2.dll\nvcruntime140.dll\nvcruntime140_1.dll\n```\n- run .../musicpod/windows/inno.iss\n\n## Testing\n\nTest mocks are generated with [Mockito](https://github.com/dart-lang/mockito). You need to run the `build_runner` command in order to re-generate mocks, in case you changed the signatures of service methods.\n\n`dart run build_runner build`\n\n## Boring developer things\n\n### Under the flutter hood\n\nMusicPod is basically a fancy front-end for [MPV](https://github.com/mpv-player/mpv)! Without it it would still look nice, but it wouldn't play any media :D!\n\n### Architecture: [model, view, viewmodel (MVVM)](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel)\n\nMusicPod uses the MVVM architectural pattern, which fits the needs of this reactive app the most, and keeps all layers separated so we can exchange the implementation of one layer if we need to. [MVVM is also recommended by Flutter itself](https://docs.flutter.dev/get-started/fwe/state-management#using-mvvm-for-your-applications-architecture).\n\nThe app, the player, the search and each main page have their own set of widgets, one or more view model, which depend on one or more services.\n\nAll services and ViewModels are registered lazily via [get_it](https://pub.dev/packages/get_it), which means they are not instantiated until they are located for the first time via `di\u003cXyzService\u003e` or `di\u003cViewModel\u003e`.\n\n```mermaid\n\nflowchart LR\n\nclassDef view fill:#0e84207d\nclassDef viewmodel fill:#e9542080\nclassDef model fill:#77216f80\n\nView[\"`\n  **View**\n  (Widgets)\n`\"]:::view--watchProperty--\u003eViewModel[\"`\n  **ViewModel**\n  (ChangeNotifier)\n`\"]:::viewmodel--listen/get properties--\u003eModel[\"`\n  **(Domain) Model**\n  (Service)\n`\"]:::model\n\nViewModel--notify--\u003eView\nModel--changedProperties.add(true)--\u003eViewModel\n\n```\n\nThe ViewModels have a dependencies to services which are given via their constructor, where they are located via the service locator [get_it](https://pub.dev/packages/get_it). This makes them easy to test since you can replace the services with mocked services.\n\nThe ViewModels are [ChangeNotifiers](https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html). They can use the `notifyListener` method which makes listeners (concrete: UI classes) react (i.e. rebuild).\n\nThe ViewModels hold (a) [StreamSubscription(s)](https://api.flutter.dev/flutter/dart-async/StreamSubscription-class.html) to (the) service(s) they depend on. If properties are only non-persistent UI state, they are hold inside the ViewModel. If they are more than that, they are just getters to service properties.\nSo if a property of a service changes, the ViewModels will be notified via the propertiesChanged stream, and if we want the UI to take notice, inside the `listen` callback we will notify the UI (listeners).\n\n### Dependency choices, service locator and state management\n\nRegarding the packages to implement this architecture I've had quite a journey from [provider](https://pub.dev/packages/provider) to [riverpod](https://pub.dev/packages/riverpod).\n\nI found my personal favorite solution with [get_it](https://pub.dev/packages/get_it) plus its [watch_it](https://pub.dev/packages/watch_it) extension because this fits the need of this application and the [MVVM-architecture](https://docs.flutter.dev/get-started/fwe/state-management#using-mvvm-for-your-applications-architecture) the most without being too invasive into the API of the flutter widget tree.\n\nThis way all layers are clearly separated, easy to re-implement and easy to follow, even if this brings a little bit of boilerplate code.\n\n## Watching the ViewModels inside the View (Widgets)\n\nIf the Widgets want to be rebuilt once properties of ViewModels change, we use the `watchPropertyValue` method of the [watch_it](https://pub.dev/packages/watch_it) package:\n\n```dart\nfinal audio = watchPropertyValue((PlayerModel m) =\u003e m.audio);\n```\n\nThis makes it easier, even though we could also just use flutters built in [ListenableBuilder](https://api.flutter.dev/flutter/widgets/ListenableBuilder-class.html).\n\n### Caching\n\nBoth local covers and remote covers are cached in `LocalCoverService` and a `OnlineArtService` after they have been loaded/fetched.\n\n### Performance\n\nReading the local covers and fetching remote covers for radio data happens inside additional second [dart isolates](https://dart.dev/language/isolates). When idle MusiPod's CPU power consumption is 0%. For a 10 years old intel dual core, the CPU usage is about 2% while playing music, since only the parts are redrawn which need to be, thanks to watch_it.\n\n### Persistence\n\nPreferences are stored with [shared_preferences](https://pub.dev/packages/shared_preferences), collections are stored inside basic json files on our computer.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fubuntu-flutter-community%2Fmusicpod","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fubuntu-flutter-community%2Fmusicpod","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fubuntu-flutter-community%2Fmusicpod/lists"}