/harmonoid

🎵 Elegant music app to play & manage music library. YouTube Music client. Lyrics & Playlists.

Primary LanguageDart

Harmonoid

🎵 Elegant music app to play & manage music library. YouTube Music client.

[work-in-progress] [report-bugs-or-request-features] [patreon] [primary-guide] [youtube-music-guide]

Motion

Enjoy that 🧈 buttery experience.

video.mp4

Links

Download

  Windows

Supports Windows 7 or later.

On Windows, setup is recommended as it automatically links with files & file explorer context menus.

  Linux [beta]

Any modern Linux distribution.

On Debian or Ubuntu based distros, you need to install mpv & libmpv-dev to be able to install & run the app.

sudo apt install mpv libmpv-dev
sudo dpkg -i harmonoid-linux-x86_64.deb

Similar instructions can be followed on your favorite distro.

  Android

Features

Current features

  • Powerful music library management based on metadata tags. Indexes music into group of albums & artists.
  • Capable of indexing 20 files/second (on Windows) & saves cache for future app start-ups.
  • Cross-platform (currently aiming Windows, Linux & Android).
  • mpv based music playback for strong format support (on Linux & Windows) using dart:ffi.
  • Taskbar & System Media Transport Controls for Windows.
  • Small installer (< 25 MB) & low RAM usage (< 120 MB) (tested on Windows, still see limitations).
  • Lyrics for all your music.
  • Very strictly follows Material Design guidelines for UI & animations.
  • Ability to create persistent or "Now playing" playlists.
  • Context menu integrations & file associations (exclusive to setup version).
  • Discord RPC integration.
  • Portable (if you wish).
  • Does not use electron.js.
  • D-Bus MPRIS controls for Linux.
  • Gapless playback.

Upcoming features

  • Music visualizations.
  • Time-synced lyrics.
  • Equalizer.
  • Details editor.
  • Re-ordering "Now Playing" list.
  • Mini-window mode.
  • Minimization to system tray.
  • Last.fm scrobbling.
  • Plugin API.
  • Windows 11 IExplorerCommand integration.
  • Publishing to Microsoft Store & other places.
  • YOU Tell 😄.

Limitations

[hopefully these will be resolved over time]

A lot of time has went into making this project possible using Flutter & nearly everything has been written from ground-up (from low-level C/C++ plugins to UI & business-logic in Flutter/Dart).

Flutter is quite new at the time for desktop & every new (even basic) functionality in the app is a research itself.

Nothing at the time is very stable & every new feature is a new discovery. Just have fun, learn & share your knowledge!

Few issues regarding memory usage alone can be:

In most cases as of now (Windows & Linux), memory usage will be really low at fresh start of the application & will continue to rise (although slowly) overtime with no specific reason.

Guide

1. Keyboard shortcuts

  • Space: Play or pause.
  • Alt + N: Next song.
  • Alt + B: Previous song.
  • Alt + M: mute or un-mute.
  • Alt + V: Volume increase.
  • Alt + C: Volume decrease.
  • Alt + X: Seek forwards.
  • Alt + Z: Seek backwards.

2. Indexing your music

To show your local music inside Harmonoid, you can go to the settings & click "ADD NEW FOLDER". This will show a new window, where you can select a folder where all your music is stored. After selecting the folder, your music collection inside the application will start building.

Your music will be categorized into albums, artists etc. & you'll be able to freely browse music album-wise or artist-wise etc. while being able to sort it alphabetically or year-wise etc.

As of now, you can still browse/play your music while it is being indexed.

Next time when you start the app, your music collection will be retrieved from the cache.

To remove a folder from your music collection, just click on "REMOVE" next to the folder you might wanna remove in the settings page.

3. Refresh your music

Just tap the circular "refresh" button in bottom-right of the application, it'll look for new files & remove the deleted ones from your library.

If you wish to completely re-build your music library (from scratch), go to Settings & press "REINDEX" under "Collection" section.

4. Managing playback queue

By default, the app will attempt to play the song that you click on, while adding songs after it to the queue. To add more songs to the queue, simply right click on the new song & click "Add to now playing".

You can also configure to automatically play other songs from your collection when the queue is finished.

5. Creating a playlist

To create a new playlist, you need to go the the "PLAYLISTS" tab & click "CREATE NEW PLAYLIST". This will ask you a name for your new shiny playlist. After its creation, you can click on your favorite song to add it to the required playlist. This can help you greatly organize your music collection.

You can add both local music & music from web URLs to these playlists.

6. Playing songs from YouTube Music

Click on the "earth icon" in top-right of the application, select "YT Music".

Currently, YouTube Music support works well in terms of performance & features. Right now, you can:

  • Play songs.
  • Play songs from URL.
  • Search for songs, videos, albums, artists & playlists.
  • Browse albums, artists & playlists.
  • Get recommendations.
  • Get suggestions.
  • Save to playlists (still streamed over the internet).

7. Playing from File Explorer

You can play music directly from file explorer if you installed Harmonoid using the setup installer or from Microsoft Store.

You can also right click a folder to "Add to Harmonoid's Playlist".

8. Viewing a YouTube Music song on website

If you're playing a song from YouTube Music & want to hear it on website instead, you can simply go to the "Now Playing Screen" by an arrow in the bottom-right corner of the application. Hovering over the album art, you'll see an icon hinting to open the song in your web-browser. Click on it & you're on YouTube Music website.

9. Playing an online media URL

Click on the "earth icon" in top-right of the application, select "Play URL".

10. Troubleshoot

If you encounter some problem like you're unable to start the app or see an error screen, you can try to delete the .Harmonoid folder in your home directory. WARNING: This will also delete your music indexing cache & playlists. Best decision can be to report us at our Discord.

11. Hacking

If you wish to really configure properties of the app which are not available in the UI yet, you may edit the .JSON files in ~/.Harmonoid directory.

Acknowledgements

An incomplete list of people who are working (or worked) on the project in past:

Developers

  •   Hitesh Kumar Saini
    • Lead developer. Deals with playback & indexing of media. Writes UI, state management & lifecycle code. Manages native plugins.
  •   Yehuda Kremer
    • UI & animation improvements. Application persistence & other important features. MSIX package for the store publishing.
  •   Denis
    • Major bug-fixes & Windows installer. Russian translation.
  •   Mitja Ševerkar
    • WinGet package. Backward Windows compatiblity checks. Bug reports. CI. Slovenian translation.
  •   Prateek Sunal
    • RPM package. Bug reports. Hindi translation.
  •   Bruno D'Luka
    • User interface & design. Portuguese translation.
  •   Gaetan Jonathan BAKARY
    • Linux related bug-fixes. French translation.
  •   Tamim Arafat
    • User interface & design. Bug reports.
  •   Leon
    • User interface fixes, app persistence improvements. Dutch translation.

Artists

  •   Bluebell
    • Artwork & iconography used in the application.

Testers

Translators

Compiling

Ensure that you have Flutter SDK & the required toolchain e.g. Visual Studio for Windows, Android Studio for Android installed.

git clone https://github.com/harmonoid/harmonoid.git --single-branch --recursive --branch master
cd harmonoid
flutter build windows
flutter build linux
...

Compiling with private packages

As of now, if you wish to gain access to all the private packages (and other source code within GitHub organization) used in Harmonoid, you may become a Patreon & support the development.

Compiling without private packages

You can compile Harmonoid yourself by removing references to following private plugins & replacing them with my following other already publicly available packages:

Private package Open-source alternative Notes
libmpv.dart dart_vlc & flutter_media_metadata All features may not work, performance may not be as tuned. The resultant bundle size may be larger in size.
smtc-win32 libwinmedia libwinmedia was used in earlier versions of application for media playback & still available under MIT license.
mpris_service.dart - No alternatives available.
harmonoid_visual_assets - Contains iconography & pictures used within the project. You can simply disable.

License

The source-code in this repository and official releases/binaries are distributed under our End-User License Agreement for Harmonoid (EULA).

Third-Party Credits

  • Harmonoid is (for the most part) written in Dart programming language using Flutter SDK. Refrences to all the other external "plugins" & "packages" used at the time of building application can be found here.

  • Harmonoid uses a modified version of libmpv for media playback capabilities on desktop. The compilation setup & other information (for Microsoft Windows) can be found here. The application bundles a minimal & LGPL compilant version of mpv shared library (for Microsoft Windows) (mpv-2.dll). Users are free to update/change to their own preferred libmpv by replacing the mpv-2.dll file present in Harmonoid's application directory.

  • Harmonoid also depends upon some of the awesome packages available on pub.dev. A complete list of those can be found here.

  • YouTube & YouTube Music is owned by Google LLC. Playback of videos & music is governed by YouTube Terms of Service. The application does not store any music/video streams locally, neither saves files on the disk. The content is shown in a manner similar to how a normal web-browser functions. This is not a "core" functionality of the application and just something application supports for the sake of completion.

Controversies

A lot of things were (are still) inexistent for Flutter Desktop or had to be made on-my-own for this project specifically. Thus, few of the things are written with a compromise.

Few of the common arguments can be:

  1. You are using singletons in the project.
  2. Stop saving cache in JSON.
  3. Don't use Provider, use Riverpod.
  4. No tests?
  5. Platform specific design

Answers:

  1. Singletons might be "bad", but here the application internally requires reference to these singleton objects/ChangeNotifiers outside Widget tree quite often (without BuildContext) (possibly using get_it like dependency-injection at some point will be good idea). e.g. few situtations like:
  • Triggering seekbar re-draw whenever position-update is sent from native code.
  • A file is opened from file explorer & app should open the clicked file within same instance.
  • Showing media-buffering state.
  • Indexing a File (retreving its tags) & showing progress update in UI.
  • System media control button(s) are clicked, the playback should be paused & UI re-draws should be triggered.
  • Some TextField is focused, keyboard shortcuts should be prevented.
  • Music files are being indexed, progress updates should be shown while saving metadata/tags to cache. And we can't make UI redraw for every single file that is parsed, but rather in a definite period interval (so that everything stays usable).
  1. Saving cache as JSON isn't a problem since there are no performance drawbacks (think of it as a NoSQL database). All that is happening at the end is serialization-deserialization & file read-write, either it be a sqlite3, hive, JSON or something else. Now a lot of good cross-platform databases are available like hive or isar for Flutter on Desktop, which can be used for caching the music-library/metadata-tags. However, the same wasn't applicable before.

  2. I fear I don't have time for that-much refactor now. I will prefer switching to BLoC instead, if any refactor ever happens. Why would I use a state-management solution that encourages to create global-variables ;)

  3. We need to write those. It's becoming a struggle with time. But I fear tests in Flutter aren't "capable" enough, the app highly depends upon C-interop & if something wrong happens or memory error takes place, Dart VM itself will die. I need tests to check actual functionality, audio output, correct audio-tagging, file explorer associations etc. NOT to measure/match position of Widgets on screen or compare Dart sided data-types with fake native-calls. In that case, only a human can do the job & look for possible regressions. And, since I am the only one who regularly commits changes or works on features, I don't feel that urgency to setup a pull-request test suite for public-contributions.

  4. No. Never. It's not "smart" to run a full-blown Skia renderer (from Flutter) & make it show a bland "native looking" UI design. One of the biggest advantage Flutter provides is that it's pixel-by-pixel painted, which means it is highly customisable in terms of what one can render visually. And I don't wanna put that advantage to no use, by following same boring design as other "native looking" apps (which will actually perform better in terms of graphical performance, for obvious reasons). I really like Material Design & current design is highly inspired by this video & I've made efforts to keep it CONSISTENT, FLUID & ADAPTIVE across all the platforms. I will add support for Material You at some point, but will be optional to users inside the Settings.

If you disagree with any of the answers or want to correct my knowledge, please open a new issue or discussion.

Bonus

Well you've scrolled this down... How about seeing more ✨ colorful ✨ stuff.