15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)'use strict'; 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {HTMLElement} container Container element. 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @constructor 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function AudioPlayer(container) { 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.container_ = container; 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.metadataCache_ = MetadataCache.createFull(); 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.currentTrack_ = -1; 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.playlistGeneration_ = 0; 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.volumeManager_ = VolumeManager.getInstance(); 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.container_.classList.add('collapsed'); 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function createChild(opt_className, opt_tag) { 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var child = container.ownerDocument.createElement(opt_tag || 'div'); 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (opt_className) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) child.className = opt_className; 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) container.appendChild(child); 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return child; 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We create two separate containers (for expanded and compact view) and keep 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // two sets of TrackInfo instances. We could fiddle with a single set instead 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // but it would make keeping the list scroll position very tricky. 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.trackList_ = createChild('track-list'); 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.trackStack_ = createChild('track-stack'); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) createChild('title-button collapse').addEventListener( 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'click', this.onExpandCollapse_.bind(this)); 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.audioControls_ = new FullWindowAudioControls( 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) createChild(), this.advance_.bind(this), this.onError_.bind(this)); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.audioControls_.attachMedia(createChild('', 'audio')); 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome.fileBrowserPrivate.getStrings(function(strings) { 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) container.ownerDocument.title = strings['AUDIO_PLAYER_TITLE']; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.errorString_ = strings['AUDIO_ERROR']; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.offlineString_ = strings['AUDIO_OFFLINE']; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AudioPlayer.TrackInfo.DEFAULT_ARTIST = 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strings['AUDIO_PLAYER_DEFAULT_ARTIST']; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }.bind(this)); 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.volumeManager_.addEventListener('externally-unmounted', 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.onExternallyUnmounted_.bind(this)); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Key in the local storage for the list of track urls. 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.PLAYLIST_KEY = 'audioPlaylist'; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Key in the local storage for the number of the current track. 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.TRACK_KEY = 'audioTrack'; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Initial load method (static). 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.load = function() { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) document.ondragstart = function(e) { e.preventDefault() }; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the audio player is starting before the first instance of the File 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Manager then it does not have access to filesystem URLs. Request it now. 72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) chrome.fileBrowserPrivate.requestFileSystem(function() { 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AudioPlayer.instance = 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new AudioPlayer(document.querySelector('.audio-player')); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome.mediaPlayerPrivate.onPlaylistChanged.addListener(getPlaylist); 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) reload(); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)util.addPageLoadHandler(AudioPlayer.load); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Unload the player. 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function unload() { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AudioPlayer.instance.audioControls_.cleanup(); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Reload the player. 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)function reload() { 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (window.appState) { 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Launching/reloading a v2 app. 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) util.saveAppState(); 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AudioPlayer.instance.load(window.appState); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Lauching/reloading a v1 app. 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (document.location.hash) { 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The window is reloading, restore the state. 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AudioPlayer.instance.load(null); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) getPlaylist(); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Get the playlist from Chrome. 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function getPlaylist() { 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome.mediaPlayerPrivate.getPlaylist( 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AudioPlayer.instance.load.bind(AudioPlayer.instance)); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Load a new playlist. 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Playlist} playlist Playlist object passed via mediaPlayerPrivate. 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.prototype.load = function(playlist) { 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!playlist || !playlist.items.length) { 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // playlist is null if the window is being reloaded. 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // playlist is empty if ChromeOS has restarted with the Audio Player open. 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Restore the playlist from the local storage. 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) util.platform.getPreferences(function(prefs) { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var restoredPlaylist = { 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) items: JSON.parse(prefs[AudioPlayer.PLAYLIST_KEY]), 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) position: Number(prefs[AudioPlayer.TRACK_KEY]), 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) time: true // Force restoring time from document.location. 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (restoredPlaylist.items.length) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.load(restoredPlaylist); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } catch (ignore) {} 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }.bind(this)); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!window.appState) { 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Remember the playlist for the restart. 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // App v2 handles that in the background page. 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) util.platform.setPreference( 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AudioPlayer.PLAYLIST_KEY, JSON.stringify(playlist.items)); 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) util.platform.setPreference( 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AudioPlayer.TRACK_KEY, playlist.position); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.playlistGeneration_++; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.audioControls_.pause(); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.currentTrack_ = -1; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.urls_ = playlist.items; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.invalidTracks_ = {}; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.cancelAutoAdvance_(); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (this.urls_.length <= 1) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.container_.classList.add('single-track'); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.container_.classList.remove('single-track'); 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.syncHeight_(); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.trackList_.textContent = ''; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.trackStack_.textContent = ''; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.trackListItems_ = []; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.trackStackItems_ = []; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (this.urls_.length == 0) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (var i = 0; i != this.urls_.length; i++) { 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var url = this.urls_[i]; 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var onClick = this.select_.bind(this, i, false /* no restore */); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.trackListItems_.push( 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new AudioPlayer.TrackInfo(this.trackList_, url, onClick)); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.trackStackItems_.push( 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new AudioPlayer.TrackInfo(this.trackStack_, url, onClick)); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.select_(playlist.position, !!playlist.time); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This class will be removed if at least one track has art. 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.container_.classList.add('noart'); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Load the selected track metadata first, then load the rest. 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.loadMetadata_(playlist.position); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i != this.urls_.length; i++) { 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i != playlist.position) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.loadMetadata_(i); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Load metadata for a track. 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} track Track number. 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.prototype.loadMetadata_ = function(track) { 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.fetchMetadata_( 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.urls_[track], this.displayMetadata_.bind(this, track)); 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Display track's metadata. 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} track Track number. 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Object} metadata Metadata object. 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {string=} opt_error Error message. 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.prototype.displayMetadata_ = function(track, metadata, opt_error) { 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.trackListItems_[track]. 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setMetadata(metadata, this.container_, opt_error); 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.trackStackItems_[track]. 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setMetadata(metadata, this.container_, opt_error); 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Closes audio player when a volume containing the selected item is unmounted. 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Event} event The unmount event. 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @private 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AudioPlayer.prototype.onExternallyUnmounted_ = function(event) { 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!this.selectedItemFilesystemPath_) 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (this.selectedItemFilesystemPath_.indexOf(event.mountPath) == 0) 2317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) close(); 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Select a new track to play. 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} newTrack New track number. 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {boolean=} opt_restoreState True if restoring the play state from URL. 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.prototype.select_ = function(newTrack, opt_restoreState) { 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (this.currentTrack_ == newTrack) return; 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.changeSelectionInList_(this.currentTrack_, newTrack); 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.changeSelectionInStack_(this.currentTrack_, newTrack); 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.currentTrack_ = newTrack; 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (window.appState) { 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) window.appState.position = this.currentTrack_; 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) window.appState.time = 0; 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) util.saveAppState(); 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) util.platform.setPreference(AudioPlayer.TRACK_KEY, this.currentTrack_); 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.scrollToCurrent_(false); 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var currentTrack = this.currentTrack_; 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var url = this.urls_[currentTrack]; 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.fetchMetadata_(url, function(metadata) { 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (this.currentTrack_ != currentTrack) 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) var src = url; 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.audioControls_.load(src, opt_restoreState); 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Resolve real filesystem path of the current audio file. 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.selectedItemFilesystemPath_ = null; 2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) webkitResolveLocalFileSystemURL(src, 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) function(entry) { 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (this.currentTrack_ != currentTrack) 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.selectedItemFilesystemPath_ = entry.fullPath; 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }.bind(this)); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }.bind(this)); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} url Track file url. 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function(object)} callback Callback. 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.prototype.fetchMetadata_ = function(url, callback) { 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.metadataCache_.get(url, 'thumbnail|media|streaming', 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function(generation, metadata) { 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Do nothing if another load happened since the metadata request. 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (this.playlistGeneration_ == generation) 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback(metadata); 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }.bind(this, this.playlistGeneration_)); 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} oldTrack Old track number. 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} newTrack New track number. 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.prototype.changeSelectionInList_ = function(oldTrack, newTrack) { 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.trackListItems_[newTrack].getBox().classList.add('selected'); 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (oldTrack >= 0) { 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.trackListItems_[oldTrack].getBox().classList.remove('selected'); 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} oldTrack Old track number. 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} newTrack New track number. 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.prototype.changeSelectionInStack_ = function(oldTrack, newTrack) { 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var newBox = this.trackStackItems_[newTrack].getBox(); 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newBox.classList.add('selected'); // Put on top immediately. 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newBox.classList.add('visible'); // Start fading in. 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (oldTrack >= 0) { 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var oldBox = this.trackStackItems_[oldTrack].getBox(); 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) oldBox.classList.remove('selected'); // Put under immediately. 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setTimeout(function() { 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!oldBox.classList.contains('selected')) { 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This will start fading out which is not really necessary because 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // oldBox is already completely obscured by newBox. 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) oldBox.classList.remove('visible'); 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }, 300); 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Scrolls the current track into the viewport. 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {boolean} keepAtBottom If true, make the selected track the last 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * of the visible (if possible). If false, perform minimal scrolling. 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.prototype.scrollToCurrent_ = function(keepAtBottom) { 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var box = this.trackListItems_[this.currentTrack_].getBox(); 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.trackList_.scrollTop = Math.max( 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keepAtBottom ? 0 : Math.min(box.offsetTop, this.trackList_.scrollTop), 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) box.offsetTop + box.offsetHeight - this.trackList_.clientHeight); 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {boolean} True if the player is be displayed in compact mode. 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.prototype.isCompact_ = function() { 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return this.container_.classList.contains('collapsed') || 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.container_.classList.contains('single-track'); 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Go to the previous or the next track. 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {boolean} forward True if next, false if previous. 3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {boolean=} opt_onlyIfValid True if invalid tracks should be selected. 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.prototype.advance_ = function(forward, opt_onlyIfValid) { 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.cancelAutoAdvance_(); 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var newTrack = this.currentTrack_ + (forward ? 1 : -1); 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (newTrack < 0) newTrack = this.urls_.length - 1; 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (newTrack == this.urls_.length) newTrack = 0; 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (opt_onlyIfValid && this.invalidTracks_[newTrack]) 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.select_(newTrack); 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Media error handler. 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.prototype.onError_ = function() { 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var track = this.currentTrack_; 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.invalidTracks_[track] = true; 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.fetchMetadata_( 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.urls_[track], 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function(metadata) { 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var error = (!navigator.onLine && metadata.streaming) ? 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.offlineString_ : this.errorString_; 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.displayMetadata_(track, metadata, error); 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.scheduleAutoAdvance_(); 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }.bind(this)); 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Schedule automatic advance to the next track after a timeout. 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.prototype.scheduleAutoAdvance_ = function() { 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.cancelAutoAdvance_(); 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.autoAdvanceTimer_ = setTimeout( 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function() { 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.autoAdvanceTimer_ = null; 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We are advancing only if the next track is not known to be invalid. 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This prevents an endless auto-advancing in the case when all tracks 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // are invalid (we will only visit each track once). 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.advance_(true /* forward */, true /* only if valid */); 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }.bind(this), 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3000); 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Cancel the scheduled auto advance. 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.prototype.cancelAutoAdvance_ = function() { 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (this.autoAdvanceTimer_) { 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clearTimeout(this.autoAdvanceTimer_); 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.autoAdvanceTimer_ = null; 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Expand/collapse button click handler. 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.prototype.onExpandCollapse_ = function() { 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.container_.classList.toggle('collapsed'); 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.syncHeight_(); 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!this.isCompact_()) 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.scrollToCurrent_(true); 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Keep the below constants in sync with the CSS. */ 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Player header height. 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * TODO(kaznacheev): Set to 30 when the audio player is title-less. 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.HEADER_HEIGHT = 0; 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Track height. 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.TRACK_HEIGHT = 58; 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Controls bar height. 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.CONTROLS_HEIGHT = 35; 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Set the correct player window height. 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.prototype.syncHeight_ = function() { 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var expandedListHeight = 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Math.min(this.urls_.length, 3) * AudioPlayer.TRACK_HEIGHT; 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.trackList_.style.height = expandedListHeight + 'px'; 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var targetClientHeight = AudioPlayer.CONTROLS_HEIGHT + 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (this.isCompact_() ? 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AudioPlayer.TRACK_HEIGHT : 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AudioPlayer.HEADER_HEIGHT + expandedListHeight); 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) var appWindow = chrome.app.window.current(); 4587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) var oldHeight = appWindow.contentWindow.outerHeight; 4597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) var bottom = appWindow.contentWindow.screenY + oldHeight; 4607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) var newTop = Math.max(0, bottom - targetClientHeight); 4617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) appWindow.moveTo(appWindow.contentWindow.screenX, newTop); 4627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) appWindow.resizeTo(appWindow.contentWindow.outerWidth, 4637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) oldHeight + targetClientHeight - this.container_.clientHeight); 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Create a TrackInfo object encapsulating the information about one track. 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {HTMLElement} container Container element. 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} url Track url. 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function} onClick Click handler. 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @constructor 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.TrackInfo = function(container, url, onClick) { 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.url_ = url; 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var doc = container.ownerDocument; 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.box_ = doc.createElement('div'); 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.box_.className = 'track'; 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.box_.addEventListener('click', onClick); 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) container.appendChild(this.box_); 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.art_ = doc.createElement('div'); 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.art_.className = 'art blank'; 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.box_.appendChild(this.art_); 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.img_ = doc.createElement('img'); 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.art_.appendChild(this.img_); 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.data_ = doc.createElement('div'); 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.data_.className = 'data'; 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.box_.appendChild(this.data_); 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.title_ = doc.createElement('div'); 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.title_.className = 'data-title'; 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.data_.appendChild(this.title_); 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.artist_ = doc.createElement('div'); 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.artist_.className = 'data-artist'; 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.data_.appendChild(this.artist_); 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {HTMLDivElement} The wrapper element for the track. 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.TrackInfo.prototype.getBox = function() { return this.box_ }; 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {string} Default track title (file name extracted from the url). 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.TrackInfo.prototype.getDefaultTitle = function() { 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var title = this.url_.split('/').pop(); 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var dotIndex = title.lastIndexOf('.'); 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dotIndex >= 0) title = title.substr(0, dotIndex); 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) title = decodeURIComponent(title); 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return title; 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * TODO(kaznacheev): Localize. 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.TrackInfo.DEFAULT_ARTIST = 'Unknown Artist'; 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {string} 'Unknown artist' string. 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.TrackInfo.prototype.getDefaultArtist = function() { 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return AudioPlayer.TrackInfo.DEFAULT_ARTIST; 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Object} metadata The metadata object. 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {HTMLElement} container The container for the tracks. 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} error Error string. 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPlayer.TrackInfo.prototype.setMetadata = function( 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metadata, container, error) { 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (error) { 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.art_.classList.add('blank'); 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.art_.classList.add('error'); 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) container.classList.remove('noart'); 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (metadata.thumbnail && metadata.thumbnail.url) { 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.img_.onload = function() { 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only display the image if the thumbnail loaded successfully. 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.art_.classList.remove('blank'); 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) container.classList.remove('noart'); 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }.bind(this); 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.img_.src = metadata.thumbnail.url; 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.title_.textContent = (metadata.media && metadata.media.title) || 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.getDefaultTitle(); 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.artist_.textContent = error || 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (metadata.media && metadata.media.artist) || this.getDefaultArtist(); 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Audio controls specific for the Audio Player. 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {HTMLElement} container Parent container. 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function(boolean)} advanceTrack Parameter: true=forward. 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function} onError Error handler. 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @constructor 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function FullWindowAudioControls(container, advanceTrack, onError) { 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AudioControls.apply(this, arguments); 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) document.addEventListener('keydown', function(e) { 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (e.keyIdentifier == 'U+0020') { 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.togglePlayState(); 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) e.preventDefault(); 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }.bind(this)); 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FullWindowAudioControls.prototype = { __proto__: AudioControls.prototype }; 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Enable play state restore from the location hash. 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} src Source URL. 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {boolean} restore True if need to restore the play state. 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FullWindowAudioControls.prototype.load = function(src, restore) { 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.media_.src = src; 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.media_.load(); 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.restoreWhenLoaded_ = restore; 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Save the current state so that it survives page/app reload. 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FullWindowAudioControls.prototype.onPlayStateChanged = function() { 5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.encodeState(); 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Restore the state after page/app reload. 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FullWindowAudioControls.prototype.restorePlayState = function() { 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (this.restoreWhenLoaded_) { 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.restoreWhenLoaded_ = false; // This should only work once. 6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (this.decodeState()) 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.play(); 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 608