Fetch users' ID3 genres using Subsonic

Instead of using a predefined list.
This commit is contained in:
Hyzual 2015-05-28 23:12:27 +02:00
parent ba98427b94
commit 0ba6b651b1
5 changed files with 134 additions and 45 deletions

View file

@ -18,7 +18,14 @@ describe("Main controller", function() {
});
// Mock the player service
player = jasmine.createSpyObj("player", ["togglePause", "turnVolumeUp", "turnVolumeDown", "nextTrack", "previousTrack", "setVolume"]);
player = jasmine.createSpyObj("player", [
"togglePause",
"turnVolumeUp",
"turnVolumeDown",
"nextTrack",
"previousTrack",
"setVolume"
]);
player.queue = [];
// Mock the persistence service

View file

@ -510,33 +510,28 @@ angular.module('jamstash.subsonic.service', ['angular-underscore/utils',
deferred.resolve(content);
return deferred.promise;
},
getGenres: function () {
var deferred = $q.defer();
var genresStr = 'Acid Rock,Acoustic,Alt Country,Alt/Indie,Alternative & Punk,Alternative Metal,Alternative,AlternRock,Awesome,Bluegrass,Blues,Blues-Rock,Classic Hard Rock,Classic Rock,Comedy,Country,Country-Rock,Dance,Dance-Rock,Deep Funk,Easy Listening,Electronic,Electronica,Electronica/Dance,Folk,Folk/Rock,Funk,Grunge,Hard Rock,Heavy Metal,Holiday,House,Improg,Indie Rock,Indie,International,Irish,Jam Band,Jam,Jazz Fusion,Jazz,Latin,Live Albums,Metal,Music,Oldies,Other,Pop,Pop/Rock,Post Rock,Progressive Rock,Psychedelic Rock,Psychedelic,Punk,R&B,Rap & Hip-Hop,Reggae,Rock & Roll,Rock,Rock/Pop,Roots,Ska,Soft Rock,Soul,Southern Rock,Thrash Metal,Unknown,Vocal,World';
genres = genresStr.split(',');
/* This is broken in version 4.8, unable to convert XML to JSON
$.ajax({
url: globals.BaseURL() + '/getGenres.view?' + globals.BaseParams(),
method: 'GET',
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
success: function (data) {
if (typeof data["subsonic-response"].genres != 'undefined') {
var items = [];
if (data["subsonic-response"].genres.length > 0) {
items = data["subsonic-response"].genres;
} else {
items[0] = data["subsonic-response"].genres;
}
$rootScope.Genres = items;
$scope.$apply();
getGenres: function () {
var exception = {reason: 'No genre found on the Subsonic server.'};
var promise = subsonicService.subsonicRequest('getGenres.view')
.then(function (subsonicResponse) {
if (subsonicResponse.genres !== undefined && subsonicResponse.genres.genre !== undefined) {
var genreArray = [].concat(subsonicResponse.genres.genre);
if (genreArray.length > 0) {
var stringArray;
if (genreArray[0].value) {
stringArray = _.pluck(genreArray, "value");
// Of course, Madsonic doesn't return the same thing as Subsonic...
} else if (genreArray[0].content) {
stringArray = _.pluck(genreArray, "content");
}
return stringArray;
}
}
// We end up here for every else
return $q.reject(exception);
});
*/
deferred.resolve(genres);
return deferred.promise;
return promise;
},
getPodcasts: function () {

View file

@ -597,7 +597,6 @@ describe("Subsonic service -", function() {
expect(promise).toBeResolvedWith(true);
});
describe("toggleStar() -", function() {
it("Given an item (can be an artist, an album or a song) that wasn't starred, when I toggle its star, then a promise will be resolved with true", function() {
var song = { id: 7748, starred: false };
@ -673,6 +672,64 @@ describe("Subsonic service -", function() {
});
});
describe("getGenres() -", function() {
beforeEach(function() {
url = 'http://demo.subsonic.com/rest/getGenres.view?'+
'c=Jamstash&callback=JSON_CALLBACK&f=jsonp&p=enc:cGFzc3dvcmQ%3D&u=Hyzual&v=1.10.2';
});
it("Given that there were 2 music genres, when I get the genres, then a promise will be resolved with an array of genres", function() {
response["subsonic-response"].genres = {
genre: [
{
value: "copunctal",
songCount: 33,
artistCount: 6,
albumCount: 8
}, {
value: "unsliding",
songCount: 67,
artistCount: 54,
albumCount: 41
}
]
};
mockBackend.expectJSONP(url).respond(JSON.stringify(response));
var promise = subsonic.getGenres();
mockBackend.flush();
expect(promise).toBeResolvedWith(["copunctal", "unsliding"]);
});
it("Given that there was only 1 genre in my Madsonic library, when I get the genres, then a promise will be resolved with an array of 1 genre", function() {
response["subsonic-response"].genres = {
genre: {
value: "periople",
songCount: 53,
artistCount: 7,
albumCount: 74
}
};
mockBackend.expectJSONP(url).respond(JSON.stringify(response));
var promise = subsonic.getGenres();
mockBackend.flush();
expect(promise).toBeResolvedWith(["periople"]);
});
it("Given that there wasn't any genre in my library, when I get the genres, then a promise will be rejected with an error message", function() {
response["subsonic-response"].genres = [];
mockBackend.expectJSONP(url).respond(JSON.stringify(response));
var promise = subsonic.getGenres();
mockBackend.flush();
expect(promise).toBeRejectedWith({reason: 'No genre found on the Subsonic server.'});
});
});
describe("getArtists() -", function() {
beforeEach(function() {
url = 'http://demo.subsonic.com/rest/getIndexes.view?'+

View file

@ -4,7 +4,7 @@
* Access and use the Subsonic Server. The Controller is in charge of relaying the Service's messages to the user through the
* notifications.
*/
angular.module('jamstash.subsonic.controller', ['jamstash.subsonic.service', 'jamstash.player.service', 'jamstash.persistence'])
angular.module('jamstash.subsonic.controller', ['angular-underscore/utils', 'jamstash.subsonic.service', 'jamstash.player.service', 'jamstash.persistence'])
.controller('SubsonicController', ['$scope', '$rootScope', '$routeParams', '$window', 'utils', 'globals', 'map', 'subsonic', 'notifications', 'player', 'persistence',
function ($scope, $rootScope, $routeParams, $window, utils, globals, map, subsonic, notifications, player, persistence) {
@ -574,9 +574,15 @@ angular.module('jamstash.subsonic.controller', ['jamstash.subsonic.service', 'ja
}
}
};
$scope.getGenres = function () {
subsonic.getGenres().then(function (data) {
$scope.Genres = data;
var promise = subsonic.getGenres();
$scope.handleErrors(promise).then(function (genres) {
$scope.Genres = genres;
}, function () {
// Do not display a notification, there simply are no genres.
// Otherwise, a notification will be displayed at every page reload.
$scope.Genres = [];
});
};

View file

@ -47,14 +47,7 @@ describe("Subsonic controller", function() {
]);
// We make them return different promises and use our deferred variable only when testing
// a particular function, so that they stay isolated
subsonic.getAlbums.and.returnValue($q.defer().promise);
subsonic.getArtists.and.returnValue($q.defer().promise);
subsonic.getGenres.and.returnValue($q.defer().promise);
subsonic.getMusicFolders.and.returnValue($q.defer().promise);
subsonic.getPlaylists.and.returnValue($q.defer().promise);
subsonic.getPodcasts.and.returnValue($q.defer().promise);
subsonic.getSongs.and.returnValue($q.defer().promise);
subsonic.recursiveGetSongs.and.returnValue($q.defer().promise);
_.chain(subsonic).pluck('and').invoke("returnValue", $q.defer().promise);
subsonic.showIndex = false;
// Mock the player service
@ -65,9 +58,7 @@ describe("Subsonic controller", function() {
"play",
"playFirstSong"
]);
player.emptyQueue.and.returnValue(player);
player.addSong.and.returnValue(player);
player.addSongs.and.returnValue(player);
_.chain(player).pluck('and').invoke("returnValue", player);
player.queue = [];
$controller = _$controller_;
@ -725,12 +716,12 @@ describe("Subsonic controller", function() {
expect(subsonic.savePlaylist).not.toHaveBeenCalled();
});
describe("When I load the podcasts,", function() {
describe("getPodcasts() -", function() {
beforeEach(function() {
subsonic.getPodcasts.and.returnValue(deferred.promise);
});
it("Given that there were podcasts in the library, then the podcasts will be published to the scope", function() {
it("Given that there were podcasts in the library, When I load the podcasts, then the podcasts will be published to the scope", function() {
scope.getPodcasts();
deferred.resolve([
{id: 9775},
@ -747,7 +738,7 @@ describe("Subsonic controller", function() {
]);
});
it("Given that there weren't any podcast in the library, then an empty array will be published to the scope and the user won't be notified with an error message", function() {
it("Given that there wasn't any podcast in the library, When I load the podcasts, then an empty array will be published to the scope and the user won't be notified", function() {
scope.getPodcasts();
deferred.reject({reason: 'No podcast found on the Subsonic server.'});
scope.$apply();
@ -758,7 +749,40 @@ describe("Subsonic controller", function() {
});
});
describe("getMusicFolders", function() {
describe("getGenres() -", function() {
beforeEach(function() {
subsonic.getGenres.and.returnValue(deferred.promise);
});
it("Given that there were music genres in the library, when I get the genres, then the genre names will be published to the scope", function() {
scope.getGenres();
deferred.resolve([
"matriarchalism",
"Glyptodontidae",
"archcozener"
]);
scope.$apply();
expect(subsonic.getGenres).toHaveBeenCalled();
expect(scope.Genres).toEqual([
"matriarchalism",
"Glyptodontidae",
"archcozener"
]);
});
it("Given that there wasn't any music genre in the library, when I get the genres, then an empty array will be published to the scope and the user won't be notified", function() {
scope.getGenres();
deferred.reject({reason: 'No genre found on the Subsonic server.'});
scope.$apply();
expect(subsonic.getGenres).toHaveBeenCalled();
expect(scope.Genres).toEqual([]);
expect(notifications.updateMessage).not.toHaveBeenCalled();
});
});
describe("getMusicFolders() -", function() {
beforeEach(function() {
subsonic.getMusicFolders.and.returnValue(deferred.promise);
});