Adds more methods to control the queue in the player service.

- Adds : empty queue, shuffle queue, add one song to queue, remove one song from queue, restart the current song
- Removes the "playEnded" method : we now use correctly scope.$apply() in the directive after calling nextTrack(). The next song is correctly called after the end of the current one.
- Starts replacing the old rootScope functions with calls to the player service.
This commit is contained in:
Hyzual 2014-12-21 10:26:29 +01:00
parent f4afa67598
commit 7074e9abc8
8 changed files with 145 additions and 66 deletions

View file

@ -353,6 +353,7 @@
}); });
}; };
$scope.queueEmpty = function () { $scope.queueEmpty = function () {
//TODO: Hyz: Remove
//self.selectedSongs([]); //self.selectedSongs([]);
$rootScope.queue = []; $rootScope.queue = [];
$.fancybox.close(); $.fancybox.close();
@ -369,6 +370,7 @@
} }
}; };
$scope.queueShuffle = function () { $scope.queueShuffle = function () {
//TODO: Hyz: Remove
$rootScope.queue.sort(function () { return 0.5 - Math.random(); }); $rootScope.queue.sort(function () { return 0.5 - Math.random(); });
}; };
$scope.selectedSongs = []; $scope.selectedSongs = [];

View file

@ -12,7 +12,7 @@
<link rel="icon" href="images/favicon_32x32.png" sizes="32x32"/> <link rel="icon" href="images/favicon_32x32.png" sizes="32x32"/>
<!-- build:css(.) styles/vendor.min.css --> <!-- build:css(.) styles/vendor.min.css -->
<!-- bower:css --> <!-- bower:css -->
<link rel="stylesheet" href="bower_components/jplayer/skin/pink.flag/jplayer.pink.flag.css" /> <link rel="stylesheet" href="bower_components/jplayer/dist/skin/pink.flag/jplayer.pink.flag.css" />
<link rel="stylesheet" href="bower_components/fancybox/source/jquery.fancybox.css" /> <link rel="stylesheet" href="bower_components/fancybox/source/jquery.fancybox.css" />
<!-- endbower --> <!-- endbower -->
<!-- endbuild --> <!-- endbuild -->
@ -51,6 +51,7 @@
</div><!-- end #content --> </div><!-- end #content -->
<div id="SideBar" ng-controller="QueueController"> <div id="SideBar" ng-controller="QueueController">
<div class="headeractions"> <div class="headeractions">
<a ng-click="player.restart()">Restart</a>
<a class="buttonimg" title="Shuffle Queue" ng-click="queueShuffle()"><img src="images/fork_gd_11x12.png"></a> <a class="buttonimg" title="Shuffle Queue" ng-click="queueShuffle()"><img src="images/fork_gd_11x12.png"></a>
<a class="buttonimg" id="action_Empty" title="Delete Queue" ng-click="queueEmpty()"><img src="images/trash_fill_gd_12x12.png"></a> <a class="buttonimg" id="action_Empty" title="Delete Queue" ng-click="queueEmpty()"><img src="images/trash_fill_gd_12x12.png"></a>
<a class="buttonimg" id="action_DeleteSelected" title="Remove Selected From Queue" ng-click="queueRemoveSelected()"><img src="images/x_11x11.png"></a> <a class="buttonimg" id="action_DeleteSelected" title="Remove Selected From Queue" ng-click="queueRemoveSelected()"><img src="images/x_11x11.png"></a>

View file

@ -18,7 +18,7 @@ angular.module('jamstash.player.directive', ['jamstash.settings'])
$player.jPlayer({ $player.jPlayer({
// Flash fallback for outdated browser not supporting HTML5 audio/video tags // Flash fallback for outdated browser not supporting HTML5 audio/video tags
// http://jplayer.org/download/ // http://jplayer.org/download/
swfPath: 'bower_components/jplayer/jquery.jplayer/Jplayer.swf', swfPath: 'bower_components/jplayer/dist/jplayer/jquery.jplayer.swf',
wmode: 'window', wmode: 'window',
solution: audioSolution, solution: audioSolution,
supplied: 'mp3', supplied: 'mp3',
@ -35,9 +35,6 @@ angular.module('jamstash.player.directive', ['jamstash.settings'])
currentTime: '#played', currentTime: '#played',
duration: '#duration' duration: '#duration'
}, },
ready: function() {
//Do nothing
},
play: function() { play: function() {
console.log('jplayer play'); console.log('jplayer play');
$('#playermiddle').css('visibility', 'visible'); $('#playermiddle').css('visibility', 'visible');
@ -48,7 +45,8 @@ angular.module('jamstash.player.directive', ['jamstash.settings'])
}, },
ended: function() { ended: function() {
console.log('jplayer ended'); console.log('jplayer ended');
playerService.playEnded(); playerService.nextTrack();
scope.$apply();
} }
}); });
}; };
@ -62,6 +60,16 @@ angular.module('jamstash.player.directive', ['jamstash.settings'])
$player.jPlayer('setMedia', {'mp3': newVal.url}) $player.jPlayer('setMedia', {'mp3': newVal.url})
.jPlayer('play'); .jPlayer('play');
}); });
scope.$watch(function () {
return playerService.restartSong;
}, function (newVal) {
if(newVal === true) {
console.log('restartSong changed !');
$player.jPlayer('play', 0);
playerService.restartSong = false;
}
});
} //end link } //end link
}; };
}]); }]);

View file

@ -5,31 +5,33 @@
*/ */
angular.module('jamstash.player.service', ['jamstash.settings', 'angular-underscore/utils']) angular.module('jamstash.player.service', ['jamstash.settings', 'angular-underscore/utils'])
.factory('player', ['$rootScope', function ($rootScope) { .factory('player', function () {
'use strict'; 'use strict';
var player = { var player = {
queue: [], queue: [],
playingIndex: -1, playingIndex: -1,
playingSong: {}, playingSong: {},
restartSong: false,
play: function(song) { play: function(song) {
console.log('player service - play()', song); console.log('player service - play()', song);
var songIndexInQueue; var songIndexInQueue;
// Find the song's index in the queue, if it's in there // Find the song's index in the queue, if it's in there
_.find(player.queue, function(queuedSong, songIdx){ songIndexInQueue = player.queue.indexOf(song);
if(queuedSong.id === song.id){ songIndexInQueue = songIdx; console.log('sond Index in queue found = ', songIndexInQueue); return true; }
});
console.log('play() playingIndex', player.playingIndex);
player.playingIndex = (songIndexInQueue !== undefined) ? songIndexInQueue : -1; player.playingIndex = (songIndexInQueue !== undefined) ? songIndexInQueue : -1;
console.log('play() playingIndex', player.playingIndex);
console.log('play() playingSong = ', player.playingSong); if(player.playingSong === song) {
// We call restart because the playingSong hasn't changed and the directive won't
// play the song again
player.restart();
} else {
player.playingSong = song; player.playingSong = song;
console.log('play() playingSong = ', player.playingSong); }
}, },
playFirstSong: function() { playFirstSong: function() {
console.log('player service - playFirstSong()');
player.playingIndex = 0; player.playingIndex = 0;
player.play(player.queue[0]); player.play(player.queue[0]);
}, },
@ -40,17 +42,16 @@ angular.module('jamstash.player.service', ['jamstash.settings', 'angular-undersc
restart: function() { restart: function() {
console.log('player service - restart()'); console.log('player service - restart()');
player.restartSong = true;
}, },
nextTrack: function() { nextTrack: function() {
console.log('player service - nextTrack()'); console.log('player service - nextTrack()');
console.log('nextTrack() playingIndex = ', player.playingIndex);
if((player.playingIndex + 1) < player.queue.length) { if((player.playingIndex + 1) < player.queue.length) {
var nextTrack = player.queue[player.playingIndex + 1]; var nextTrack = player.queue[player.playingIndex + 1];
player.playingIndex++; player.playingIndex++;
player.play(nextTrack); player.play(nextTrack);
} }
console.log('nextTrack() playingIndex = ', player.playingIndex);
}, },
previousTrack: function() { previousTrack: function() {
@ -64,10 +65,25 @@ angular.module('jamstash.player.service', ['jamstash.settings', 'angular-undersc
} }
}, },
// TODO: Hyz Special nextTrack for jplayer to call at ended event emptyQueue: function() {
playEnded: function () { console.log('player service - emptyQueue()');
player.nextTrack(); player.queue = [];
$rootScope.$apply(); },
shuffleQueue: function() {
console.log('player service - shuffleQueue()');
player.queue = _.shuffle(player.queue);
},
addSong: function(song) {
console.log('player service - addSong()');
player.queue.push(song);
},
removeSong: function(song) {
console.log('player service - removeSong()');
var index = player.queue.indexOf(song);
player.queue.splice(index, 1);
}, },
getPlayingSong: function() { getPlayingSong: function() {
@ -76,4 +92,4 @@ angular.module('jamstash.player.service', ['jamstash.settings', 'angular-undersc
}; };
return player; return player;
}]); });

View file

@ -1,7 +1,7 @@
describe("Player service -", function() { describe("Player service -", function() {
'use strict'; 'use strict';
var player, firstSong, secondSong; var player, firstSong, secondSong, thirdSong, newSong;
beforeEach(function() { beforeEach(function() {
module('jamstash.player.service'); module('jamstash.player.service');
@ -25,15 +25,19 @@ describe("Player service -", function() {
artist: 'Lura Jeppsen', artist: 'Lura Jeppsen',
album: 'dioptrical' album: 'dioptrical'
}; };
player.queue = [ thirdSong = {
firstSong,
secondSong, {
id: 574, id: 574,
name: 'Celtidaceae', name: 'Celtidaceae',
artist: 'Willard Steury', artist: 'Willard Steury',
album: 'redux' album: 'redux'
} };
]; player.queue = [firstSong, secondSong, thirdSong];
newSong = {
id: 3573,
name: 'Tritopatores',
artist: 'Alysha Rocher',
album: 'uncombinably'
};
}); });
describe("when I call nextTrack", function() { describe("when I call nextTrack", function() {
@ -109,22 +113,28 @@ describe("Player service -", function() {
it("when I play the second song, it finds its index in the playing queue and updates the playing index", function() { it("when I play the second song, it finds its index in the playing queue and updates the playing index", function() {
player.play(secondSong); player.play(secondSong);
expect(player.playingIndex).toBe(1); expect(player.playingIndex).toBe(1);
}); });
it("when I play a song that isn't in the playing queue, the next song will be the first song of the playing queue", function() { it("when I play a song that isn't in the playing queue, the next song will be the first song of the playing queue", function() {
var newSong = {
id: 3573,
name: 'Tritopatores',
artist: 'Alysha Rocher',
album: 'uncombinably'
};
player.play(newSong); player.play(newSong);
expect(player.playingIndex).toBe(-1); expect(player.playingIndex).toBe(-1);
}); });
it("When I call emptyQueue, it empties the playing queue", function() {
player.emptyQueue();
expect(player.queue).toEqual([]);
});
it("When I add a song to the queue, it is appended to the end of the playing queue", function() {
player.addSong(newSong);
expect(player.queue).toEqual([firstSong, secondSong, thirdSong, newSong]);
});
it("When I remove the second song, the playing queue is now only the first and third song", function() {
player.removeSong(secondSong);
expect(player.queue).toEqual([firstSong, thirdSong]);
});
}); });
describe("Given a song", function() { describe("Given a song", function() {
@ -156,6 +166,15 @@ describe("Player service -", function() {
expect(player.getPlayingSong()).toBe(song); expect(player.getPlayingSong()).toBe(song);
expect(song.playing).toBeTruthy(); expect(song.playing).toBeTruthy();
}); });
it("When the song was playing and I play it again, it restarts playback", function() {
spyOn(player, "restart");
player.play(song);
player.play(song);
expect(player.restart).toHaveBeenCalled();
});
}); });
describe("Given that there is no song in my playing queue", function() { describe("Given that there is no song in my playing queue", function() {

View file

@ -5,9 +5,7 @@ angular.module('jamstash.queue.controller', ['jamstash.player.service'])
'use strict'; 'use strict';
$scope.settings = globals.settings; $scope.settings = globals.settings;
$scope.player = player; $scope.player = player;
//$scope.song = player.queue; $scope.itemType = 'pl'; // TODO: Hyz: What is this ?
//angular.copy($rootScope.queue, $scope.song);
$scope.itemType = 'pl';
$scope.playSong = function (song) { $scope.playSong = function (song) {
console.log('Queue Controller - playSong()', song); console.log('Queue Controller - playSong()', song);
@ -15,6 +13,18 @@ angular.module('jamstash.queue.controller', ['jamstash.player.service'])
}; };
$scope.queueEmpty = function() { $scope.queueEmpty = function() {
player.queue = []; player.emptyQueue();
};
$scope.queueShuffle = function() {
player.shuffleQueue();
};
$scope.addSongToQueue = function(song) {
player.addSong(song);
};
$scope.removeSongFromQueue = function(song) {
player.removeSong(song);
}; };
}]); }]);

View file

@ -2,6 +2,9 @@ describe("Queue controller", function() {
'use strict'; 'use strict';
var player, scope, globals; var player, scope, globals;
var song = {
id: 7310
};
beforeEach(function() { beforeEach(function() {
module('jamstash.queue.controller'); module('jamstash.queue.controller');
@ -11,9 +14,6 @@ describe("Queue controller", function() {
globals = _globals_; globals = _globals_;
player = _player_; player = _player_;
// Mock the functions of the services
spyOn(player, "play");
$controller('QueueController', { $controller('QueueController', {
$scope: scope, $scope: scope,
globals: globals, globals: globals,
@ -21,7 +21,9 @@ describe("Queue controller", function() {
}); });
}); });
}); });
it("When I call playSong, it calls play in the player service", function() { it("When I call playSong, it calls play in the player service", function() {
spyOn(player, "play");
var songIndexInQueue = 3; var songIndexInQueue = 3;
scope.playSong(songIndexInQueue); scope.playSong(songIndexInQueue);
@ -29,22 +31,40 @@ describe("Queue controller", function() {
expect(player.play).toHaveBeenCalledWith(songIndexInQueue); expect(player.play).toHaveBeenCalledWith(songIndexInQueue);
}); });
it("When I call queueEmpty, it empties the player's queue", function() { it("When I call queueEmpty, it calls emptyQueue in the player service", function() {
player.queue = [{ spyOn(player, "emptyQueue");
id: 4425,
name: 'Ratiocinator',
artist: 'Kandice Pince',
album: 'Additionally'
}, {
id: 1831,
name: 'Nonteetotaler',
artist: 'Anabel Eady',
album: 'Lyricalness'
}
];
scope.queueEmpty(); scope.queueEmpty();
expect(player.queue).toEqual([]); expect(player.emptyQueue).toHaveBeenCalled();
});
it("When I call queueShuffle, it calls shuffleQueue in the player service", function() {
spyOn(player, "shuffleQueue");
scope.queueShuffle();
expect(player.shuffleQueue).toHaveBeenCalled();
});
it("When I add one song to the queue, it calls addSong in the player service", function() {
spyOn(player, "addSong");
scope.addSongToQueue(song);
expect(player.addSong).toHaveBeenCalledWith(song);
});
xit("When I add many songs to the queue, it calls addSong in the player service", function() {
spyOn(player, "addSong");
});
it("When I remove a song from the queue, it calls removeSong in the player service", function() {
spyOn(player, "removeSong");
scope.removeSongFromQueue(song);
expect(player.removeSong).toHaveBeenCalledWith(song);
}); });
}); });

View file

@ -451,6 +451,9 @@ angular.module('jamstash.subsonic.controller', ['jamstash.subsonic.service', 'ja
$scope.playSong = function (song) { $scope.playSong = function (song) {
player.play(song); player.play(song);
}; };
$scope.addSongToQueue = function(song) {
player.addSong(song);
};
/* Launch on Startup */ /* Launch on Startup */
$scope.getArtists(); $scope.getArtists();