diff --git a/beetsplug/web/__init__.py b/beetsplug/web/__init__.py index dcf383368..50a0c63e6 100644 --- a/beetsplug/web/__init__.py +++ b/beetsplug/web/__init__.py @@ -20,6 +20,7 @@ import beets.library import flask from flask import g import os +import json # Utilities. @@ -49,6 +50,23 @@ def _rep(obj, expand=False): out['items'] = [_rep(item) for item in obj.items()] return out +def json_generator(items, root): + """Generator that dumps list of beets Items or Albums as JSON + + :param root: root key for JSON + :param items: list of :class:`Item` or :class:`Album` to dump + :returns: generator that yields strings + """ + yield '{"%s":[' % root + first = True + for item in items: + if first: + first = False + else: + yield ',' + yield json.dumps(_rep(item)) + yield ']}' + # Flask setup. @@ -67,11 +85,11 @@ def single_item(item_id): return flask.jsonify(_rep(item)) @app.route('/item/') +@app.route('/item/query/') def all_items(): - with g.lib.transaction() as tx: - rows = tx.query("SELECT id FROM items") - all_ids = [row[0] for row in rows] - return flask.jsonify(item_ids=all_ids) + return app.response_class( + json_generator(g.lib.items(), root='items'), + mimetype='application/json') @app.route('/item//file') def item_file(item_id): @@ -96,11 +114,12 @@ def single_album(album_id): return flask.jsonify(_rep(album)) @app.route('/album/') +@app.route('/album/query/') def all_albums(): - with g.lib.transaction() as tx: - rows = tx.query("SELECT id FROM albums") - all_ids = [row[0] for row in rows] - return flask.jsonify(album_ids=all_ids) + return app.response_class( + json_generator(g.lib.albums(), root='albums'), + mimetype='application/json') + @app.route('/album/query/') def album_query(query): diff --git a/test/test_web.py b/test/test_web.py new file mode 100644 index 000000000..d038b410d --- /dev/null +++ b/test/test_web.py @@ -0,0 +1,63 @@ +"""Tests for the 'web' plugin""" + +from _common import unittest +import _common +import json +import beets +import beetsplug +beetsplug.__path__ = ['./beetsplug', '../beetsplug'] +from beetsplug import web + + +class WebPluginTest(_common.LibTestCase): + + def setUp(self): + super(WebPluginTest, self).setUp() + + # Add fixtures + self.lib.add(beets.library.Item( + title = u'another title', + path = 'somepath' + str(_common._item_ident))) + self.lib.add(beets.library.Album()) + self.lib.add(beets.library.Album()) + + web.app.config['TESTING'] = True + web.app.config['lib'] = self.lib + self.client = web.app.test_client() + + def test_get_item(self): + response = self.client.get('/item/') + response.json = json.loads(response.data) + + self.assertEqual(response.status_code, 200) + self.assertEqual(len(response.json['items']), 2) + + def test_get_item_empty_query(self): + response = self.client.get('/item/query/') + response.json = json.loads(response.data) + + self.assertEqual(response.status_code, 200) + self.assertEqual(len(response.json['items']), 2) + + def test_get_album(self): + response = self.client.get('/album/') + response.json = json.loads(response.data) + + self.assertEqual(response.status_code, 200) + self.assertEqual(len(response.json['albums']), 2) + + def test_get_album_empty_query(self): + response = self.client.get('/album/query/') + response.json = json.loads(response.data) + + self.assertEqual(response.status_code, 200) + self.assertEqual(len(response.json['albums']), 2) + + + + +def suite(): + return unittest.TestLoader().loadTestsFromName(__name__) + +if __name__ == '__main__': + unittest.main(defaultTest='suite')