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 // 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 = []; player.queue = [];
// Mock the persistence service // Mock the persistence service

View file

@ -510,33 +510,28 @@ angular.module('jamstash.subsonic.service', ['angular-underscore/utils',
deferred.resolve(content); deferred.resolve(content);
return deferred.promise; 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; getGenres: function () {
$scope.$apply(); 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);
}); });
*/ return promise;
deferred.resolve(genres);
return deferred.promise;
}, },
getPodcasts: function () { getPodcasts: function () {

View file

@ -597,7 +597,6 @@ describe("Subsonic service -", function() {
expect(promise).toBeResolvedWith(true); expect(promise).toBeResolvedWith(true);
}); });
describe("toggleStar() -", function() { 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() { 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 }; 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() { describe("getArtists() -", function() {
beforeEach(function() { beforeEach(function() {
url = 'http://demo.subsonic.com/rest/getIndexes.view?'+ 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 * Access and use the Subsonic Server. The Controller is in charge of relaying the Service's messages to the user through the
* notifications. * 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', .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) { 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 () { $scope.getGenres = function () {
subsonic.getGenres().then(function (data) { var promise = subsonic.getGenres();
$scope.Genres = data; $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 // We make them return different promises and use our deferred variable only when testing
// a particular function, so that they stay isolated // a particular function, so that they stay isolated
subsonic.getAlbums.and.returnValue($q.defer().promise); _.chain(subsonic).pluck('and').invoke("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);
subsonic.showIndex = false; subsonic.showIndex = false;
// Mock the player service // Mock the player service
@ -65,9 +58,7 @@ describe("Subsonic controller", function() {
"play", "play",
"playFirstSong" "playFirstSong"
]); ]);
player.emptyQueue.and.returnValue(player); _.chain(player).pluck('and').invoke("returnValue", player);
player.addSong.and.returnValue(player);
player.addSongs.and.returnValue(player);
player.queue = []; player.queue = [];
$controller = _$controller_; $controller = _$controller_;
@ -725,12 +716,12 @@ describe("Subsonic controller", function() {
expect(subsonic.savePlaylist).not.toHaveBeenCalled(); expect(subsonic.savePlaylist).not.toHaveBeenCalled();
}); });
describe("When I load the podcasts,", function() { describe("getPodcasts() -", function() {
beforeEach(function() { beforeEach(function() {
subsonic.getPodcasts.and.returnValue(deferred.promise); 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(); scope.getPodcasts();
deferred.resolve([ deferred.resolve([
{id: 9775}, {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(); scope.getPodcasts();
deferred.reject({reason: 'No podcast found on the Subsonic server.'}); deferred.reject({reason: 'No podcast found on the Subsonic server.'});
scope.$apply(); 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() { beforeEach(function() {
subsonic.getMusicFolders.and.returnValue(deferred.promise); subsonic.getMusicFolders.and.returnValue(deferred.promise);
}); });