DAAP server framework implemented with Flask
DAAP server for streaming media, built around the Flask micro framework. Supports iTunes, artwork and revisioning.
The Digital Audio Access Protocol (DAAP) is a protocol designed by Apple to share media over the network, using HTTP as transport layer. It advertises itself via Bonjour/Zeroconf.
This Python module implements the full stack, providing a HTTP server (built around Flask), a high-level application layer and Bonjour/Zeroconf advertising.
The DAAP data model consists of the following entities:
There are a few more, but the above ones have been implemented.
A server contains databases, a database contains containers and items, a container contains container items and a container item is a one-to-many mapping between items and containers. While the DAAP client implementation of iTunes only supports one database per server (this is the one that shows up in iTunes), the models does not impose any restrictions. Therefore, this implementation does not keep you from adding multiple databases to a server.
The DAAP protocol efficiently updates the entities. Only deltas are send to the client. For this to work, the server has to add revision (version) numbers to the entities, and map entities to revisions. Because several clients can be on different revisions, it is necessary to keep track of all revisions. When all clients are up to date, the older revisions can be cleaned.
The DAAP protocol assumes that string are encoded as UTF-8. Therefore, you are encouraged to use unicode objects where possible.
Python is a language that does not implement access modifiers (private/protected/public). Therefore, an instance variable can be changed, no matter from where. This makes it harder to implement immutable types. Cython (which converts Python to C), allows you to add these modifiers, in some sense.
Support for immutable types was planned, but dropped for the following reasons:
Do note that this module does not merge objects with the same ID of different revisions. For instance, the following will fail:
db_rev1 = Database(id=1, name="My DB") server.databases.add(db_rev1) server.databases is db_rev1 # Is True db_rev1.items.add(Item(id=1, name="Song 1")) db_rev1.items.add(Item(id=2, name="Song 2")) db_rev1.items.add(Item(id=3, name="Song 3")) db_rev2 = Database(id=2, name="My Updated DB") server.databases.add(db_rev2) server.databases is db_rev2 # Is True len(db_rev1.items) is not len(db_rev2.items) # Reference to items lost because # db_rev1.items was overwritten.
If you want immutability, a correct way is the following:
db_rev2 = copy.copy(server.databases) db_rev2.name = "My DB, version 2" db_rev1.items is db_rev2.items # Is True
The copy can even be skipped if you don’t care about actual immutability and don’t mind that intermediate revision will all be the same:
db_rev3 = server.databases db_rev3.name = "My DB, version 3" db_rev1.items is db_rev2.items is db_rev3.items # Is True db_rev2.name == db_rev3.name # Is True because db_rev3 is not a copy. However, # the revisioning store will detect this as # another update.
Make sure Cython is installed. It is required to boost performance of some modules significantly.
To install, simply run pip install flask-daapserver. It should install all dependencies and compile the Cython-based modules. If you want the latest version, type pip install git+https://github.com/basilfx/flask-daapserver.
The revisioning storage API has changed between version v2.3.0 and v3.0.0. Due to the large overhead of revisioning, it was decided that there should be less memory usage and faster access. While the API has remained similar, a few changes have been made:
To give an idea of the performance impact, the utils/benchmark.py script yielded an improvement of 108MB vs 196MB in memory usage and 0.8375s vs 4.3017s in time (100,000 items, Python 2.7.9, OS X 10.10, 64 Bits).
There are several unit tests included to test core components. The test suite can be invoked using python setup.py nosetests.
Take a look at the examples, or to the projects using Flask-DAAPServer:
There are four examples included in the examples/ directory. You can run them with python examples/<filename>. Check the source for more information and the details.
Feel free to submit a pull request. All pull requests must be made against the development branch. Python code should follow the PEP-8 conventions and tested (if applicable).
See the LICENSE file (MIT license).
Part of this work (DAAP object encoding) is based on the original work of Davyd Madeley.