Serve Your Music Collection Using HTML5, Backbone, and Flask
git.zx2c4.com
git.zx2c4.com
I might actually use yours until my take on this is done. It certainly looks superior to Subsonic in every way.
I'm still going to finish mine, because I have some different UI/design ideas. For instance, I want a visually-oriented player with cover art very prominently featured, whereas yours doesn't show art at all.
But on the technical side of things, the concept is rather identical. Have you tested it on a smartphone browser and does it work/look good? I didn't use Bootstrap like you, so I'll probably have to create a totally separate mobile interface.
Anyway, well done!
But I think I'll abandon my project (I was in the earlier steps either way), study you guys' efforts, and work on something else.
Edit: Hmm, seems glitchy. The music is playing but tags won't load and a random textbox is obscuring part of the UI. http://i.imgur.com/sJwd2.png
Initial frontend prototype took about 30 minutes, and backend about the same. Then I spent a few hours polishing. Was mostly done in between other tasks over the course of a couple days. It's a tiny simple-ish project. But there's a lot of work to be done and things that can be added.
> I want a visually-oriented player with cover art very prominently featured
I'd love to have this!
Please feel welcome to submit any patches or improvements from your own project. It'd be nice to have some help on it.
Anyway, zx2c4's project is obvious slicker than mine.
It's somewhat crazy that all the people on this thread saying "hey, me too" are only now finding each other. I think there are some pretty clear opportunities for collaboration here. In particular, I think it would be prudent to informally standardize a REST/JSON API for music collections so these tools can interoperable. (I'll send you email about this, zx2c4.)
beets is a great music importer. A few months ago I wanted to write something like that — looking up releases in a central repository, automatically correcting tags and renaming. But I hadn't got very far, so I abandoned the project when I saw you had already done it way better.
I would prefer if it pulled data from Discogs instead of MusicBrainz. Have you considered using the Discogs API? In my limited experience, MusicBrainz disappoints me by "correcting" tags to something wrong because there's a typo in the DB, or changing the typography ("and" -> "&", "... (Part One)" -> "..., Part 1") in a way that doesn't match the official track listing. Also a very, very large percentage of albums I run through beets aren't in the MB database at all. I think I'm spoiled by how good Discogs is: these problems would mostly go away. Last.fm's data might also be an improvement, though it's not on par with Discogs.
> it would be prudent to informally standardize a REST/JSON API for music collections
This sounds cool. If you come up with a spec for this, I'd like to know too (email in profile).
You also have to bare in mind that Subsonic also has native players for a whole bucket load of platforms (both mobile and desktop), supports video, transcodes, is multi user and has a tone of other neat functions.
In many ways, Subsonic is more akin to Spotify.
> Based on Java technology, ...
I stopped reading there. Bias? Maybe.
But really, it's your loss.
(I also happen to be the maintainer of cgit...)
Anyway, if you really must have it, I do mirror all my git repos to github as a free backup. Look under my account -- zx2c4.
uwsgi --socket /tmp/uwsgi-zmusic.sock --file /home/user/zmusic-ng/backend/zmusic -H /home/user/zmusic-ng/venv --callable app --processes 4
-w zmusic:app --socket /tmp/uwsgi-zmusic.sock --chmod-socket=660
Using --chdir to change to the backend/ directory may be useful as well.I've just updated the README with these instructions.
I've also added a section on using uwsgi in standalone mode, as the built-in debugging server can't handle concurrent requests.
One minor, minor gripe is that it uses a Makefile instead of the canonical setup.py for building. (did I mention "minor"?) For me personally, it makes up for this fact by using Flask. (Yes, i am unabashedly a fanboy of that microframework. squeee)
One question though: What is the [git-root]/server.cfg? it seems not to have an influence? is it deprecated?
Makefiles. I love Makefiles. I kind of dislike all these bloated new-fangled build-systems - Rake, Jake, Pip, Pap, Nodifier, Grunt, whatever else is on the street. A setup.py might be nice, though, for installing system-wide, but generally speaking, standard GNU Make is wonderful.
server.cfg influences where 'make deploy' and 'make upload' deploy things to. Check out the bottom section of the README for info.
But i had this open in a different browser some minutes ago and it seemed quite impressive. Especially the encoding on the fly, as that is something I experimented with on my own mini-project (https://github.com/onli/music-streamer, ruby with sinatra, plain html5-audio). I'll have a look at your code how you did it, but I wonder if that would work with a low-end homeserver (i'm targeting a pogoplug). On what hardware did you test that?
I've got it working well on:
* Highend Core i7 laptop
* Atom 1U rackmount server
* Linode VPS
* Raspberry piI listen to a lot of foreign music and have had a hard time populating my zmusic database. There's a work-around (decode the relevant strings to Unicode) that seems to have worked but I have to leave for work before I'll be able to test this fully. I've never submitted a patch before and hope to use this as an opportunity to learn how to make one.
I have a basic question, however: why did you decide to use tab characters in your python? Most libs whose code I've read use spaces but I've never seen an argument for one convention or the other.
Oh noes! I too have lots of foreign music in my collection, and it seemed to work fine. I'm using the tagging framework out of MusicBrainz' Picard application, so things should be pretty flawless. I wonder what happened... Maybe the encoding system-wide needs to be set to UTF-8 so Python picks this up? If you email me more information, I can take a look.
> why did you decide to use tab characters in your python?
I'm partial to Linux-kernel C-style. I like tabs. That's what they're for. Holy wars though. What else? I use VIM, KDE, and Gentoo. Death to Emacs, Gnome, and Mandrake! Ahh, preferences...
> ProgrammingError: (ProgrammingError) You must not use 8-bit bytestrings unless you use a text_factory that can interpret 8-bit bytestrings (like text_factory = str). It is highly recommended that you instead just switch your application to Unicode strings. u'SELECT songs.filename AS songs_filename, songs.id AS songs_id, songs.title AS songs_title, songs.album AS songs_album, songs.artist AS songs_artist, songs.mimetype AS songs_mimetype, songs.year AS songs_year, songs.track AS songs_track, songs.disc AS songs_disc, songs.lastmodified AS songs_lastmodified, songs.filesize AS songs_filesize, songs.length AS songs_length \nFROM songs \nWHERE songs.filename = ?' ('/home/dschulz/M\xc3\xbasica/Michel_Petrucciani/Blue_Note/06-Trouble.mp3',)
http://git.zx2c4.com/zmusic-ng/commit/?id=297514d6e6c42057ee...
But I like tabs. Old habit.
> I run subsonic server on my home server and it's quite resource hungry.
Yea, that's the thing about subsonic -- big bloated app. Lots of features, but it needs to start fresh and lean.
On the plus side though, it's super easy to try it out locally using the built-in server:
Give backend/app.cfg the path of the music on your computer. Then run backend/local_server.py. Browse to localhost:5000 in your web browser, and you're set.
I'm curious as to the performance of your implementation? Does it handle a large library of music well?
ZX2C4 Music handles my 100 gigabyte collection without a hitch, and I'm just using sqlite on my box. If I wanted something more intense, I could run this with PostgreSQL or MySQL or MariaDB or something a little bit better primed for performance (zx2c4 music supports multiple database types out of the box). But, even with sqlite, searches are practically instantaneous.
Incidentally, I'm somewhat interested in the protocol: http://git.zx2c4.com/Airtunes2/about/
http://kovyrin.net/2010/07/24/nginx-fu-x-accel-redirect-remo...
One thing that concerns me though is the CPU usage on the client machine. chromium uses roughly ~30% CPU on a 6-core AMD Phenom II running only zmusic. Anyone else seeing this too?
If there's high CPU usage, file a Chrome bug -- it's possibly do to some nastiness in their audio decoder.
If you are looking for feature requests: I'd love to see a last.fm scrobbler integrated.
I really wish there was an nginx header like X-Accel-Redirect called X-Accel-FD where I could pass it a file descriptor to send the data directly, with SIGPIPE set up fine. That way I wouldn't have to buffer from the application process.
Wait a second. Here's an idea -- maybe I can just pass a fifo file to X-Accel-Redirect... I'll give that a whirl. One potential issue here is that it's not going to behave nicely with the client terminating the connection prematurely -- it'll leave a zombified process or a filled pipe or both. So maybe this isn't best then. Any suggestions here? I'd like to not wind up rolling my own nginx module for this.
That said, the current solution works very well, and in my tests works great with several clients transcoding. My server is pretty underpowered, but it doesn't seem to have much of an issue.
In backend/local_server.py, change the line that says:
app.run()
to instead read: app.run(host='0.0.0.0')
You should then be able to access the server at the WLAN IP address of your machine, provided port 5000 is opened by your firewall.Even better, however, would be to use uwsgi in standalone mode. I've updated the README with instructions on this.
it'd be nice during setup if you used the non-minified includes for all the scripts, with the minified paths commented out (or vice versa!)
i was trying to change the default search terms and they were stuck in scripts.min.js
As mentioned in the setup guide, you can build unminifed by setting the DEBUG environment variable to 1:
zmusic-ng $ make clean
zmusic-ng $ DEBUG=1 make
But, for changing the default search terms, just change the config in frontend/js/app.js _before_ running make. I could add some fancy frontend configuration system, but as there is only that one thing to configure at the moment, this is easy enough.For more details, all of this is in the README linked above.
Let me know if you have any other questions or feedback. I'm thrilled someone is already making use of the project.
zmusic-ng $ uwsgi --chdir backend/ -w zmusic:app --http-socket 0.0.0.0:5000
I've updated the README to reflect this suggestion: