/* * Copyright (C) 2005-2013 Team XBMC * http://xbmc.org * * This Program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This Program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with XBMC; see the file COPYING. If not, see * . * */ var MediaLibrary = function () { this.init(); }; MediaLibrary.prototype = { playlists: {}, init: function () { this.bindControls(); this.getPlaylists(); }, bindControls: function () { $('#musicLibrary').click(jQuery.proxy(this.musicLibraryOpen, this)); $('#movieLibrary').click(jQuery.proxy(this.movieLibraryOpen, this)); $('#tvshowLibrary').click(jQuery.proxy(this.tvshowLibraryOpen, this)); $('#pictureLibrary').click(jQuery.proxy(this.pictureLibraryOpen, this)); $('#remoteControl').click(jQuery.proxy(this.remoteControlOpen, this)); $('#profiles').click(jQuery.proxy(this.profilesOpen, this)); $('#overlay').click(jQuery.proxy(this.hideOverlay, this)); $(window).resize(jQuery.proxy(this.updatePlayButtonLocation, this)); $(document).on('keydown', jQuery.proxy(this.handleKeyPress, this)); $(document).on('contextmenu', jQuery.proxy(this.handleContextMenu, this)); }, resetPage: function () { $('#musicLibrary').removeClass('selected'); $('#movieLibrary').removeClass('selected'); $('#tvshowLibrary').removeClass('selected'); $('#remoteControl').removeClass('selected'); $('#pictureLibrary').removeClass('selected'); $('#profiles').removeClass('selected'); this.hideOverlay(); }, replaceAll: function (haystack, needle, thread) { return (haystack || '').split(needle || '').join(thread || ''); }, getPlaylists: function () { xbmc.rpc.request({ 'context': this, 'method': 'Playlist.GetPlaylists', 'timeout': 3000, 'success': function (data) { if (data && data.result && data.result.length > 0) { $.each($(data.result), jQuery.proxy(function (i, item) { this.playlists[item.type] = item.playlistid; }, this)); } }, 'error': function (data, error) { xbmc.core.displayCommunicationError(); setTimeout(jQuery.proxy(this.updateState, this), 2000); } }); }, remoteControlOpen: function (event) { this.resetPage(); this.textBuffer = ''; $('#remoteControl').addClass('selected'); $('.contentContainer').hide(); var libraryContainer = $('#remoteContainer'); if (!libraryContainer || libraryContainer.length === 0) { $('#spinner').show(); libraryContainer = $('
'); libraryContainer.attr('id', 'remoteContainer') .addClass('contentContainer'); $('#content').append(libraryContainer); var keys = [{ name: 'up', width: '40px', height: '30px', top: '28px', left: '58px' }, { name: 'down', width: '40px', height: '30px', top: '122px', left: '58px' }, { name: 'left', width: '40px', height: '30px', top: '74px', left: '15px' }, { name: 'right', width: '40px', height: '30px', top: '74px', left: '104px' }, { name: 'ok', width: '40px', height: '30px', top: '74px', left: '58px' }, { name: 'back', width: '40px', height: '30px', top: '13px', left: '161px' }, { name: 'home', width: '40px', height: '30px', top: '154px', left: '8px' }, { name: 'mute', width: '40px', height: '30px', top: '107px', left: '391px' }, { name: 'power', width: '30px', height: '30px', top: '-3px', left: '13px' }, { name: 'volumeup', width: '30px', height: '30px', top: '49px', left: '422px' }, { name: 'volumedown', width: '30px', height: '30px', top: '49px', left: '367px' }, { name: 'playpause', width: '32px', height: '23px', top: '62px', left: '260px' }, { name: 'stop', width: '32px', height: '23px', top: '62px', left: '211px' }, { name: 'next', width: '38px', height: '25px', top: '102px', left: '304px' }, { name: 'previous', width: '38px', height: '25px', top: '101px', left: '160px' }, { name: 'forward', width: '32px', height: '23px', top: '102px', left: '259px' }, { name: 'rewind', width: '32px', height: '23px', top: '101px', left: '211px' }, { name: 'cleanlib_a', width: '46px', height: '26px', top: '47px', left: '553px' }, { name: 'updatelib_a', width: '46px', height: '26px', top: '47px', left: '492px' }, { name: 'cleanlib_v', width: '46px', height: '26px', top: '111px', left: '553px' }, { name: 'updatelib_v', width: '46px', height: '26px', top: '111px', left: '492px' } ]; for (var akey in keys) { var aremotekey = $('

').attr('id', keys[akey]['name']); aremotekey.addClass('remote_key') .css('height', keys[akey]['height']) .css('width', keys[akey]['width']) .css('top', keys[akey]['top']) .css('left', keys[akey]['left']) .bind('click', { key: keys[akey]['name'] }, jQuery.proxy(this.pressRemoteKey, this)); libraryContainer.append(aremotekey); } } else { libraryContainer.show(); libraryContainer.trigger('scroll'); } $('#spinner').hide(); }, shouldHandleEvent: function (event) { var inRemoteControl = $('#remoteControl').hasClass('selected'); return (!event.ctrlKey && !event.altKey && inRemoteControl); }, handleKeyPress: function (event) { if (!this.shouldHandleEvent(event)) { return true; } var keys = { 8: 'back', // Back space 13: 'ok', // Enter 27: 'home', // Escape 32: 'playpause', // Space bar 37: 'left', // Left 38: 'up', // Up 39: 'right', // Right 40: 'down', // Down 93: 'contextmenu', // "Right Click" 107: 'volumeup', // + (num keypad) 109: 'volumedown', // - (num keypad) 187: 'volumeup', // + (alnum keypad) 189: 'volumedown' // - (alnum keypad) }; var which = event.which; var key = keys[which]; event.data = { key: key }; if (!key) { event.data.key = 'text'; if (event.key && event.key.length === 1) { event.data.text = event.key; } else { // Letters if (which >= 65 && which <= 90) { var offset = event.shiftKey ? 0 : 32; event.data.text = String.fromCharCode(which + offset); } // Digits if (which >= 96 && which <= 105) { event.data.text = (which - 96) + ""; } } } if (event.data.key) { this.pressRemoteKey(event); return false; } }, handleContextMenu: function (event) { if (!this.shouldHandleEvent(event)) { return true; } if ( (event.target == document) || //Chrome/Opera (event.clientX === event.clientY && event.clientX === 0) //FF/IE ) { return false; } //keyboard event. cancel it. return true; }, rpcCall: function (method, params) { var callObj = { 'method': method }; if (params) { callObj.params = params; } return xbmc.rpc.request(callObj); }, typeRemoteText: function (event) { if (event.data.key === 'text' || ((event.data.key === 'playpause' || event.data.key === 'back') && this .textBuffer.length)) { if (event.data.key === 'back') { this.textBuffer = this.textBuffer.substring(0, this.textBuffer.length - 1); } else if (event.data.key === 'playpause') { this.textBuffer += ' '; } else if (event.data.text && event.data.text.length) { this.textBuffer += event.data.text; } console.log(this.textBuffer); return this.rpcCall('Input.SendText', { 'text': this.textBuffer, 'done': false }); } else { this.textBuffer = ''; } }, pressRemoteKey: function (event) { var player = -1, keyPressed = event.data.key; $('#spinner').show(); if (this.typeRemoteText(event)) { return true; } switch (keyPressed) { case 'up': return this.rpcCall('Input.Up'); case 'down': return this.rpcCall('Input.Down'); case 'left': return this.rpcCall('Input.Left'); case 'right': return this.rpcCall('Input.Right'); case 'ok': return this.rpcCall('Input.Select'); case 'cleanlib_a': return this.rpcCall('AudioLibrary.Clean'); case 'updatelib_a': return this.rpcCall('AudioLibrary.Scan'); case 'cleanlib_v': return this.rpcCall('VideoLibrary.Clean'); case 'updatelib_v': return this.rpcCall('VideoLibrary.Scan'); case 'back': return this.rpcCall('Input.Back'); case 'home': return this.rpcCall('Input.Home'); case 'power': return this.rpcCall('System.Shutdown'); case 'contextmenu': return this.rpcCall('Input.ContextMenu'); case 'mute': return this.rpcCall('Application.SetMute', { 'mute': 'toggle' }); case 'volumeup': return this.rpcCall('Application.SetVolume', { 'volume': 'increment' }); case 'volumedown': return this.rpcCall('Application.SetVolume', { 'volume': 'decrement' }); } // TODO: Get active player if ($('#videoDescription').is(':visible')) { player = this.playlists["video"]; } else if ($('#audioDescription').is(':visible')) { player = this.playlists["audio"]; } if (player >= 0) { switch (keyPressed) { case 'playpause': return this.rpcCall('Player.PlayPause', { 'playerid': player }); case 'stop': return this.rpcCall('Player.Stop', { 'playerid': player }); case 'next': return this.rpcCall('Player.GoTo', { 'playerid': player, 'to': 'next' }); case 'previous': return this.rpcCall('Player.GoTo', { 'playerid': player, 'to': 'previous' }); case 'forward': return this.rpcCall('Player.SetSpeed', { 'playerid': player, 'speed': 'increment' }); case 'rewind': return this.rpcCall('Player.SetSpeed', { 'playerid': player, 'speed': 'decrement' }); } } }, musicLibraryOpen: function (event) { this.resetPage(); $('#musicLibrary').addClass('selected'); $('.contentContainer').hide(); var libraryContainer = $('#libraryContainer'); if (!libraryContainer || libraryContainer.length === 0) { $('#spinner').show(); libraryContainer = $('

'); libraryContainer.attr('id', 'libraryContainer') .addClass('contentContainer'); $('#content').append(libraryContainer); xbmc.rpc.request({ 'context': this, 'method': 'AudioLibrary.GetAlbums', 'params': { 'limits': { 'start': 0 }, 'properties': [ 'description', 'theme', 'mood', 'style', 'type', 'albumlabel', 'artist', 'genre', 'rating', 'title', 'year', 'thumbnail' ], 'sort': { 'method': 'artist' } }, 'success': function (data) { if (data && data.result && data.result.albums) { this.albumList = data.result.albums; $.each($(this.albumList), jQuery.proxy(function (i, item) { var floatableAlbum = this.generateThumb('album', item .thumbnail, item.title, item.artist); floatableAlbum.bind('click', { album: item }, jQuery.proxy(this.displayAlbumDetails, this)); libraryContainer.append(floatableAlbum); }, this)); libraryContainer.append($('
').addClass('footerPadding')); $('#spinner').hide(); libraryContainer.bind('scroll', { activeLibrary: libraryContainer }, jQuery.proxy(this.updateScrollEffects, this)); libraryContainer.trigger('scroll'); myScroll = new iScroll('libraryContainer'); } else { libraryContainer.html(''); } } }); } else { libraryContainer.show(); libraryContainer.trigger('scroll'); } }, getThumbnailPath: function (thumbnail) { return thumbnail ? ('image/' + encodeURI(thumbnail)) : xbmc.core.DEFAULT_ALBUM_COVER; }, generateThumb: function (type, thumbnail, title, artist) { title = title || ''; artist = artist || ''; var showTitle = title, showArtist = artist; var floatableAlbum = $('
'); var path = this.getThumbnailPath(thumbnail); if (title.length > 21) { showTitle = $.trim(title.substr(0, 18)) + '...'; } if (artist.length > 22) { showArtist = $.trim(artist.substr(0, 20)) + '...'; } var className = ''; var code = ''; switch (type) { case 'album': className = 'floatableAlbum'; code = '

' + showTitle + '

' + artist + '

'; break; case 'movie': className = 'floatableMovieCover'; code = '

' + showTitle + '

'; break; case 'tvshow': className = 'floatableTVShowCover'; break; case 'tvshowseason': className = 'floatableTVShowCoverSeason'; break; case 'image': case 'directory': className = 'floatableAlbum'; code = '

' + showTitle + '

'; break; case 'profile': className = 'floatableProfileThumb'; code = '

' + showTitle + '

'; break; } return floatableAlbum.addClass(className).html('
' + title + '
' + code); }, showAlbumSelectorBlock: function (album) { if (album) { var prevAlbum = null, nextAlbum = null; $.each($(this.albumList), jQuery.proxy(function (i, item) { if (item.albumid == album.albumid) { if (this.albumList.length > 1) { prevAlbum = this.albumList[i <= 0 ? this.albumList.length - 1 : i - 1]; nextAlbum = this.albumList[i >= this.albumList.length ? 0 : i + 1]; } return false; /* .each break */ } }, this)); var albumSelectorBlock = $('#albumSelector'); if (!albumSelectorBlock || albumSelectorBlock.length === 0) { albumSelectorBlock = $('
'); albumSelectorBlock.attr('id', 'albumSelector') .html( '' + '
All Albums  
' ); $('#content').prepend(albumSelectorBlock); $('#albumSelector .allAlbums').bind('click', jQuery.proxy(this.hideAlbumDetails, this)); } $('#albumSelector .prevAlbum').unbind(); $('#albumSelector .nextAlbum').unbind(); if (prevAlbum) { $('#albumSelector .prevAlbum').bind('click', { album: prevAlbum }, jQuery.proxy(this.displayAlbumDetails, this)); } if (nextAlbum) { $('#albumSelector .nextAlbum').bind('click', { album: nextAlbum }, jQuery.proxy(this.displayAlbumDetails, this)); } $('#albumSelector .activeAlbumTitle').html(album.title || 'Unknown Album'); albumSelectorBlock.show(); } }, hideAlbumDetails: function () { $('.contentContainer').hide(); this.musicLibraryOpen(); }, displayAlbumDetails: function (event) { this.showAlbumSelectorBlock(event.data.album); var albumDetailsContainer = $('#albumDetails' + event.data.album.albumid); $('#topScrollFade').hide(); if (!albumDetailsContainer || albumDetailsContainer.length === 0) { $('#spinner').show(); xbmc.rpc.request({ 'context': this, 'method': 'AudioLibrary.GetSongs', 'params': { 'properties': [ 'title', 'artist', 'genre', 'track', 'duration', 'year', 'rating', 'playcount' ], 'sort': { 'method': 'track' }, 'filter': { 'albumid': event.data.album.albumid } }, 'success': function (data) { albumDetailsContainer = $('
'); albumDetailsContainer.attr('id', 'albumDetails' + event.data.album.albumid) .addClass('contentContainer') .addClass('albumContainer') .html( '' + '' + '
Artwork NameTimeArtistGenre
' ); $('.contentContainer').hide(); $('#content').append(albumDetailsContainer); var albumThumbnail = event.data.album.thumbnail; var albumTitle = event.data.album.title || 'Unknown Album'; var albumArtist = event.data.album.artist.join(', ') || 'Unknown Artist'; var trackCount = data.result.limits.total; $.each($(data.result.songs), jQuery.proxy(function (i, item) { var trackRow, trackNumberTD; if (i === 0) { trackRow = $('').addClass('trackRow').addClass('tr' + i % 2); trackRow.append($('').attr('rowspan', ++trackCount + 1) .addClass('albumThumb')); for (var a = 0; a < 5; a++) { trackRow.append($('').html(' ').attr('style', 'display: none')); } $('#albumDetails' + event.data.album.albumid + ' .resultSet').append(trackRow); } trackRow = $('').addClass('trackRow').addClass('tr' + i % 2) .bind('click', { album: event.data.album, itmnbr: i }, jQuery.proxy(this.playTrack, this)); trackNumberTD = $('').html(item.track); trackRow.append(trackNumberTD); var trackTitleTD = $('').html(item.title); trackRow.append(trackTitleTD); var trackDurationTD = $('') .addClass('time') .html(xbmc.core.durationToString(item.duration)); trackRow.append(trackDurationTD); var trackArtistTD = $('').html(item.artist.join(', ')); trackRow.append(trackArtistTD); var trackGenreTD = $('').html(item.genre.join(', ')); trackRow.append(trackGenreTD); $('#albumDetails' + event.data.album.albumid + ' .resultSet') .append(trackRow); }, this)); if (trackCount > 0) { var trackRow = $('').addClass('fillerTrackRow'), i; for (i = 0; i < 5; i++) { trackRow.append($('').html(' ')); } $('#albumDetails' + event.data.album.albumid + ' .resultSet').append( trackRow); var trackRow2 = $('').addClass('fillerTrackRow2'); trackRow2.append($('').addClass('albumBG').html(' ')); for (i = 0; i < 5; i++) { trackRow2.append($('').html(' ')); } $('#albumDetails' + event.data.album.albumid + ' .resultSet').append( trackRow2); } $('#albumDetails' + event.data.album.albumid + ' .albumThumb') .append(this.generateThumb('album', albumThumbnail, albumTitle, albumArtist)) .append($('
').addClass('footerPadding')); $('#spinner').hide(); myScroll = new iScroll('albumDetails' + event.data.album.albumid); } }); } else { $('.contentContainer').hide(); $('#albumDetails' + event.data.album.albumid).show(); } }, togglePosterView: function (event) { var view = event.data.mode; var wthumblist, hthumblist, hthumbdetails; $("#toggleBanner").removeClass('activeMode'); $("#togglePoster").removeClass('activeMode'); $("#toggleLandscape").removeClass('activeMode'); switch (view) { case 'landscape': xbmc.core.setCookie('TVView', 'landscape'); wthumblist = '210px'; hthumblist = '118px'; hthumbdetails = '213px'; $("#toggleLandscape").addClass('activeMode'); break; case 'banner': xbmc.core.setCookie('TVView', 'banner'); wthumblist = '379px'; hthumblist = '70px'; hthumbdetails = '70px'; $("#toggleBanner").addClass('activeMode'); break; default: xbmc.core.setCookie('TVView', 'poster'); wthumblist = '135px'; hthumblist = '199px'; hthumbdetails = '559px'; $("#togglePoster").addClass('activeMode'); break; } $(".floatableTVShowCover, .floatableTVShowCover div.imgWrapper, .floatableTVShowCover img, " + ".floatableTVShowCover div.imgWrapper div.inner") .css('width', wthumblist).css('height', hthumblist); $(".floatableTVShowCoverSeason div.imgWrapper, .floatableTVShowCoverSeason div.imgWrapper div.inner," + ".floatableTVShowCoverSeason img, .floatableTVShowCoverSeason") .css('height', hthumbdetails); }, displayTVShowDetails: function (event) { var tvshowDetailsContainer = $('#tvShowDetails' + event.data.tvshow.tvshowid); $('#topScrollFade').hide(); toggle = this.toggle.detach(); if (!tvshowDetailsContainer || tvshowDetailsContainer.length === 0) { $('#spinner').show(); xbmc.rpc.request({ 'context': this, 'method': 'VideoLibrary.GetSeasons', 'params': { 'properties': [ 'season', 'showtitle', 'playcount', 'episode', 'thumbnail', 'fanart' ], 'tvshowid': event.data.tvshow.tvshowid }, 'success': function (data) { tvshowDetailsContainer = $('
'); tvshowDetailsContainer.attr('id', 'tvShowDetails' + event.data.tvshow.tvshowid) .css('display', 'none') .addClass('contentContainer') .addClass('tvshowContainer'); var showThumb = this.generateThumb('tvshowseason', event.data.tvshow.thumbnail, event.data.tvshow.title); if (data && data.result && data.result.seasons && data.result.seasons.length > 0) { var showDetails = $('
').addClass('showDetails'); showDetails.append(toggle); showDetails.append($('

').html(data.result.seasons[0].showtitle).addClass( 'showTitle')); var seasonSelectionSelect = $('