2 * Copyright (C) 2005-2010 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
22 var MediaLibrary = function() {
27 MediaLibrary.prototype = {
35 bindControls: function() {
36 $('#musicLibrary').click(jQuery.proxy(this.musicLibraryOpen, this));
37 $('#movieLibrary').click(jQuery.proxy(this.movieLibraryOpen, this));
38 $('#tvshowLibrary').click(jQuery.proxy(this.tvshowLibraryOpen, this));
39 $('#pictureLibrary').click(jQuery.proxy(this.pictureLibraryOpen, this));
40 $('#remoteControl').click(jQuery.proxy(this.remoteControlOpen, this));
41 $('#overlay').click(jQuery.proxy(this.hideOverlay, this));
42 $(window).resize(jQuery.proxy(this.updatePlayButtonLocation, this));
44 resetPage: function() {
45 $('#musicLibrary').removeClass('selected');
46 $('#movieLibrary').removeClass('selected');
47 $('#tvshowLibrary').removeClass('selected');
48 $('#remoteControl').removeClass('selected');
49 $('#pictureLibrary').removeClass('selected');
52 replaceAll: function(haystack, find, replace) {
53 var parts = haystack.split(find);
63 result += parts[index];
69 getPlaylists: function() {
72 url: JSON_RPC + '?GetPlaylists',
73 data: '{"jsonrpc": "2.0", "method": "Playlist.GetPlaylists", "id": 1}',
75 success: jQuery.proxy(function(data) {
76 if (data && data.result && data.result.length > 0) {
77 $.each($(data.result), jQuery.proxy(function(i, item) {
78 this.playlists[item.type] = item.playlistid;
82 error: jQuery.proxy(function(data, error) {
83 displayCommunicationError();
84 setTimeout(jQuery.proxy(this.updateState, this), 2000);
88 remoteControlOpen: function(event) {
90 $('#remoteControl').addClass('selected');
91 $('.contentContainer').hide();
92 var libraryContainer = $('#remoteContainer');
93 if (!libraryContainer || libraryContainer.length == 0) {
95 libraryContainer = $('<div>');
96 libraryContainer.attr('id', 'remoteContainer')
97 .addClass('contentContainer');
98 $('#content').append(libraryContainer);
100 {name:'up',width:'40px',height:'30px',top:'28px',left:'58px'}
101 ,{name:'down',width:'40px',height:'30px',top:'122px',left:'58px'}
102 ,{name:'left',width:'40px',height:'30px',top:'74px',left:'15px'}
103 ,{name:'right',width:'40px',height:'30px',top:'74px',left:'104px'}
104 ,{name:'ok',width:'40px',height:'30px',top:'74px',left:'58px'}
105 ,{name:'back',width:'40px',height:'30px',top:'13px',left:'161px'}
106 ,{name:'home',width:'40px',height:'30px',top:'154px',left:'8px'}
107 ,{name:'mute',width:'40px',height:'30px',top:'107px',left:'391px'}
108 ,{name:'power',width:'30px',height:'30px',top:'-3px',left:'13px'}
109 ,{name:'volumeup',width:'30px',height:'30px',top:'49px',left:'422px'}
110 ,{name:'volumedown',width:'30px',height:'30px',top:'49px',left:'367px'}
111 ,{name:'playpause',width:'32px',height:'23px',top:'62px',left:'260px'}
112 ,{name:'stop',width:'32px',height:'23px',top:'62px',left:'211px'}
113 ,{name:'next',width:'38px',height:'25px',top:'102px',left:'304px'}
114 ,{name:'previous',width:'38px',height:'25px',top:'101px',left:'160px'}
115 ,{name:'forward',width:'32px',height:'23px',top:'102px',left:'259px'}
116 ,{name:'rewind',width:'32px',height:'23px',top:'101px',left:'211px'}
117 ,{name:'cleanlib_a',width:'46px',height:'26px',top:'47px',left:'553px'}
118 ,{name:'updatelib_a',width:'46px',height:'26px',top:'47px',left:'492px'}
119 ,{name:'cleanlib_v',width:'46px',height:'26px',top:'111px',left:'553px'}
120 ,{name:'updatelib_v',width:'46px',height:'26px',top:'111px',left:'492px'}
122 for (var akey in keys) {
123 var aremotekey=$('<p>').attr('id',keys[akey]['name']);
124 aremotekey.addClass('remote_key')
125 .css('height',keys[akey]['height'])
126 .css('width',keys[akey]['width'])
127 .css('top',keys[akey]['top'])
128 .css('left',keys[akey]['left'])
129 //.css('border','1px solid black')
130 .bind('click',{key: keys[akey]['name']},jQuery.proxy(this.pressRemoteKey,this));
131 libraryContainer.append(aremotekey);
136 libraryContainer.show();
137 libraryContainer.trigger('scroll');
140 $('#spinner').hide();
143 pressRemoteKey: function(event) {
144 var keyPressed=event.data.key;
145 $('#spinner').show();
147 // TODO: Get active player
148 if($('#videoDescription').is(':visible'))
149 player = this.playlists["video"];
150 else if($('#audioDescription').is(':visible'))
151 player = this.playlists["audio"];
156 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "AudioLibrary.Clean", "id": 1}', function(data){$('#spinner').hide();}, 'json');
159 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "AudioLibrary.Scan", "id": 1}', function(data){$('#spinner').hide();}, 'json');
162 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "VideoLibrary.Clean", "id": 1}', function(data){$('#spinner').hide();}, 'json');
165 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "VideoLibrary.Scan", "id": 1}', function(data){$('#spinner').hide();}, 'json');
168 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "Input.Back", "id": 1}', function(data){$('#spinner').hide();}, 'json');
171 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "Input.Home", "id": 1}', function(data){$('#spinner').hide();}, 'json');
174 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "Application.ToggleMute", "id": 1}', function(data){$('#spinner').hide();}, 'json');
177 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "System.Shutdown", "id": 1}', function(data){$('#spinner').hide();}, 'json');
180 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "Application.GetProperties", "params": { "properties": [ "volume" ] }, "id": 1}', function(data){
181 var volume = data.result.volume + 1;
182 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "Application.SetVolume", "params": { "value": '+volume+' }, "id": 1}', function(data){
184 $('#spinner').hide();
189 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "Application.GetProperties", "params": { "properties": [ "volume" ] }, "id": 1}', function(data){
190 var volume = data.result.volume - 1;
191 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "Application.SetVolume", "params": { "value": '+volume+' }, "id": 1}', function(data){
193 $('#spinner').hide();
198 //menus or other sections
203 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "Input.Up", "id": 1}', function(data){$('#spinner').hide();}, 'json');
206 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "Input.Down", "id": 1}', function(data){$('#spinner').hide();}, 'json');
209 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "Input.Left", "id": 1}', function(data){$('#spinner').hide();}, 'json');
212 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "Input.Right", "id": 1}', function(data){$('#spinner').hide();}, 'json');
215 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "Input.Select", "id": 1}', function(data){$('#spinner').hide();}, 'json');
224 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "Player.Seek", "params": { "playerid": ' + player + ', "value": "bigforward" }, "id": 1}', function(data){$('#spinner').hide();}, 'json');
227 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "Player.Seek", "params": { "playerid": ' + player + ', "value": "bigbackward" }, "id": 1}', function(data){$('#spinner').hide();}, 'json');
230 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "Player.Seek", "params": { "playerid": ' + player + ', "value": "smallbackward" }, "id": 1}', function(data){$('#spinner').hide();}, 'json');
233 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "Player.Seek", "params": { "playerid": ' + player + ', "value": "smallforward" }, "id": 1}', function(data){$('#spinner').hide();}, 'json');
236 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "Player.PlayPause", "params": { "playerid": ' + player + ' }, "id": 1}', function(data){$('#spinner').hide();}, 'json');
239 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "Player.Stop", "params": { "playerid": ' + player + ' }, "id": 1}', function(data){$('#spinner').hide();}, 'json');
242 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "Player.GoNext", "params": { "playerid": ' + player + ' }, "id": 1}', function(data){$('#spinner').hide();}, 'json');
245 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "Player.GoPrevious", "params": { "playerid": ' + player + ' }, "id": 1}', function(data){$('#spinner').hide();}, 'json');
248 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "Player.SetSpeed", "params": { "playerid": ' + player + ', "speed": "increment" }, "id": 1}', function(data){$('#spinner').hide();}, 'json');
251 jQuery.post(JSON_RPC + '?SendRemoteKey', '{"jsonrpc": "2.0", "method": "Player.SetSpeed", "params": { "playerid": ' + player + ', "speed": "decrement" }, "id": 1}', function(data){$('#spinner').hide();}, 'json');
257 musicLibraryOpen: function(event) {
259 $('#musicLibrary').addClass('selected');
260 $('.contentContainer').hide();
261 var libraryContainer = $('#libraryContainer');
262 if (!libraryContainer || libraryContainer.length == 0) {
263 $('#spinner').show();
264 libraryContainer = $('<div>');
265 libraryContainer.attr('id', 'libraryContainer')
266 .addClass('contentContainer');
267 $('#content').append(libraryContainer);
268 jQuery.post(JSON_RPC + '?GetAlbums', '{"jsonrpc": "2.0", "method": "AudioLibrary.GetAlbums", "params": { "limits": { "start": 0 }, "properties": ["description", "theme", "mood", "style", "type", "label", "artist", "genre", "rating", "title", "year", "thumbnail"], "sort": { "method": "artist" } }, "id": 1}', jQuery.proxy(function(data) {
269 if (data && data.result && data.result.albums) {
270 this.albumList = data.result.albums;
271 $.each($(this.albumList), jQuery.proxy(function(i, item) {
272 var floatableAlbum = this.generateThumb('album', item.thumbnail, item.title, item.artist);
273 floatableAlbum.bind('click', { album: item }, jQuery.proxy(this.displayAlbumDetails, this));
274 libraryContainer.append(floatableAlbum);
276 libraryContainer.append($('<div>').addClass('footerPadding'));
277 $('#spinner').hide();
278 libraryContainer.bind('scroll', { activeLibrary: libraryContainer }, jQuery.proxy(this.updateScrollEffects, this));
279 libraryContainer.trigger('scroll');
280 myScroll = new iScroll('libraryContainer');
282 libraryContainer.html('');
286 libraryContainer.show();
287 libraryContainer.trigger('scroll');
290 getThumbnailPath: function(thumbnail) {
291 return thumbnail ? ('/vfs/' + thumbnail) : DEFAULT_ALBUM_COVER;
293 generateThumb: function(type, thumbnail, title, artist) {
294 var floatableAlbum = $('<div>');
295 var path = this.getThumbnailPath(thumbnail);
297 artist = artist ||'';
298 if (title.length > 18 && !(title.length <= 21)) {
299 title = title.substring(0, 18) + '...';
301 if (artist.length > 20 && !(artist.length <= 22)) {
302 artist = artist.substring(0, 20) + '...';
308 className = 'floatableAlbum';
309 code = '<p class="album" title="' + title + '">' + title + '</p><p class="artist" title="' + artist + '">' + artist + '</p>';
312 className = 'floatableMovieCover';
313 code = '<p class="album" title="' + title + '">' + title + '</p>';
316 className = 'floatableTVShowCover';
319 className = 'floatableTVShowCoverSeason';
323 className = 'floatableAlbum';
324 code = '<p class="album" title="' + title + '">' + title + '</p>';
327 return floatableAlbum.addClass(className).html('<div class="imgWrapper"><div class="inner"><img src="' + path + '" alt="' + title + '" /></div></div>' + code);
329 showAlbumSelectorBlock: function(album) {
331 //Find album in stored array
332 var prevAlbum = null,
334 $.each($(this.albumList), jQuery.proxy(function(i, item) {
335 if (item.albumid == album.albumid) {
336 if (this.albumList.length > 1) {
337 prevAlbum = this.albumList[i <= 0 ? this.albumList.length-1 : i-1];
338 nextAlbum = this.albumList[i >= this.albumList.length ? 0 : i+1];
340 return false; /* .each break */
343 var albumSelectorBlock = $('#albumSelector');
344 if (!albumSelectorBlock || albumSelectorBlock.length == 0) {
345 albumSelectorBlock = $('<div>');
346 albumSelectorBlock.attr('id', 'albumSelector')
347 .html('<table><tr><td class="allAlbums">All Albums</td><td class="activeAlbumTitle"></td><td class="prevAlbum"> </td><td class="nextAlbum"> </td></tr></table>');
348 $('#content').prepend(albumSelectorBlock);
349 $('#albumSelector .allAlbums').bind('click', jQuery.proxy(this.hideAlbumDetails, this));
351 $('#albumSelector .prevAlbum').unbind();
352 $('#albumSelector .nextAlbum').unbind();
354 $('#albumSelector .prevAlbum').bind('click', {album: prevAlbum}, jQuery.proxy(this.displayAlbumDetails, this));
357 $('#albumSelector .nextAlbum').bind('click', {album: nextAlbum}, jQuery.proxy(this.displayAlbumDetails, this));
359 $('#albumSelector .activeAlbumTitle').html(album.title||'Unknown Album');
360 albumSelectorBlock.show();
363 hideAlbumDetails: function() {
364 $('.contentContainer').hide();
365 this.musicLibraryOpen();
367 displayAlbumDetails: function(event) {
368 this.showAlbumSelectorBlock(event.data.album);
369 var albumDetailsContainer = $('#albumDetails' + event.data.album.albumid);
370 $('#topScrollFade').hide();
371 if (!albumDetailsContainer || albumDetailsContainer.length == 0) {
372 $('#spinner').show();
373 jQuery.post(JSON_RPC + '?GetSongs', '{"jsonrpc": "2.0", "method": "AudioLibrary.GetSongs", "params": { "properties": ["title", "artist", "genre", "track", "duration", "year", "rating", "playcount"], "albumid" : ' + event.data.album.albumid + ' }, "id": 1}', jQuery.proxy(function(data) {
374 albumDetailsContainer = $('<div>');
375 albumDetailsContainer.attr('id', 'albumDetails' + event.data.album.albumid)
376 .addClass('contentContainer')
377 .addClass('albumContainer')
378 .html('<table class="albumView"><thead><tr class="headerRow"><th>Artwork</th><th> </th><th>Name</th><th class="time">Time</th><th>Artist</th><th>Genre</th></tr></thead><tbody class="resultSet"></tbody></table>');
379 $('.contentContainer').hide();
380 $('#content').append(albumDetailsContainer);
381 var albumThumbnail = event.data.album.thumbnail;
382 var albumTitle = event.data.album.title||'Unknown Album';
383 var albumArtist = event.data.album.artist||'Unknown Artist';
384 var trackCount = data.result.limits.total;
385 $.each($(data.result.songs), jQuery.proxy(function(i, item) {
387 var trackRow = $('<tr>').addClass('trackRow').addClass('tr' + i % 2);
388 trackRow.append($('<td>').attr('rowspan', ++trackCount + 1).addClass('albumThumb'));
389 for (var a = 0; a < 5; a++) {
390 trackRow.append($('<td>').html(' ').attr('style', 'display: none'));
392 $('#albumDetails' + event.data.album.albumid + ' .resultSet').append(trackRow);
394 var trackRow = $('<tr>').addClass('trackRow').addClass('tr' + i % 2).bind('click', { album: event.data.album, itmnbr: i }, jQuery.proxy(this.playTrack,this));
395 var trackNumberTD = $('<td>')
398 trackRow.append(trackNumberTD);
399 var trackTitleTD = $('<td>')
402 trackRow.append(trackTitleTD);
403 var trackDurationTD = $('<td>')
405 .html(durationToString(item.duration));
407 trackRow.append(trackDurationTD);
408 var trackArtistTD = $('<td>')
411 trackRow.append(trackArtistTD);
412 var trackGenreTD = $('<td>')
415 trackRow.append(trackGenreTD);
416 $('#albumDetails' + event.data.album.albumid + ' .resultSet').append(trackRow);
418 if (trackCount > 0) {
419 var trackRow = $('<tr>').addClass('fillerTrackRow');
420 for (var i = 0; i < 5; i++) {
421 trackRow.append($('<td>').html(' '));
423 $('#albumDetails' + event.data.album.albumid + ' .resultSet').append(trackRow);
425 var trackRow2 = $('<tr>').addClass('fillerTrackRow2');
426 trackRow2.append($('<td>').addClass('albumBG').html(' '));
427 for (var i = 0; i < 5; i++) {
428 trackRow2.append($('<td>').html(' '));
430 $('#albumDetails' + event.data.album.albumid + ' .resultSet').append(trackRow2);
432 $('#albumDetails' + event.data.album.albumid + ' .albumThumb')
433 .append(this.generateThumb('album', albumThumbnail, albumTitle, albumArtist))
434 .append($('<div>').addClass('footerPadding'));
435 $('#spinner').hide();
436 myScroll = new iScroll('albumDetails' + event.data.album.albumid);
439 $('.contentContainer').hide();
440 $('#albumDetails' + event.data.album.albumid).show();
444 togglePosterView: function(event){
445 var view=event.data.mode;
446 var wthumblist,hthumblist,hthumbdetails;
447 $("#toggleBanner").removeClass('activeMode');
448 $("#togglePoster").removeClass('activeMode');
449 $("#toggleLandscape").removeClass('activeMode');
452 setCookie('TVView','poster');
455 hthumbdetails='559px';
456 $("#togglePoster").addClass('activeMode');
459 setCookie('TVView','landscape');
462 hthumbdetails='213px';
463 $("#toggleLandscape").addClass('activeMode');
465 default: //set banner view as default
466 setCookie('TVView','banner');
469 hthumbdetails='70px';
470 $("#toggleBanner").addClass('activeMode');
473 $(".floatableTVShowCover, .floatableTVShowCover div.imgWrapper, .floatableTVShowCover img, .floatableTVShowCover div.imgWrapper div.inner").css('width',wthumblist).css('height',hthumblist);
474 $(".floatableTVShowCoverSeason div.imgWrapper, .floatableTVShowCoverSeason div.imgWrapper div.inner,.floatableTVShowCoverSeason img, .floatableTVShowCoverSeason").css('height',hthumbdetails);
477 displayTVShowDetails: function(event) {
478 var tvshowDetailsContainer = $('#tvShowDetails' + event.data.tvshow.tvshowid);
479 $('#topScrollFade').hide();
480 toggle=this.toggle.detach();
481 if (!tvshowDetailsContainer || tvshowDetailsContainer.length == 0) {
482 $('#spinner').show();
483 jQuery.post(JSON_RPC + '?GetTVShowSeasons', '{"jsonrpc": "2.0", "method": "VideoLibrary.GetSeasons", "params": { "properties": [ "season", "showtitle", "playcount", "episode", "thumbnail","fanart" ], "tvshowid" : ' + event.data.tvshow.tvshowid + ' }, "id": 1}', jQuery.proxy(function(data) {
484 tvshowDetailsContainer = $('<div>');
485 tvshowDetailsContainer.attr('id', 'tvShowDetails' + event.data.tvshow.tvshowid)
486 .css('display', 'none')
487 .addClass('contentContainer')
488 .addClass('tvshowContainer');
489 var showThumb = this.generateThumb('tvshowseason', event.data.tvshow.thumbnail, event.data.tvshow.title);
490 if (data && data.result && data.result.seasons && data.result.seasons.length > 0) {
491 var showDetails = $('<div>').addClass('showDetails');
492 showDetails.append(toggle);
493 showDetails.append($('<p>').html(data.result.seasons[0].showtitle).addClass('showTitle'));
494 var seasonSelectionSelect = $('<select>').addClass('seasonPicker');
495 //var episodeCount = 0;
496 this.tvActiveShowContainer = tvshowDetailsContainer;
498 $.each($(data.result.seasons), jQuery.proxy(function(i, item) {
499 // if(fanart==null && item.fanart!=null){
500 // fanart=item.fanart;
502 // //episodeCount += item.episode;
503 var season = $('<option>').attr('value',i);
504 season.text(item.label);
505 seasonSelectionSelect.append(season);
510 // $('.contentContainer').css('background','url("'+this.getThumbnailPath(fanart)+'")').css('background-size','cover');
512 seasonSelectionSelect.bind('change', {tvshow: event.data.tvshow.tvshowid, seasons: data.result.seasons, element: seasonSelectionSelect}, jQuery.proxy(this.displaySeasonListings, this));
513 //showDetails.append($('<p>').html('<span class="heading">Episodes:</span> ' + episodeCount));
514 showDetails.append(seasonSelectionSelect);
515 tvshowDetailsContainer.append(showDetails);
516 tvshowDetailsContainer.append(showThumb);
517 seasonSelectionSelect.trigger('change');
518 $('#content').append(tvshowDetailsContainer);
519 if(getCookie('TVView')!=null && getCookie('TVView')!='banner'){
520 var view=getCookie('TVView');
523 togglePoster.trigger('click');
526 toggleLandscape.trigger('click')
530 tvshowDetailsContainer.fadeIn();
532 $('#spinner').hide();
535 $('.contentContainer').hide();
536 $('#tvShowDetails' + event.data.tvshow.tvshowid).show();
537 $('#tvShowDetails' + event.data.tvshow.tvshowid +' select').trigger('change');
540 displaySeasonListings: function(event) {
541 //retrieve selected season
542 var selectedVal=event.data.element.val();
543 var seasons=event.data.seasons;
544 $('#topScrollFade').hide();
546 var oldListings = $('.episodeListingsContainer', this.tvActiveShowContainer).fadeOut();
547 //Update ActiveSeason
548 this.tvActiveSeason = selectedVal;
549 //Populate new listings
550 jQuery.post(JSON_RPC + '?GetTVSeasonEpisodes', '{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": { "properties": [ "title", "thumbnail","episode","plot","season"], "season" : ' + seasons[selectedVal].season + ', "tvshowid" : ' + event.data.tvshow + ' }, "id": 1}', jQuery.proxy(function(data) {
551 var episodeListingsContainer = $('<div>').addClass('episodeListingsContainer');
552 var episodeTable= $('<table>').addClass('seasonView').html('<thead><tr class="headerRow"><th class="thumbHeader">N°</th><th>Title</th><th class="thumbHeader">Thumb</th><th class="thumbHeader">Details</th></tr></thead><tbody class="resultSet"></tbody>');
553 $.each($(data.result.episodes), jQuery.proxy(function(i, item) {
554 var episodeRow = $('<tr>').addClass('episodeRow').addClass('tr' + i % 2);
555 var episodePictureImg = $('<img>').bind('click', { episode: item }, jQuery.proxy(this.playTVShow, this)).css('cursor','pointer');
556 episodePictureImg.attr('src', this.getThumbnailPath(item.thumbnail));
557 var episodePicture=$('<td>').addClass('episodeThumb').append(episodePictureImg).bind('click', { episode: item }, jQuery.proxy(this.playTVShow, this));
558 var episodeNumber = $('<td>').addClass('episodeNumber').html(item.episode).bind('click', { episode: item }, jQuery.proxy(this.playTVShow, this));
559 var episodeTitle = $('<td>').html(item.title).bind('click', { episode: item }, jQuery.proxy(this.playTVShow, this));
560 var episodeDetails = $('<td class="info">').html('').bind('click',{episode:item}, jQuery.proxy(this.displayEpisodeDetails, this)).css('cursor','pointer');
561 episodeRow.append(episodeNumber).append(episodeTitle).append(episodePicture).append(episodeDetails);
562 episodeTable.append(episodeRow);
564 episodeListingsContainer.append(episodeTable);
565 $(this.tvActiveShowContainer).append(episodeListingsContainer);
570 displayEpisodeDetails: function(event) {
571 var episodeDetails = $('<div>').attr('id', 'episode-' + event.data.episode.episodeid).addClass('episodePopoverContainer');
572 episodeDetails.append($('<img>').attr('src', '/images/close-button.png').addClass('closeButton').bind('click', jQuery.proxy(this.hideOverlay, this)));
573 episodeDetails.append($('<img>').attr('src', this.getThumbnailPath(event.data.episode.thumbnail)).addClass('episodeCover'));
574 episodeDetails.append($('<div>').addClass('playIcon').bind('click', {episode: event.data.episode}, jQuery.proxy(this.playTVShow, this)));
575 var episodeTitle = $('<p>').addClass('episodeTitle');
576 var yearText = event.data.episode.year ? ' <span class="year">(' + event.data.episode.year + ')</span>' : '';
577 episodeTitle.html(event.data.episode.title + yearText);
578 episodeDetails.append(episodeTitle);
579 if (event.data.episode.runtime) {
580 episodeDetails.append($('<p>').addClass('runtime').html('<strong>Runtime:</strong> ' + event.data.epispde.runtime + ' minutes'));
582 if (event.data.episode.season) {
583 episodeDetails.append($('<p>').addClass('season').html('<strong>Season:</strong> ' + event.data.episode.season));
585 if (event.data.episode.episode) {
586 episodeDetails.append($('<p>').addClass('episode').html('<strong>Episode:</strong> ' + event.data.episode.episode));
588 if (event.data.episode.plot) {
589 episodeDetails.append($('<p>').addClass('plot').html('<strong>Plot:</strong> <br/><br/>' +event.data.episode.plot));
591 if (event.data.episode.genre) {
592 episodeDetails.append($('<p>').addClass('genre').html('<strong>Genre:</strong> ' + event.data.episode.genre));
594 if (event.data.episode.rating) {
597 if (event.data.episode.director) {
598 episodeDetails.append($('<p>').addClass('director').html('<strong>Directed By:</strong> ' + event.data.episode.director));
600 this.activeCover = episodeDetails;
601 $('body').append(episodeDetails);
602 $('#overlay').show();
603 this.updatePlayButtonLocation();
606 playTVShow: function(event) {
607 jQuery.post(JSON_RPC + '?AddTvShowToPlaylist', '{"jsonrpc": "2.0", "method": "Player.Open", "params": { "item": { "episodeid": ' + event.data.episode.episodeid + ' } }, "id": 1}', jQuery.proxy(function(data) {
611 hideOverlay: function(event) {
612 if (this.activeCover) {
613 $(this.activeCover).remove();
614 this.activeCover = null;
616 $('#overlay').hide();
618 updatePlayButtonLocation: function(event) {
619 var movieContainer = $('.movieCover');
620 if (movieContainer.length > 0) {
621 var playIcon = $('.playIcon');
622 if (playIcon.length > 0) {
623 var heightpi=$(movieContainer[0]).height();
624 playIcon.width(Math.floor(0.65*heightpi));
625 playIcon.height(heightpi);
628 var episodeContainer = $('.episodeCover');
629 if (episodeContainer.length > 0) {
630 var playIcon = $('.playIcon');
631 if (playIcon.length > 0) {
632 var widthpi=$(episodeContainer[0]).width();
633 playIcon.width(widthpi);
635 playIcon.height(Math.floor(widthpi*9/16));
639 playMovie: function(event) {
640 jQuery.post(JSON_RPC + '?PlayMovie', '{"jsonrpc": "2.0", "method": "Player.Open", "params": { "item": { "movieid": ' + event.data.movie.movieid + ' } }, "id": 1}', jQuery.proxy(function(data) {
644 displayMovieDetails: function(event) {
645 var movieDetails = $('<div>').attr('id', 'movie-' + event.data.movie.movieid).addClass('moviePopoverContainer');
646 movieDetails.append($('<img>').attr('src', '/images/close-button.png').addClass('closeButton').bind('click', jQuery.proxy(this.hideOverlay, this)));
647 movieDetails.append($('<img>').attr('src', this.getThumbnailPath(event.data.movie.thumbnail)).addClass('movieCover'));
648 movieDetails.append($('<div>').addClass('playIcon').bind('click', {movie: event.data.movie}, jQuery.proxy(this.playMovie, this)));
649 var movieTitle = $('<p>').addClass('movieTitle');
650 var yearText = event.data.movie.year ? ' <span class="year">(' + event.data.movie.year + ')</span>' : '';
651 movieTitle.html(event.data.movie.title + yearText);
652 movieDetails.append(movieTitle);
653 if (event.data.movie.runtime) {
654 movieDetails.append($('<p>').addClass('runtime').html('<strong>Runtime:</strong> ' + event.data.movie.runtime + ' minutes'));
656 if (event.data.movie.plot) {
657 movieDetails.append($('<p>').addClass('plot').html(event.data.movie.plot));
659 if (event.data.movie.genre) {
660 movieDetails.append($('<p>').addClass('genre').html('<strong>Genre:</strong> ' + event.data.movie.genre));
662 if (event.data.movie.rating) {
665 if (event.data.movie.director) {
666 movieDetails.append($('<p>').addClass('director').html('<strong>Directed By:</strong> ' + event.data.movie.director));
668 this.activeCover = movieDetails;
669 $('body').append(movieDetails);
670 $('#overlay').show();
671 this.updatePlayButtonLocation();
673 playTrack: function(event) {
674 jQuery.post(JSON_RPC + '?ClearPlaylist', '{"jsonrpc": "2.0", "method": "Playlist.Clear", "params": { "playlistid": ' + this.playlists["audio"] + ' }, "id": 1}', jQuery.proxy(function(data) {
675 //check that clear worked.
676 jQuery.post(JSON_RPC + '?AddAlbumToPlaylist', '{"jsonrpc": "2.0", "method": "Playlist.Add", "params": { "playlistid": ' + this.playlists["audio"] + ', "item": { "albumid": ' + event.data.album.albumid + ' } }, "id": 1}', jQuery.proxy(function(data) {
677 //play specific song in playlist
678 jQuery.post(JSON_RPC + '?PlaylistItemPlay', '{"jsonrpc": "2.0", "method": "Player.Open", "params": { "playlist": { "playlistid": ' + this.playlists["audio"] + ', "position": '+ event.data.itmnbr + ' } }, "id": 1}', function() {}, 'json');
682 movieLibraryOpen: function() {
684 $('#movieLibrary').addClass('selected');
685 $('.contentContainer').hide();
686 var libraryContainer = $('#movieLibraryContainer');
687 if (!libraryContainer || libraryContainer.length == 0) {
688 $('#spinner').show();
689 jQuery.post(JSON_RPC + '?GetMovies', '{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovies", "params": { "limits": { "start": 0 }, "properties": [ "genre", "director", "trailer", "tagline", "plot", "plotoutline", "title", "originaltitle", "lastplayed", "runtime", "year", "playcount", "rating", "thumbnail", "file" ], "sort": { "method": "sorttitle", "ignorearticle": true } }, "id": 1}', jQuery.proxy(function(data) {
690 if (data && data.result && data.result.movies) {
691 libraryContainer = $('<div>');
692 libraryContainer.attr('id', 'movieLibraryContainer')
693 .addClass('contentContainer');
694 $('#content').append(libraryContainer);
696 libraryContainer.html('');
698 //data.result.movies.sort(jQuery.proxy(this.movieTitleSorter, this));
699 $.each($(data.result.movies), jQuery.proxy(function(i, item) {
700 var floatableMovieCover = this.generateThumb('movie', item.thumbnail, item.title);
701 floatableMovieCover.bind('click', { movie: item }, jQuery.proxy(this.displayMovieDetails, this));
702 libraryContainer.append(floatableMovieCover);
704 libraryContainer.append($('<div>').addClass('footerPadding'));
705 $('#spinner').hide();
706 libraryContainer.bind('scroll', { activeLibrary: libraryContainer }, jQuery.proxy(this.updateScrollEffects, this));
707 libraryContainer.trigger('scroll');
708 //$('#libraryContainer img').lazyload();
709 myScroll = new iScroll('movieLibraryContainer');
712 libraryContainer.show();
713 libraryContainer.trigger('scroll');
716 tvshowLibraryOpen: function() {
718 $('#tvshowLibrary').addClass('selected');
719 $('.contentContainer').hide();
720 var libraryContainer = $('#tvshowLibraryContainer');
721 if (!libraryContainer || libraryContainer.length == 0) {
722 $('#spinner').show();
723 toggle=$('<p>').addClass('toggle');
724 togglePoster= $('<span>Poster</span>');
725 togglePoster.attr('id', 'togglePoster')
726 .css('cursor','pointer')
727 .bind('click',{mode: 'poster'},jQuery.proxy(this.togglePosterView,this));
728 toggleBanner= $('<span>Banner</span>');
729 toggleBanner.attr('id', 'toggleBanner')
730 .css('cursor','pointer')
731 .addClass('activeMode')
732 .bind('click',{mode: 'banner'},jQuery.proxy(this.togglePosterView,this));
733 toggleLandscape= $('<span>Landscape</span>');
734 toggleLandscape.attr('id', 'toggleLandscape')
735 .css('cursor','pointer')
736 .bind('click',{mode: 'landscape'},jQuery.proxy(this.togglePosterView,this));
737 toggle.append(toggleBanner).append(' | ').append(togglePoster).append(' | ').append(toggleLandscape);
739 jQuery.post(JSON_RPC + '?GetTVShows', '{"jsonrpc": "2.0", "method": "VideoLibrary.GetTVShows", "params": { "properties": ["genre", "plot", "title", "lastplayed", "episode", "year", "playcount", "rating", "thumbnail", "studio", "mpaa", "premiered"] }, "id": 1}', jQuery.proxy(function(data) {
740 if (data && data.result && data.result.tvshows) {
741 libraryContainer = $('<div>');
742 libraryContainer.append(toggle);
743 libraryContainer.attr('id', 'tvshowLibraryContainer')
744 .addClass('contentContainer');
745 $('#content').append(libraryContainer);
747 libraryContainer.html('');
749 $.each($(data.result.tvshows), jQuery.proxy(function(i, item) {
750 var floatableTVShowCover = this.generateThumb('tvshow', item.thumbnail, item.title);
751 floatableTVShowCover.bind('click', { tvshow: item }, jQuery.proxy(this.displayTVShowDetails, this));
752 libraryContainer.append(floatableTVShowCover);
754 libraryContainer.append($('<div>').addClass('footerPadding'));
755 $('#spinner').hide();
756 libraryContainer.bind('scroll', { activeLibrary: libraryContainer }, jQuery.proxy(this.updateScrollEffects, this));
757 libraryContainer.trigger('scroll');
758 myScroll = new iScroll('tvshowLibraryContainer');
759 if(getCookie('TVView')!=null && getCookie('TVView')!='banner'){
760 var view=getCookie('TVView');
763 togglePoster.trigger('click');
766 toggleLandscape.trigger('click')
772 libraryContainer.prepend($(".toggle").detach()).show();
773 libraryContainer.trigger('scroll');
777 updateScrollEffects: function(event) {
778 if (event.data.activeLibrary && $(event.data.activeLibrary).scrollTop() > 0) {
779 $('#topScrollFade').fadeIn();
781 $('#topScrollFade').fadeOut();
784 startSlideshow: function(event) {
785 jQuery.post(JSON_RPC + '?StartSlideshow', '{"jsonrpc": "2.0", "method": "Player.Open", "params": { "slideshow": { "recursive" : "true", "random":"true", "directory" : "' + this.replaceAll(event.data.directory.file, "\\", "\\\\") + '" } }, "id": 1}', null, 'json');
787 showDirectory: function(event) {
788 var directory = event.data.directory.file;
789 var jsonDirectory = this.replaceAll(directory, "\\", "\\\\");
791 $('#pictureLibrary').addClass('selected');
792 $('.contentContainer').hide();
793 var libraryContainer = $('#pictureLibraryDirContainer' + directory);
794 if (!libraryContainer || libraryContainer.length == 0) {
795 $('#spinner').show();
796 jQuery.post(JSON_RPC + '?GetDirectory', '{"jsonrpc": "2.0", "method": "Files.GetDirectory", "params": { "media" : "pictures", "directory": "' + jsonDirectory + '" }, "id": 1}', jQuery.proxy(function(data) {
797 if (data && data.result && ( data.result.directories || data.result.files )) {
798 libraryContainer = $('<div>');
799 libraryContainer.attr('id', 'pictureLibraryDirContainer' + directory)
800 .addClass('contentContainer');
801 $('#content').append(libraryContainer);
802 var breadcrumb = $('<div>');
805 var directoryArray = directory.split(seperator);
806 jQuery.each(directoryArray, function(i,v) {
808 item += v + seperator;
809 //tmp.bind('click', { directory: item }, jQuery.proxy(this.showDirectory, this));
810 breadcrumb.append($('<div>').text(' > ' + v).css('float','left').addClass('breadcrumb'));
813 libraryContainer.append(breadcrumb);
814 libraryContainer.append($('<div>').css('clear','both'));
815 if (data.result.files) {
816 $.each($(data.result.files), jQuery.proxy(function(i, item) {
817 if (item.filetype == "file")
819 var floatableImage = this.generateThumb('image', item.file, item.label);
820 libraryContainer.append(floatableImage);
822 else if (item.filetype == "directory")
824 var floatableShare = this.generateThumb('directory', item.thumbnail, item.label);
825 floatableShare.bind('click', { directory: item }, jQuery.proxy(this.showDirectory, this));
826 //var slideshow = $('<div">');
827 //slideshow.html('<div>Slideshow</div>');
828 //slideshow.bind('click', { directory: item }, jQuery.proxy(this.startSlideshow, this));
829 //floatableShare.append(slideshow);
830 libraryContainer.append(floatableShare);
834 libraryContainer.append($('<div>').addClass('footerPadding'));
836 libraryContainer.html('');
838 $('#spinner').hide();
839 libraryContainer.bind('scroll', { activeLibrary: libraryContainer }, jQuery.proxy(this.updateScrollEffects, this));
840 libraryContainer.trigger('scroll');
841 myScroll = new iScroll('#pictureLibraryDirContainer' + directory);
844 libraryContainer.show();
845 libraryContainer.trigger('scroll');
848 pictureLibraryOpen: function() {
850 $('#pictureLibrary').addClass('selected');
851 $('.contentContainer').hide();
852 var libraryContainer = $('#pictureLibraryContainer');
853 if (!libraryContainer || libraryContainer.length == 0) {
854 $('#spinner').show();
855 jQuery.post(JSON_RPC + '?GetSources', '{"jsonrpc": "2.0", "method": "Files.GetSources", "params": { "media" : "pictures" }, "id": 1}', jQuery.proxy(function(data) {
856 if (data && data.result && data.result.shares) {
857 libraryContainer = $('<div>');
858 libraryContainer.attr('id', 'pictureLibraryContainer')
859 .addClass('contentContainer');
860 $('#content').append(libraryContainer);
862 libraryContainer.html('');
864 $.each($(data.result.shares), jQuery.proxy(function(i, item) {
865 var floatableShare = this.generateThumb('directory', item.thumbnail, item.label);
866 floatableShare.bind('click', { directory: item }, jQuery.proxy(this.showDirectory, this));
867 libraryContainer.append(floatableShare);
869 libraryContainer.append($('<div>').addClass('footerPadding'));
870 $('#spinner').hide();
871 libraryContainer.bind('scroll', { activeLibrary: libraryContainer }, jQuery.proxy(this.updateScrollEffects, this));
872 libraryContainer.trigger('scroll');
873 myScroll = new iScroll('#pictureLibraryContainer');
876 libraryContainer.show();
877 libraryContainer.trigger('scroll');