// Global Variables var debug = false; var audio; var hostURL = location.href; var baseURL; // Set auth cookies if specified in URL on launch var u = getParameterByName('u'); var p = getParameterByName('p'); var s = getParameterByName('s'); if (u && p && s) { if (!$.cookie('username')) { $.cookie('username', u, { expires: 365 }); } if (!$.cookie('password')) { $.cookie('password', p, { expires: 365 }); } if (!$.cookie('Server')) { $.cookie('Server', s, { expires: 365 }); } window.location.href = getPathFromUrl(window.location); } if ($.cookie('Server')) { baseURL = $.cookie('Server') + '/rest'; } var applicationName; if ($.cookie('ApplicationName')) { applicationName = $.cookie('ApplicationName'); } else { applicationName = 'MiniSub'; } var username = $.cookie('username'); var password = $.cookie('password'); var auth = makeBaseAuth(username, password); var passwordenc = 'enc:' + HexEncode($.cookie('password')); var version = '1.6.0'; function loadTabContent(tab) { switch (tab) { case '#tabLibrary': console.log("TAG LIBRARY"); if ($.cookie('MusicFolders')) { loadArtists($.cookie('MusicFolders'), false); } else { loadArtists(); } getMusicFolders(); break; case '#tabCurrent': console.log("TAG CURRENT"); var header = generateSongHeaderHTML(); $("#CurrentPlaylistContainer thead").html(header); break; case '#tabPlaylists': console.log("TAG PLAYLIST"); loadPlaylists(); break; case '#tabPreferences': break; default: break; } } var scrobbled = false; function playSong(el, songid, albumid) { $.ajax({ url: baseURL + '/getMusicDirectory.view?u=' + username + '&p=' + passwordenc + '&v=' + version + '&c=' + applicationName + '&f=jsonp&id=' + albumid, method: 'GET', dataType: 'jsonp', timeout: 10000, beforeSend: function (req) { req.setRequestHeader('Authorization', auth); }, success: function (data) { var title, artist, album; if (data["subsonic-response"].directory !== undefined) { // There is a bug in the API that doesn't return a JSON array for one artist var children = []; if (data["subsonic-response"].directory.child.length > 0) { children = data["subsonic-response"].directory.child; } else { children[0] = data["subsonic-response"].directory.child; } $.each(children, function (i, child) { if (child.id === songid) { title = child.title; artist = child.artist; album = child.album; coverart = child.coverArt; } }); } $('#songdetails_song').html(title); $('#songdetails_song').attr('parentid', albumid); $('#songdetails_song').attr('childid', songid); $('#songdetails_artist').html(artist + ' - ' + album); $('#coverartimage').attr('href', baseURL + '/getCoverArt.view?v=' + version + '&c=' + applicationName + '&f=jsonp&id=' + coverart); $('#coverartimage img').attr('src', baseURL + '/getCoverArt.view?v=' + version + '&c=' + applicationName + '&f=jsonp&size=50&id=' + coverart); $('#playermiddle').css('visibility', 'visible'); $('#songdetails').css('visibility', 'visible'); // SoundManager Initialize var salt = Math.floor(Math.random() * 100000); if (audio) { soundManager.destroySound('audio'); } audio = soundManager.createSound({ id: 'audio', url: baseURL + '/stream.view?u=' + username + '&p=' + passwordenc + '&v=' + version + '&c=' + applicationName + '&id=' + songid + '&salt=' + salt, stream: true, whileloading: function () { if (debug) { console.log('loaded:' + this.bytesLoaded + ' total:' + this.bytesTotal); } var percent = this.bytesLoaded / this.bytesTotal; var scrubber = $('#audio_wrapper0').find(".scrubber"); var loaded = $('#audio_wrapper0').find(".loaded"); loaded.css('width', (scrubber.get(0).offsetWidth * percent) + 'px'); }, whileplaying: function () { //console.log('position:' + this.position + ' duration:' + this.duration); var percent = this.position / this.duration; var scrubber = $('#audio_wrapper0').find(".scrubber"); var progress = $('#audio_wrapper0').find(".progress"); progress.css('width', (scrubber.get(0).offsetWidth * percent) + 'px'); var played = $('#audio_wrapper0').find(".played"); var p = (this.duration / 1000) * percent, m = Math.floor(p / 60), s = Math.floor(p % 60); played.html((m < 10 ? '0' : '') + m + ':' + (s < 10 ? '0' : '') + s); // Scrobble song once percentage is reached if (!scrobbled && p > 30 && (percent > 0.5 || p > 480)) { scrobbleSong(true); } }, onload: function () { var duration = $('#audio_wrapper0').find(".duration"); var dp = this.duration / 1000, dm = Math.floor(dp / 60), ds = Math.floor(dp % 60); duration.html((dm < 10 ? '0' : '') + dm + ':' + (ds < 10 ? '0' : '') + ds); }, onfinish: function () { var next = $('#CurrentPlaylistContainer tr.playing').next(); changeTrack(next); } }); audio.play('audio'); $('table.songlist tr.song').removeClass('playing'); $(el).addClass('playing'); $('#PlayTrack').find('img').attr('src', 'images/pause_24x32.png'); $('#PlayTrack').addClass('playing'); scrobbleSong(false); scrobbled = false; if ($.cookie('EnableNotifications')) { showNotification(baseURL + '/getCoverArt.view?v=' + version + '&c=' + applicationName + '&f=jsonp&size=50&id=' + coverart, toHTML.un(title), toHTML.un(artist + ' - ' + album)); } if ($.cookie('ScrollTitle')) { scrollTitle(toHTML.un(artist) + ' - ' + toHTML.un(title)); } else { setTitle(toHTML.un(artist) + ' - ' + toHTML.un(title)); } } }); } function scrobbleSong(submission) { var songid = $('#songdetails_song').attr('childid'); $.ajax({ url: baseURL + '/scrobble.view?u=' + username + '&p=' + passwordenc + '&v=' + version + '&c=' + applicationName + '&f=jsonp&id=' + songid + "&submission=" + submission, method: 'GET', dataType: 'jsonp', timeout: 10000, beforeSend: function (req) { req.setRequestHeader('Authorization', auth); }, success: function () { if (submission) { scrobbled = true; } } }); } function rateSong(songid, rating) { $.ajax({ url: baseURL + '/setRating.view?u=' + username + '&p=' + passwordenc + '&v=' + version + '&c=' + applicationName + '&f=jsonp&id=' + songid + "&rating=" + rating, method: 'GET', dataType: 'jsonp', timeout: 10000, beforeSend: function (req) { req.setRequestHeader('Authorization', auth); }, success: function () { updateMessage('Rating Updated!'); } }); } function playPauseSong() { var el = '#PlayTrack'; if ($(el).hasClass('playing')) { $(el).find('img').attr('src', 'images/play_24x32.png'); $(el).removeClass('playing'); $(el).addClass('paused'); soundManager.pause('audio'); } else if ($(el).hasClass('paused')) { $(el).find('img').attr('src', 'images/pause_24x32.png'); $(el).removeClass('paused'); $(el).addClass('playing'); soundManager.resume('audio'); } else { // Start playing song var play = $('#CurrentPlaylistContainer tr.selected').first(); if (changeTrack(play)) { $(el).find('img').attr('src', 'images/pause_24x32.png'); $(el).addClass('playing'); } else { var first = $('#CurrentPlaylistContainer tr').first(); changeTrack(first); } } } function changeTrack(next) { var songid = $(next).attr('childid'); if (songid !== undefined) { var albumid = $(next).attr('parentid'); playSong(next, songid, albumid); return true; } else { return false; } } function autoPlay() { var firstsong = $('#CurrentPlaylistContainer tr.song:first'); var songid = $(firstsong).attr('childid'); var albumid = $(firstsong).attr('parentid'); playSong(firstsong, songid, albumid); } function search(type, query) { $.ajax({ url: baseURL + '/search2.view?u=' + username + '&p=' + passwordenc + '&v=' + version + '&c=' + applicationName + '&f=jsonp&query=' + query, method: 'GET', dataType: 'jsonp', timeout: 10000, beforeSend: function (req) { req.setRequestHeader('Authorization', auth); }, success: function (data) { if (data["subsonic-response"].searchResult2 !== "") { $("#AlbumRows").empty(); var header = generateSongHeaderHTML(); $("#AlbumHeader").html(header); // There is a bug in the API that doesn't return a JSON array for one artist var children = []; if (data["subsonic-response"].searchResult2.song.length > 0) { children = data["subsonic-response"].searchResult2.song; } else { children[0] = data["subsonic-response"].searchResult2.song; } var rowcolor; var albumhtml; $.each(children, function (i, child) { if (i % 2 === 0) { rowcolor = 'even'; } else { rowcolor = 'odd'; } var track; if (child.track === undefined) { track = " "; } else { track = child.track; } var time = secondsToTime(child.duration); albumhtml = generateSongHTML(rowcolor, child.id, child.parent, track, child.title, child.artist, child.album, child.coverArt, child.userRating, time['m'], time['s']); $(albumhtml).appendTo("#AlbumRows"); }); } } }); } var starttime; var updater; function updateChatMessages() { updater = $.periodic({ period: 1000, decay: 1.5, max_period: 1800000 }, function () { $.ajax({ periodic: this, url: baseURL + '/getChatMessages.view?u=' + username + '&p=' + passwordenc + '&v=' + version + '&c=' + applicationName + '&f=jsonp&since=' + starttime, method: 'GET', dataType: 'jsonp', timeout: 10000, beforeSend: function (req) { req.setRequestHeader('Authorization', auth); }, success: function (data) { if (data["subsonic-response"].chatMessages.chatMessage === undefined) { this.periodic.increment(); } else { var msgs = []; if (data["subsonic-response"].chatMessages.chatMessage.length > 0) { msgs = data["subsonic-response"].chatMessages.chatMessage; } else { msgs[0] = data["subsonic-response"].chatMessages.chatMessage; } this.periodic.reset(); var sorted = msgs.sort(function (a, b) { return a.time - b.time; }); var x = 1; $.each(sorted, function (i, msg) { var chathtml = '
'; chathtml += '' + $.format.date(new Date(parseInt(msg.time, 10)), 'hh:mm:ss a') + ' '; chathtml += '' + msg.username + '
'; chathtml += '' + msg.message + ''; chathtml += '
'; $(chathtml).appendTo("#ChatMsgs"); if (x === sorted.length) { starttime = msg.time; } x++; }); $("#ChatMsgs").linkify(); $("#ChatMsgs").attr({ scrollTop: $("#ChatMsgs").attr("scrollHeight") }); } } }); }); } function stopUpdateChatMessages() { updater.cancel(); } function addChatMessage(msg) { $.ajax({ type: 'GET', url: baseURL + '/addChatMessage.view', dataType: 'jsonp', timeout: 10000, data: { u: username, p: passwordenc, v: version, c: applicationName, f: "jsonp", message: msg }, beforeSend: function (req) { req.setRequestHeader('Authorization', auth); }, success: function () { updater.reset(); }, traditional: true // Fixes POST with an array in JQuery 1.4 }); } var updaterNowPlaying; var updaterNowPlayingData; function updateNowPlaying() { updaterNowPlaying = $.periodic({ period: 4000, decay: 1.5, max_period: 1800000 }, function () { $.ajax({ periodic: this, url: baseURL + '/getNowPlaying.view?u=' + username + '&p=' + passwordenc + '&v=' + version + '&c=' + applicationName + '&f=jsonp', method: 'GET', dataType: 'jsonp', timeout: 10000, beforeSend: function (req) { req.setRequestHeader('Authorization', auth); }, success: function (data) { if (data["subsonic-response"].nowPlaying.entry === undefined) { this.periodic.increment(); $("#NowPlayingList").empty(); var chathtml = '
'; chathtml += 'Nothing :(
'; chathtml += '
'; $(chathtml).appendTo("#NowPlayingList"); } else if (updaterNowPlayingData === $.param(data)) { this.periodic.increment(); } else { $("#NowPlayingList").empty(); var msgs = []; if (data["subsonic-response"].nowPlaying.entry.length > 0) { msgs = data["subsonic-response"].nowPlaying.entry; } else { msgs[0] = data["subsonic-response"].nowPlaying.entry; } this.periodic.reset(); var sorted = msgs.sort(function (a, b) { return a.minutesAgo - b.minutesAgo; }); $.each(sorted, function (i, msg) { var chathtml = '
'; chathtml += '' + msg.username + '
'; chathtml += '' + msg.artist + ' - '; chathtml += '' + msg.title + ''; chathtml += '
'; $(chathtml).appendTo("#NowPlayingList"); }); updaterNowPlayingData = $.param(data); } } }); }); } function stopUpdateNowPlaying() { updaterNowPlaying.cancel(); } function loadPlaylists(refresh) { if (refresh) { $('#PlaylistContainer').empty(); } var content = $('#PlaylistContainer').html(); if (content === "") { // Load Playlists $.ajax({ url: baseURL + '/getPlaylists.view?u=' + username + '&p=' + passwordenc + '&v=' + version + '&c=' + applicationName + '&f=jsonp', method: 'GET', dataType: 'jsonp', timeout: 10000, beforeSend: function (req) { req.setRequestHeader('Authorization', auth); }, success: function (data) { var playlists = []; if (data["subsonic-response"].playlists.playlist.length > 0) { playlists = data["subsonic-response"].playlists.playlist; } else { playlists[0] = data["subsonic-response"].playlists.playlist; } $.each(playlists, function (i, playlist) { var html = ""; html += '
  • '; html += '' + playlist.name + ''; html += '
    '; html += '
    '; html += '
  • '; $(html).appendTo("#PlaylistContainer"); }); } }); } } function loadPlaylistsForMenu(menu) { $('#' + menu).empty(); $.ajax({ url: baseURL + '/getPlaylists.view?u=' + username + '&p=' + passwordenc + '&v=' + version + '&c=' + applicationName + '&f=jsonp', method: 'GET', dataType: 'jsonp', timeout: 10000, beforeSend: function (req) { req.setRequestHeader('Authorization', auth); }, success: function (data) { var playlists = []; if (data["subsonic-response"].playlists.playlist.length > 0) { playlists = data["subsonic-response"].playlists.playlist; } else { playlists[0] = data["subsonic-response"].playlists.playlist; } $.each(playlists, function (i, playlist) { if (menu === 'submenu_AddCurrentToPlaylist') { $("" + playlist.name + "
    ").appendTo("#" + menu); } else { $("" + playlist.name + "
    ").appendTo("#" + menu); } }); //$("+ New Playlist
    ").appendTo("#submenu"); } }); } function newPlaylist() { var reply = prompt("Choose a name for your new playlist.", ""); if (reply) { $.ajax({ url: baseURL + '/createPlaylist.view?u=' + username + '&p=' + passwordenc + '&v=' + version + '&c=' + applicationName + '&f=jsonp&name=' + reply, method: 'GET', dataType: 'jsonp', timeout: 10000, beforeSend: function (req) { req.setRequestHeader('Authorization', auth); }, success: function (data) { loadPlaylists(true); } }); } } function deletePlaylist(id) { $.ajax({ url: baseURL + '/deletePlaylist.view?u=' + username + '&p=' + passwordenc + '&v=' + version + '&c=' + applicationName + '&f=jsonp&id=' + id, method: 'GET', dataType: 'jsonp', timeout: 10000, beforeSend: function (req) { req.setRequestHeader('Authorization', auth); }, success: function (data) { loadPlaylists(true); $('#TrackContainer tbody').empty(); } }); } function addToPlaylist(playlistid, from) { var selected = []; var el; if (from === 'current') { el = $('#CurrentPlaylist table.songlist tr.selected'); } else { el = $('#Albums table.songlist tr.selected'); } el.each(function (index) { selected.push($(this).attr('childid')); }); if (selected.length > 0) { if (playlistid !== 'new') { // Create new playlist from here, will implement in UI later // Get songs from playlist var currentsongs = []; $.ajax({ url: baseURL + '/getPlaylist.view?u=' + username + '&p=' + passwordenc + '&v=' + version + '&c=' + applicationName + '&f=jsonp&id=' + playlistid, method: 'GET', dataType: 'jsonp', timeout: 10000, beforeSend: function (req) { req.setRequestHeader('Authorization', auth); }, success: function (data) { // There is a bug in the API that doesn't return a JSON array for one artist var children = []; if (data["subsonic-response"].playlist.entry !== undefined) { if (data["subsonic-response"].playlist.entry.length > 1) { children = data["subsonic-response"].playlist.entry; } else { children[0] = data["subsonic-response"].playlist.entry; } $.each(children, function (i, child) { currentsongs.push(child.id); }); } var newsongs = []; var count = 0; $.each(selected, function (i, songid) { if (jQuery.inArray(songid, currentsongs) === -1) { currentsongs.push(songid); count++; } }); if (count > 0) { $.ajax({ type: 'GET', url: baseURL + '/createPlaylist.view', dataType: 'jsonp', timeout: 10000, data: { u: username, p: passwordenc, v: version, c: applicationName, f: "jsonp", playlistId: playlistid, songId: currentsongs }, beforeSend: function (req) { req.setRequestHeader('Authorization', auth); }, success: function () { $('table.songlist tr.song').each(function () { $(this).removeClass('selected'); }); updateMessage('Playlist Updated!'); }, traditional: true // Fixes POST with an array in JQuery 1.4 }); } } }); } else { $.ajax({ type: 'GET', url: baseURL + '/createPlaylist.view', dataType: 'jsonp', timeout: 10000, data: { u: username, p: passwordenc, v: version, c: applicationName, f: "jsonp", name: 'New Playlist', songId: selected }, beforeSend: function (req) { req.setRequestHeader('Authorization', auth); }, success: function () { $('table.songlist tr.song').each(function () { $(this).removeClass('selected'); }); updateMessage('Playlist Created!'); }, traditional: true // Fixes POST with an array in JQuery 1.4 }); } setTimeout(function () { $('div.submenu').fadeOut(); }, 100); } } function addToCurrent(addAll) { var count; if (addAll) { count = $('#AlbumContainer tr.song').length; } else { count = $('#AlbumContainer tr.selected').length; } if (count > 0) { if (addAll) { $('#AlbumContainer tr.song').each(function (index) { $(this).clone().appendTo('#CurrentPlaylistContainer tbody'); updateMessage(count + ' Song(s) Added'); }); } else { $('#AlbumContainer tr.selected').each(function (index) { $(this).clone().appendTo('#CurrentPlaylistContainer tbody'); updateMessage(count + ' Song(s) Added'); }); } } } function downloadItem(id) { var url; if (id) { url = baseURL + '/download.view?u=' + username + '&p=' + passwordenc + '&v=' + version + '&c=' + applicationName + '&f=jsonp&id=' + id; window.location = url; } /* $('table.songlist tr.selected').each(function (index) { id = $(this).attr('childid'); if (id) { url = baseURL + '/download.view?u=' + username + '&p=' + passwordenc + '&v=' + version + '&c=' + applicationName + '&f=jsonp&id=' + id; window.location = url; } }); */ } function savePlaylist(playlistid) { var songs = []; $('#TrackContainer tr.song').each(function (index) { songs.push($(this).attr('childid')); }); if (songs.length > 0) { $.ajax({ type: 'GET', url: baseURL + '/createPlaylist.view', dataType: 'jsonp', timeout: 10000, data: { u: username, p: passwordenc, v: version, c: applicationName, f: "jsonp", playlistId: playlistid, songId: songs }, beforeSend: function (req) { req.setRequestHeader('Authorization', auth); }, success: function () { getPlaylist(playlistid); updateMessage('Playlist Updated!'); }, traditional: true // Fixes POST with an array in JQuery 1.4 }); } } function getPlaylist(id, action, appendto) { $.ajax({ url: baseURL + '/getPlaylist.view?u=' + username + '&p=' + passwordenc + '&v=' + version + '&c=' + applicationName + '&f=jsonp&id=' + id, method: 'GET', dataType: 'jsonp', timeout: 10000, beforeSend: function (req) { req.setRequestHeader('Authorization', auth); }, success: function (data) { if (data["subsonic-response"].playlist.entry !== undefined) { if (appendto === '#TrackContainer tbody') { $(appendto).empty(); var header = generateSongHeaderHTML(); $("#TrackContainer thead").html(header); } if (action === 'autoplay') { $(appendto).empty(); } // There is a bug in the API that doesn't return a JSON array for one artist var children = []; if (data["subsonic-response"].playlist.entry.length > 0) { children = data["subsonic-response"].playlist.entry; } else { children[0] = data["subsonic-response"].playlist.entry; } var rowcolor; var html; $.each(children, function (i, child) { if (i % 2 === 0) { rowcolor = 'even'; } else { rowcolor = 'odd'; } var track; if (child.track === undefined) { track = " "; } else { track = child.track; } var time = secondsToTime(child.duration); html = generateSongHTML(rowcolor, child.id, child.parent, track, child.title, child.artist, child.album, child.coverArt, child.userRating, time['m'], time['s']); $(html).appendTo(appendto); }); if (appendto === '#CurrentPlaylistContainer tbody') { updateMessage(children.length + ' Song(s) Added'); } if (action === 'autoplay') { autoPlay(); } } else { if (appendto === '#TrackContainer tbody') { $(appendto).empty(); } } } }); }